summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt1
-rw-r--r--Help/command/link_directories.rst50
-rw-r--r--Help/command/target_link_directories.rst55
-rw-r--r--Help/cpack_gen/deb.rst20
-rw-r--r--Help/cpack_gen/rpm.rst6
-rw-r--r--Help/generator/Visual Studio 10 2010.rst33
-rw-r--r--Help/generator/Visual Studio 11 2012.rst35
-rw-r--r--Help/generator/Visual Studio 12 2013.rst33
-rw-r--r--Help/generator/Visual Studio 14 2015.rst27
-rw-r--r--Help/generator/Visual Studio 15 2017.rst34
-rw-r--r--Help/generator/Visual Studio 9 2008.rst17
-rw-r--r--Help/manual/cmake-commands.7.rst1
-rw-r--r--Help/manual/cmake-policies.7.rst1
-rw-r--r--Help/manual/cmake-properties.7.rst2
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/policy/CMP0081.rst22
-rw-r--r--Help/prop_dir/LINK_DIRECTORIES.rst15
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst9
-rw-r--r--Help/prop_tgt/LINK_DIRECTORIES.rst18
-rw-r--r--Help/release/dev/FindMatlab-2018b.rst12
-rw-r--r--Help/release/dev/LINK_DIRECTORIES-policy.rst5
-rw-r--r--Help/release/dev/LINK_DIRECTORIES.rst9
-rw-r--r--Help/release/dev/cpack-deb-dbgsym-ddeb.rst6
-rw-r--r--Help/release/dev/link_directories-enhancements.rst5
-rw-r--r--Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst9
-rw-r--r--Modules/CMakeDetermineASMCompiler.cmake6
-rw-r--r--Modules/FindGLUT.cmake42
-rw-r--r--Modules/FindLua.cmake1
-rw-r--r--Modules/FindMatlab.cmake78
-rw-r--r--Modules/Internal/CPack/CPackDeb.cmake106
-rw-r--r--Source/CMakeLists.txt5
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx944
-rw-r--r--Source/CPack/cmCPackDebGenerator.h2
-rw-r--r--Source/CTest/cmCTestBuildAndTestHandler.cxx12
-rw-r--r--Source/cmCPluginAPI.cxx2
-rw-r--r--Source/cmCommands.cxx3
-rw-r--r--Source/cmComputeLinkInformation.cxx11
-rw-r--r--Source/cmExportBuildFileGenerator.cxx3
-rw-r--r--Source/cmExportFileGenerator.cxx31
-rw-r--r--Source/cmExportFileGenerator.h4
-rw-r--r--Source/cmExportInstallFileGenerator.cxx2
-rw-r--r--Source/cmGeneratorExpression.cxx6
-rw-r--r--Source/cmGeneratorExpression.h9
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h1
-rw-r--r--Source/cmGeneratorTarget.cxx131
-rw-r--r--Source/cmGeneratorTarget.h8
-rw-r--r--Source/cmGlobalVisualStudio10Generator.cxx1
-rw-r--r--Source/cmIncludeDirectoryCommand.cxx8
-rw-r--r--Source/cmJsonObjectDictionary.h46
-rw-r--r--Source/cmJsonObjects.cxx823
-rw-r--r--Source/cmJsonObjects.h27
-rw-r--r--Source/cmLinkDirectoriesCommand.cxx30
-rw-r--r--Source/cmLinkDirectoriesCommand.h3
-rw-r--r--Source/cmListFileCache.cxx165
-rw-r--r--Source/cmListFileCache.h30
-rw-r--r--Source/cmMakefile.cxx38
-rw-r--r--Source/cmMakefile.h3
-rw-r--r--Source/cmPolicies.h8
-rw-r--r--Source/cmServer.cxx1
-rw-r--r--Source/cmServerDictionary.h38
-rw-r--r--Source/cmServerProtocol.cxx798
-rw-r--r--Source/cmState.cxx5
-rw-r--r--Source/cmStateDirectory.cxx80
-rw-r--r--Source/cmStateDirectory.h10
-rw-r--r--Source/cmStatePrivate.h4
-rw-r--r--Source/cmStateSnapshot.cxx7
-rw-r--r--Source/cmTarget.cxx83
-rw-r--r--Source/cmTarget.h11
-rw-r--r--Source/cmTargetLinkDirectoriesCommand.cxx61
-rw-r--r--Source/cmTargetLinkDirectoriesCommand.h41
-rw-r--r--Source/cmake.cxx21
-rw-r--r--Source/cmake.h1
-rw-r--r--Tests/CMakeCommands/link_directories/CMakeLists.txt30
-rw-r--r--Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c4
-rw-r--r--Tests/CMakeCommands/target_link_directories/CMakeLists.txt40
-rw-r--r--Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c7
-rw-r--r--Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt2
-rw-r--r--Tests/CMakeLists.txt38
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt12
-rw-r--r--Tests/ExportImport/Import/A/CMakeLists.txt5
-rw-r--r--Tests/LinkDirectory/External/CMakeLists.txt14
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-Common.cmake5
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW.cmake4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-OLD.cmake4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0081/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0081/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0081/empty.cpp7
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/CPack/DEB/Helpers.cmake2
-rw-r--r--Tests/RunCMake/CPack/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/CPack/VerifyResult.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake39
-rw-r--r--Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake4
-rw-r--r--Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt1
-rw-r--r--Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt2
-rw-r--r--Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake3
-rw-r--r--Tests/RunCMake/set_property/RunCMakeTest.cmake1
-rw-r--r--Utilities/Release/linux64_release.cmake7
-rwxr-xr-xUtilities/Scripts/update-libarchive.bash2
-rw-r--r--Utilities/cmlibarchive/CMakeLists.txt49
-rw-r--r--Utilities/cmlibarchive/build/cmake/config.h.in10
-rw-r--r--Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in1
-rw-r--r--Utilities/cmlibarchive/build/version2
-rw-r--r--Utilities/cmlibarchive/libarchive/CMakeLists.txt2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive.h8
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_acl.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cmdline.c6
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cryptor.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cryptor_private.h2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry.h3
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_match.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h3
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_pack_dev.c3
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_platform.h6
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd7.c10
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd_private.h7
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read.c12
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_append_filter.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c8
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c19
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_filter.36
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c292
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c21
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c7
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c29
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c6
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c109
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c30
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c10
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_string.c3
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_util.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_version_details.c18
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_virtual.c11
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write.32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter.c1
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c1
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c7
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c335
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c12
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c19
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_filter.36
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c17
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c17
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c2
159 files changed, 3931 insertions, 1720 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7f16e79..e88e925 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -513,6 +513,7 @@ macro (CMAKE_BUILD_UTILITIES)
set(ENABLE_NETTLE OFF CACHE INTERNAL "Enable use of Nettle")
set(ENABLE_OPENSSL ${CMAKE_USE_OPENSSL} CACHE INTERNAL "Enable use of OpenSSL")
set(ENABLE_LZMA ON CACHE INTERNAL "Enable the use of the system LZMA library if found")
+ set(ENABLE_LZ4 OFF CACHE INTERNAL "Enable the use of the system LZ4 library if found")
set(ENABLE_LZO OFF CACHE INTERNAL "Enable the use of the system LZO library if found")
set(ENABLE_ZLIB ON CACHE INTERNAL "Enable the use of the system ZLIB library if found")
set(ENABLE_BZip2 ON CACHE INTERNAL "Enable the use of the system BZip2 library if found")
diff --git a/Help/command/link_directories.rst b/Help/command/link_directories.rst
index 5c64bc6..1dce9a0 100644
--- a/Help/command/link_directories.rst
+++ b/Help/command/link_directories.rst
@@ -1,19 +1,51 @@
link_directories
----------------
-Specify directories in which the linker will look for libraries.
+Add directories in which the linker will look for libraries.
::
- link_directories(directory1 directory2 ...)
+ link_directories([AFTER|BEFORE] directory1 [directory2 ...])
-Specify the paths in which the linker should search for libraries.
-The command will apply only to targets created after it is called.
+Add the paths in which the linker should search for libraries.
Relative paths given to this command are interpreted as relative to
the current source directory, see :policy:`CMP0015`.
-Note that this command is rarely necessary. Library locations
-returned by :command:`find_package` and :command:`find_library` are
-absolute paths. Pass these absolute library file paths directly to the
-:command:`target_link_libraries` command. CMake will ensure the linker finds
-them.
+The directories are added to the :prop_dir:`LINK_DIRECTORIES` directory
+property for the current ``CMakeLists.txt`` file, converting relative
+paths to absolute as needed.
+The command will apply only to targets created after it is called.
+
+By default the directories specified are appended onto the current list of
+directories. This default behavior can be changed by setting
+:variable:`CMAKE_LINK_DIRECTORIES_BEFORE` to ``ON``. By using
+``AFTER`` or ``BEFORE`` explicitly, you can select between appending and
+prepending, independent of the default.
+
+Arguments to ``link_directories`` may use "generator expressions" with
+the syntax "$<...>". See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. note::
+
+ This command is rarely necessary and should be avoided where there are
+ other choices. Prefer to pass full absolute paths to libraries where
+ possible, since this ensures the correct library will always be linked.
+ The :command:`find_library` command provides the full path, which can
+ generally be used directly in calls to :command:`target_link_libraries`.
+ Situations where a library search path may be needed include:
+
+ - Project generators like Xcode where the user can switch target
+ architecture at build time, but a full path to a library cannot
+ be used because it only provides one architecture (i.e. it is not
+ a universal binary).
+ - Libraries may themselves have other private library dependencies
+ that expect to be found via ``RPATH`` mechanisms, but some linkers
+ are not able to fully decode those paths (e.g. due to the presence
+ of things like ``$ORIGIN``).
+
+ If a library search path must be provided, prefer to localize the effect
+ where possible by using the :command:`target_link_directories` command
+ rather than ``link_directories()``. The target-specific command can also
+ control how the search directories propagate to other dependent targets.
diff --git a/Help/command/target_link_directories.rst b/Help/command/target_link_directories.rst
new file mode 100644
index 0000000..b46aac0
--- /dev/null
+++ b/Help/command/target_link_directories.rst
@@ -0,0 +1,55 @@
+target_link_directories
+-----------------------
+
+Add link directories to a target.
+
+::
+
+ target_link_directories(<target> [BEFORE]
+ <INTERFACE|PUBLIC|PRIVATE> [items1...]
+ [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
+
+Specify the paths in which the linker should search for libraries when
+linking a given target. Each item can be an absolute or relative path,
+with the latter being interpreted as relative to the current source
+directory. These items will be added to the link command.
+
+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>`.
+
+The ``INTERFACE``, ``PUBLIC`` and ``PRIVATE`` keywords are required to
+specify the scope of the items that follow them. ``PRIVATE`` and
+``PUBLIC`` items will populate the :prop_tgt:`LINK_DIRECTORIES` property
+of ``<target>``. ``PUBLIC`` and ``INTERFACE`` items will populate the
+:prop_tgt:`INTERFACE_LINK_DIRECTORIES` property of ``<target>``
+(:ref:`IMPORTED targets <Imported Targets>` only support ``INTERFACE`` items).
+Each item specifies a link directory and will be converted to an absolute
+path if necessary before adding it to the relevant property. Repeated
+calls for the same ``<target>`` append items in the order called.
+
+If ``BEFORE`` is specified, the content will be prepended to the relevant
+property instead of being appended.
+
+Arguments to ``target_link_directories`` may use "generator expressions"
+with the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
+
+.. note::
+
+ This command is rarely necessary and should be avoided where there are
+ other choices. Prefer to pass full absolute paths to libraries where
+ possible, since this ensures the correct library will always be linked.
+ The :command:`find_library` command provides the full path, which can
+ generally be used directly in calls to :command:`target_link_libraries`.
+ Situations where a library search path may be needed include:
+
+ - Project generators like Xcode where the user can switch target
+ architecture at build time, but a full path to a library cannot
+ be used because it only provides one architecture (i.e. it is not
+ a universal binary).
+ - Libraries may themselves have other private library dependencies
+ that expect to be found via ``RPATH`` mechanisms, but some linkers
+ are not able to fully decode those paths (e.g. due to the presence
+ of things like ``$ORIGIN``).
diff --git a/Help/cpack_gen/deb.rst b/Help/cpack_gen/deb.rst
index 37d750d..26021cc 100644
--- a/Help/cpack_gen/deb.rst
+++ b/Help/cpack_gen/deb.rst
@@ -518,6 +518,26 @@ List of CPack Deb generator specific variables:
This value is not interpreted. It is possible to pass an optional
revision number of the referenced source package as well.
+Packaging of debug information
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Dbgsym packages contain debug symbols for debugging packaged binaries.
+
+Dbgsym packaging has its own set of variables:
+
+.. variable:: CPACK_DEBIAN_DEBUGINFO_PACKAGE
+ CPACK_DEBIAN_<component>_DEBUGINFO_PACKAGE
+
+ Enable generation of dbgsym .ddeb package(s).
+
+ * Mandatory : NO
+ * Default : OFF
+
+.. note::
+
+ Binaries must contain debug symbols before packaging so use either ``Debug``
+ or ``RelWithDebInfo`` for :variable:`CMAKE_BUILD_TYPE` variable value.
+
Building Debian packages on Windows
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/Help/cpack_gen/rpm.rst b/Help/cpack_gen/rpm.rst
index 0214766..5c543ff 100644
--- a/Help/cpack_gen/rpm.rst
+++ b/Help/cpack_gen/rpm.rst
@@ -85,7 +85,7 @@ List of CPack RPM generator specific variables:
By using user provided spec file, rpm macro extensions such as for
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 it's own spec file).
+ 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
setting or spec file content structure. Duplicate files get overwritten
and it is up to the packager to set the variables in a manner that will
@@ -749,7 +749,7 @@ Packaging of debug information
Debuginfo packages contain debug symbols and sources for debugging packaged
binaries.
-Debuginfo RPM packaging has it's own set of variables:
+Debuginfo RPM packaging has its own set of variables:
.. variable:: CPACK_RPM_DEBUGINFO_PACKAGE
CPACK_RPM_<component>_DEBUGINFO_PACKAGE
@@ -911,7 +911,7 @@ directories.
different binary rpm packages on different platforms depending on the platform's
packaging rules.
-Source RPM packaging has it's own set of variables:
+Source RPM packaging has its own set of variables:
.. variable:: CPACK_RPM_PACKAGE_SOURCES
diff --git a/Help/generator/Visual Studio 10 2010.rst b/Help/generator/Visual Studio 10 2010.rst
index b8d6872..0446b8c 100644
--- a/Help/generator/Visual Studio 10 2010.rst
+++ b/Help/generator/Visual Studio 10 2010.rst
@@ -3,18 +3,6 @@ Visual Studio 10 2010
Generates Visual Studio 10 (VS 2010) project files.
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set
-to specify a target platform name (architecture).
-
-For compatibility with CMake versions prior to 3.1, one may specify
-a target platform name optionally at the end of this generator name:
-
-``Visual Studio 10 2010 Win64``
- Specify target platform ``x64``.
-
-``Visual Studio 10 2010 IA64``
- Specify target platform ``Itanium``.
-
For compatibility with CMake versions prior to 3.0, one may specify this
generator using the name ``Visual Studio 10`` without the year component.
@@ -24,6 +12,27 @@ Project Types
Only Visual C++ and C# projects may be generated. Other types of
projects (Database, Website, etc.) are not supported.
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 10 2010" -A Win32``
+* ``cmake -G "Visual Studio 10 2010" -A x64``
+* ``cmake -G "Visual Studio 10 2010" -A Itanium``
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 10 2010 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 10 2010 IA64``
+ Specify target platform ``Itanium``.
+
Toolset Selection
^^^^^^^^^^^^^^^^^
diff --git a/Help/generator/Visual Studio 11 2012.rst b/Help/generator/Visual Studio 11 2012.rst
index 8e9998a..8fddbb3 100644
--- a/Help/generator/Visual Studio 11 2012.rst
+++ b/Help/generator/Visual Studio 11 2012.rst
@@ -3,11 +3,31 @@ Visual Studio 11 2012
Generates Visual Studio 11 (VS 2012) project files.
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set
-to specify a target platform name (architecture).
+For compatibility with CMake versions prior to 3.0, one may specify this
+generator using the name "Visual Studio 11" without the year component.
+
+Project Types
+^^^^^^^^^^^^^
+
+Only Visual C++ and C# projects may be generated. Other types of
+projects (JavaScript, Database, Website, etc.) are not supported.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 11 2012" -A Win32``
+* ``cmake -G "Visual Studio 11 2012" -A x64``
+* ``cmake -G "Visual Studio 11 2012" -A ARM``
+* ``cmake -G "Visual Studio 11 2012" -A <WinCE-SDK>``
+ (Specify a target platform matching a Windows CE SDK name.)
For compatibility with CMake versions prior to 3.1, one may specify
-a target platform name optionally at the end of this generator name:
+a target platform name optionally at the end of the generator name.
+This is supported only for:
``Visual Studio 11 2012 Win64``
Specify target platform ``x64``.
@@ -18,15 +38,6 @@ a target platform name optionally at the end of this generator name:
``Visual Studio 11 2012 <WinCE-SDK>``
Specify target platform matching a Windows CE SDK name.
-For compatibility with CMake versions prior to 3.0, one may specify this
-generator using the name "Visual Studio 11" without the year component.
-
-Project Types
-^^^^^^^^^^^^^
-
-Only Visual C++ and C# projects may be generated. Other types of
-projects (JavaScript, Database, Website, etc.) are not supported.
-
Toolset Selection
^^^^^^^^^^^^^^^^^
diff --git a/Help/generator/Visual Studio 12 2013.rst b/Help/generator/Visual Studio 12 2013.rst
index 03f7586..8b4c162 100644
--- a/Help/generator/Visual Studio 12 2013.rst
+++ b/Help/generator/Visual Studio 12 2013.rst
@@ -3,18 +3,6 @@ Visual Studio 12 2013
Generates Visual Studio 12 (VS 2013) project files.
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set
-to specify a target platform name (architecture).
-
-For compatibility with CMake versions prior to 3.1, one may specify
-a target platform name optionally at the end of this generator name:
-
-``Visual Studio 12 2013 Win64``
- Specify target platform ``x64``.
-
-``Visual Studio 12 2013 ARM``
- Specify target platform ``ARM``.
-
For compatibility with CMake versions prior to 3.0, one may specify this
generator using the name "Visual Studio 12" without the year component.
@@ -24,6 +12,27 @@ Project Types
Only Visual C++ and C# projects may be generated. Other types of
projects (JavaScript, Powershell, Python, etc.) are not supported.
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 12 2013" -A Win32``
+* ``cmake -G "Visual Studio 12 2013" -A x64``
+* ``cmake -G "Visual Studio 12 2013" -A ARM``
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 12 2013 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 12 2013 ARM``
+ Specify target platform ``ARM``.
+
Toolset Selection
^^^^^^^^^^^^^^^^^
diff --git a/Help/generator/Visual Studio 14 2015.rst b/Help/generator/Visual Studio 14 2015.rst
index e55bc73..917d8e5 100644
--- a/Help/generator/Visual Studio 14 2015.rst
+++ b/Help/generator/Visual Studio 14 2015.rst
@@ -3,11 +3,26 @@ Visual Studio 14 2015
Generates Visual Studio 14 (VS 2015) project files.
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set
-to specify a target platform name (architecture).
+Project Types
+^^^^^^^^^^^^^
+
+Only Visual C++ and C# projects may be generated. Other types of
+projects (JavaScript, Powershell, Python, etc.) are not supported.
+
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 14 2015" -A Win32``
+* ``cmake -G "Visual Studio 14 2015" -A x64``
+* ``cmake -G "Visual Studio 14 2015" -A ARM``
For compatibility with CMake versions prior to 3.1, one may specify
-a target platform name optionally at the end of this generator name:
+a target platform name optionally at the end of the generator name.
+This is supported only for:
``Visual Studio 14 2015 Win64``
Specify target platform ``x64``.
@@ -15,12 +30,6 @@ a target platform name optionally at the end of this generator name:
``Visual Studio 14 2015 ARM``
Specify target platform ``ARM``.
-Project Types
-^^^^^^^^^^^^^
-
-Only Visual C++ and C# projects may be generated. Other types of
-projects (JavaScript, Powershell, Python, etc.) are not supported.
-
Toolset Selection
^^^^^^^^^^^^^^^^^
diff --git a/Help/generator/Visual Studio 15 2017.rst b/Help/generator/Visual Studio 15 2017.rst
index 809be4b..42a3bb6 100644
--- a/Help/generator/Visual Studio 15 2017.rst
+++ b/Help/generator/Visual Studio 15 2017.rst
@@ -3,18 +3,6 @@ Visual Studio 15 2017
Generates Visual Studio 15 (VS 2017) project files.
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set
-to specify a target platform name (architecture).
-
-For compatibility with CMake versions prior to 3.1, one may specify
-a target platform name optionally at the end of this generator name:
-
-``Visual Studio 15 2017 Win64``
- Specify target platform ``x64``.
-
-``Visual Studio 15 2017 ARM``
- Specify target platform ``ARM``.
-
Project Types
^^^^^^^^^^^^^
@@ -37,6 +25,28 @@ one of the instances, that instance will be used. Otherwise, if more
than one instance is installed we do not define which one is chosen
by default.
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 15 2017" -A Win32``
+* ``cmake -G "Visual Studio 15 2017" -A x64``
+* ``cmake -G "Visual Studio 15 2017" -A ARM``
+* ``cmake -G "Visual Studio 15 2017" -A ARM64``
+
+For compatibility with CMake versions prior to 3.1, one may specify
+a target platform name optionally at the end of the generator name.
+This is supported only for:
+
+``Visual Studio 15 2017 Win64``
+ Specify target platform ``x64``.
+
+``Visual Studio 15 2017 ARM``
+ Specify target platform ``ARM``.
+
Toolset Selection
^^^^^^^^^^^^^^^^^
diff --git a/Help/generator/Visual Studio 9 2008.rst b/Help/generator/Visual Studio 9 2008.rst
index 40471b9..a29033f 100644
--- a/Help/generator/Visual Studio 9 2008.rst
+++ b/Help/generator/Visual Studio 9 2008.rst
@@ -3,11 +3,22 @@ Visual Studio 9 2008
Generates Visual Studio 9 2008 project files.
-The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set
-to specify a target platform name.
+Platform Selection
+^^^^^^^^^^^^^^^^^^
+
+The :variable:`CMAKE_GENERATOR_PLATFORM` variable may be set, perhaps
+via the :manual:`cmake(1)` ``-A`` option, to specify a target platform
+name (architecture). For example:
+
+* ``cmake -G "Visual Studio 9 2008" -A Win32``
+* ``cmake -G "Visual Studio 9 2008" -A x64``
+* ``cmake -G "Visual Studio 9 2008" -A Itanium``
+* ``cmake -G "Visual Studio 9 2008" -A <WinCE-SDK>``
+ (Specify a target platform matching a Windows CE SDK name.)
For compatibility with CMake versions prior to 3.1, one may specify
-a target platform name optionally at the end of this generator name:
+a target platform name optionally at the end of the generator name.
+This is supported only for:
``Visual Studio 9 2008 Win64``
Specify target platform ``x64``.
diff --git a/Help/manual/cmake-commands.7.rst b/Help/manual/cmake-commands.7.rst
index 753647d..0cc5fca 100644
--- a/Help/manual/cmake-commands.7.rst
+++ b/Help/manual/cmake-commands.7.rst
@@ -111,6 +111,7 @@ These commands are available only in CMake projects.
/command/target_compile_features
/command/target_compile_options
/command/target_include_directories
+ /command/target_link_directories
/command/target_link_libraries
/command/target_link_options
/command/target_sources
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 904ebee..2cc52fe 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.13
.. toctree::
:maxdepth: 1
+ CMP0081: Relative paths not allowed in LINK_DIRECTORIES target property. </policy/CMP0081>
CMP0080: BundleUtilities cannot be included at configure time. </policy/CMP0080>
CMP0079: target_link_libraries allows use with targets in other directories. </policy/CMP0079>
CMP0078: UseSWIG generates standard target names. </policy/CMP0078>
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 8ccd7f6..5c3eb81 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -228,6 +228,7 @@ Properties on Targets
/prop_tgt/INTERFACE_COMPILE_OPTIONS
/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
/prop_tgt/INTERFACE_LINK_DEPENDS
+ /prop_tgt/INTERFACE_LINK_DIRECTORIES
/prop_tgt/INTERFACE_LINK_LIBRARIES
/prop_tgt/INTERFACE_LINK_OPTIONS
/prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE
@@ -252,6 +253,7 @@ Properties on Targets
/prop_tgt/LINK_DEPENDS_NO_SHARED
/prop_tgt/LINK_DEPENDS
/prop_tgt/LINKER_LANGUAGE
+ /prop_tgt/LINK_DIRECTORIES
/prop_tgt/LINK_FLAGS_CONFIG
/prop_tgt/LINK_FLAGS
/prop_tgt/LINK_INTERFACE_LIBRARIES_CONFIG
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index f217f11..9dd36ed 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -179,6 +179,7 @@ Variables that Change Behavior
/variable/CMAKE_INSTALL_PREFIX
/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
/variable/CMAKE_LIBRARY_PATH
+ /variable/CMAKE_LINK_DIRECTORIES_BEFORE
/variable/CMAKE_MFC_FLAG
/variable/CMAKE_MODULE_PATH
/variable/CMAKE_NOT_USING_CONFIG_FLAGS
diff --git a/Help/policy/CMP0081.rst b/Help/policy/CMP0081.rst
new file mode 100644
index 0000000..d3b2872
--- /dev/null
+++ b/Help/policy/CMP0081.rst
@@ -0,0 +1,22 @@
+CMP0081
+-------
+
+Relative paths not allowed in :prop_tgt:`LINK_DIRECTORIES` target property.
+
+CMake 3.12 and lower allowed the :prop_dir:`LINK_DIRECTORIES` directory
+property to contain relative paths. The base path for such relative
+entries is not well defined. CMake 3.13 and later will issue a
+``FATAL_ERROR`` if the :prop_tgt:`LINK_DIRECTORIES` target property
+(which is initialized by the :prop_dir:`LINK_DIRECTORIES` directory property)
+contains a relative path.
+
+The ``OLD`` behavior for this policy is not to warn about relative paths
+in the :prop_tgt:`LINK_DIRECTORIES` target property. The ``NEW`` behavior for
+this policy is to issue a ``FATAL_ERROR`` if :prop_tgt:`LINK_DIRECTORIES`
+contains a relative path.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_dir/LINK_DIRECTORIES.rst b/Help/prop_dir/LINK_DIRECTORIES.rst
index fa37576..f9fb815 100644
--- a/Help/prop_dir/LINK_DIRECTORIES.rst
+++ b/Help/prop_dir/LINK_DIRECTORIES.rst
@@ -3,6 +3,15 @@ LINK_DIRECTORIES
List of linker search directories.
-This read-only property specifies the list of directories given so far
-to the link_directories command. It is intended for debugging
-purposes.
+This property holds a :ref:`;-list <CMake Language Lists>` of directories
+and is typically populated using the :command:`link_directories` command.
+It gets its initial value from its parent directory, if it has one.
+
+The directory property is used to initialize the :prop_tgt:`LINK_DIRECTORIES`
+target property when a target is created. That target property is used
+by the generators to set the library search directories for the linker.
+
+Contents of ``LINK_DIRECTORIES`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..56a4ec0
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
@@ -0,0 +1,9 @@
+INTERFACE_LINK_DIRECTORIES
+--------------------------
+
+.. |property_name| replace:: link directories
+.. |command_name| replace:: :command:`target_link_directories`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_LINK_DIRECTORIES``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`LINK_DIRECTORIES`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_LINK_DIRECTORIES>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt
diff --git a/Help/prop_tgt/LINK_DIRECTORIES.rst b/Help/prop_tgt/LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..085a701
--- /dev/null
+++ b/Help/prop_tgt/LINK_DIRECTORIES.rst
@@ -0,0 +1,18 @@
+LINK_DIRECTORIES
+----------------
+
+List of directories to use for the link step of shared library, module
+and executable targets.
+
+This property holds a :ref:`;-list <CMake Language Lists>` of directories
+specified so far for its target. Use the :command:`target_link_directories`
+command to append more search directories.
+
+This property is initialized by the :prop_dir:`LINK_DIRECTORIES` directory
+property when a target is created, and is used by the generators to set
+the search directories for the linker.
+
+Contents of ``LINK_DIRECTORIES`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
diff --git a/Help/release/dev/FindMatlab-2018b.rst b/Help/release/dev/FindMatlab-2018b.rst
new file mode 100644
index 0000000..c698b9d
--- /dev/null
+++ b/Help/release/dev/FindMatlab-2018b.rst
@@ -0,0 +1,12 @@
+FindMatlab-2018b
+----------------
+
+* The :module:`FindMatlab` module gained new components ``ENGINE_LIBRARY`` and
+ ``DATAARRAY_LIBRARY`` to request finding the Matlab C++ Engine and DataArray
+ libraries respectively.
+
+* The :module:`FindMatlab` module now explicitly exports mexFunction in Visual
+ Studio.
+
+* The :module:`FindMatlab` module gained the ability to discover Matlab R2018a
+ and R2018b.
diff --git a/Help/release/dev/LINK_DIRECTORIES-policy.rst b/Help/release/dev/LINK_DIRECTORIES-policy.rst
new file mode 100644
index 0000000..5bbfa51
--- /dev/null
+++ b/Help/release/dev/LINK_DIRECTORIES-policy.rst
@@ -0,0 +1,5 @@
+LINK_DIRECTORIES-policy
+-----------------------
+
+* The :prop_tgt:`LINK_DIRECTORIES` target property expects absolute paths.
+ See policy :policy:`CMP0081`.
diff --git a/Help/release/dev/LINK_DIRECTORIES.rst b/Help/release/dev/LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..dc7d609
--- /dev/null
+++ b/Help/release/dev/LINK_DIRECTORIES.rst
@@ -0,0 +1,9 @@
+LINK_DIRECTORIES
+----------------
+
+* CMake gained new capabilities to manage link directories:
+
+ * :prop_tgt:`LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DIRECTORIES`
+ target properties.
+ * :command:`target_link_directories` command to add link directories to
+ targets.
diff --git a/Help/release/dev/cpack-deb-dbgsym-ddeb.rst b/Help/release/dev/cpack-deb-dbgsym-ddeb.rst
new file mode 100644
index 0000000..dc3e96e
--- /dev/null
+++ b/Help/release/dev/cpack-deb-dbgsym-ddeb.rst
@@ -0,0 +1,6 @@
+cpack-deb-dbgsym-ddeb
+---------------------
+
+* The :cpack_gen:`CPack Deb Generator` learned to split debug symbols into
+ a corresponding .ddeb package when ``CPACK_DEBIAN_DEBUGINFO_PACKAGE`` is
+ set.
diff --git a/Help/release/dev/link_directories-enhancements.rst b/Help/release/dev/link_directories-enhancements.rst
new file mode 100644
index 0000000..2521fa1
--- /dev/null
+++ b/Help/release/dev/link_directories-enhancements.rst
@@ -0,0 +1,5 @@
+link_directories-enhancements
+-----------------------------
+
+* :command:`link_directories` command gains capability to control directories
+ insertion position.
diff --git a/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst b/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst
new file mode 100644
index 0000000..026ca35
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst
@@ -0,0 +1,9 @@
+CMAKE_LINK_DIRECTORIES_BEFORE
+-----------------------------
+
+Whether to append or prepend directories by default in
+:command:`link_directories`.
+
+This variable affects the default behavior of the :command:`link_directories`
+command. Setting this variable to ``ON`` is equivalent to using the ``BEFORE``
+option in all uses of that command.
diff --git a/Modules/CMakeDetermineASMCompiler.cmake b/Modules/CMakeDetermineASMCompiler.cmake
index 24048ed..45dea8f 100644
--- a/Modules/CMakeDetermineASMCompiler.cmake
+++ b/Modules/CMakeDetermineASMCompiler.cmake
@@ -22,11 +22,9 @@ if(NOT CMAKE_ASM${ASM_DIALECT}_COMPILER)
if("ASM${ASM_DIALECT}" STREQUAL "ASM") # the generic assembler support
if(NOT CMAKE_ASM_COMPILER_INIT)
if(CMAKE_C_COMPILER)
- set(CMAKE_ASM_COMPILER "${CMAKE_C_COMPILER}" CACHE FILEPATH "The ASM compiler")
- set(CMAKE_ASM_COMPILER_ID "${CMAKE_C_COMPILER_ID}")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST ${CMAKE_C_COMPILER})
elseif(CMAKE_CXX_COMPILER)
- set(CMAKE_ASM_COMPILER "${CMAKE_CXX_COMPILER}" CACHE FILEPATH "The ASM compiler")
- set(CMAKE_ASM_COMPILER_ID "${CMAKE_CXX_COMPILER_ID}")
+ set(CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST ${CMAKE_CXX_COMPILER})
else()
# List all default C and CXX compilers
set(CMAKE_ASM${ASM_DIALECT}_COMPILER_LIST
diff --git a/Modules/FindGLUT.cmake b/Modules/FindGLUT.cmake
index 88d4b29..1779683 100644
--- a/Modules/FindGLUT.cmake
+++ b/Modules/FindGLUT.cmake
@@ -34,20 +34,30 @@
# GLUT_Xmu_LIBRARY = the full path to the Xmu library.
# GLUT_Xi_LIBRARY = the full path to the Xi Library.
+include(${CMAKE_CURRENT_LIST_DIR}/SelectLibraryConfigurations.cmake)
+
if (WIN32)
find_path( GLUT_INCLUDE_DIR NAMES GL/glut.h
PATHS ${GLUT_ROOT_PATH}/include )
- find_library( GLUT_glut_LIBRARY NAMES glut glut32 freeglut
+ find_library( GLUT_glut_LIBRARY_RELEASE NAMES glut glut32 freeglut
PATHS
${OPENGL_LIBRARY_DIR}
${GLUT_ROOT_PATH}/Release
)
+ find_library( GLUT_glut_LIBRARY_DEBUG NAMES freeglutd
+ PATHS
+ ${OPENGL_LIBRARY_DIR}
+ ${GLUT_ROOT_PATH}/Debug
+ )
+ mark_as_advanced(GLUT_glut_LIBRARY_RELEASE GLUT_glut_LIBRARY_DEBUG)
+ select_library_configurations(GLUT_glut)
else ()
if (APPLE)
find_path(GLUT_INCLUDE_DIR glut.h ${OPENGL_LIBRARY_DIR})
find_library(GLUT_glut_LIBRARY GLUT DOC "GLUT library for OSX")
find_library(GLUT_cocoa_LIBRARY Cocoa DOC "Cocoa framework for OSX")
+ mark_as_advanced(GLUT_glut_LIBRARY GLUT_cocoa_LIBRARY)
if(GLUT_cocoa_LIBRARY AND NOT TARGET GLUT::Cocoa)
add_library(GLUT::Cocoa UNKNOWN IMPORTED)
@@ -72,10 +82,12 @@ else ()
find_library( GLUT_Xi_LIBRARY Xi
/usr/openwin/lib
)
+ mark_as_advanced(GLUT_Xi_LIBRARY)
find_library( GLUT_Xmu_LIBRARY Xmu
/usr/openwin/lib
)
+ mark_as_advanced(GLUT_Xmu_LIBRARY)
if(GLUT_Xi_LIBRARY AND NOT TARGET GLUT::Xi)
add_library(GLUT::Xi UNKNOWN IMPORTED)
@@ -104,6 +116,7 @@ else ()
/usr/openwin/lib
${_GLUT_glut_LIB_DIR}
)
+ mark_as_advanced(GLUT_glut_LIBRARY)
unset(_GLUT_INC_DIR)
unset(_GLUT_glut_LIB_DIR)
@@ -135,8 +148,24 @@ if (GLUT_FOUND)
set_target_properties(GLUT::GLUT PROPERTIES
IMPORTED_LOCATION "${GLUT_glut_LIBRARY}/${CMAKE_MATCH_1}")
else()
- set_target_properties(GLUT::GLUT PROPERTIES
- IMPORTED_LOCATION "${GLUT_glut_LIBRARY}")
+ if(GLUT_glut_LIBRARY_RELEASE)
+ set_property(TARGET GLUT::GLUT APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS RELEASE)
+ set_target_properties(GLUT::GLUT PROPERTIES
+ IMPORTED_LOCATION_RELEASE "${GLUT_glut_LIBRARY_RELEASE}")
+ endif()
+
+ if(GLUT_glut_LIBRARY_DEBUG)
+ set_property(TARGET GLUT::GLUT APPEND PROPERTY
+ IMPORTED_CONFIGURATIONS DEBUG)
+ set_target_properties(GLUT::GLUT PROPERTIES
+ IMPORTED_LOCATION_DEBUG "${GLUT_glut_LIBRARY_DEBUG}")
+ endif()
+
+ if(NOT GLUT_glut_LIBRARY_RELEASE AND NOT GLUT_glut_LIBRARY_DEBUG)
+ set_property(TARGET GLUT::GLUT APPEND PROPERTY
+ IMPORTED_LOCATION "${GLUT_glut_LIBRARY}")
+ endif()
endif()
if(TARGET GLUT::Xmu)
@@ -160,9 +189,4 @@ if (GLUT_FOUND)
set (GLUT_INCLUDE_PATH ${GLUT_INCLUDE_DIR})
endif()
-mark_as_advanced(
- GLUT_INCLUDE_DIR
- GLUT_glut_LIBRARY
- GLUT_Xmu_LIBRARY
- GLUT_Xi_LIBRARY
- )
+mark_as_advanced(GLUT_INCLUDE_DIR)
diff --git a/Modules/FindLua.cmake b/Modules/FindLua.cmake
index e86c15c..68530b3 100644
--- a/Modules/FindLua.cmake
+++ b/Modules/FindLua.cmake
@@ -198,6 +198,7 @@ endif ()
find_library(LUA_LIBRARY
NAMES ${_lua_library_names} lua
+ NAMES_PER_DIR
HINTS
ENV LUA_DIR
PATH_SUFFIXES lib
diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake
index 12a2f75..547a330 100644
--- a/Modules/FindMatlab.cmake
+++ b/Modules/FindMatlab.cmake
@@ -21,6 +21,8 @@
#
# * ``MX_LIBRARY``, ``ENG_LIBRARY`` and ``MAT_LIBRARY``: respectively the ``MX``,
# ``ENG`` and ``MAT`` libraries of Matlab
+# * ``ENGINE_LIBRARY``, ``DATAARRAY_LIBRARY``: respectively the ``MatlabEngine``
+# and ``MatlabDataArray`` libraries of Matlab (Matlab 2018a and later)
# * ``MAIN_PROGRAM`` the Matlab binary program. Note that this component is not
# available on the MCR version, and will yield an error if the MCR is found
# instead of the regular Matlab installation.
@@ -107,6 +109,12 @@
# ``Matlab_MAT_LIBRARY``
# Matlab matrix library. Available only if the component ``MAT_LIBRARY``
# is requested.
+# ``Matlab_ENGINE_LIBRARY``
+# Matlab C++ engine library. Available only if the component ``ENGINE_LIBRARY``
+# is requested.
+# ``Matlab_DATAARRAY_LIBRARY``
+# Matlab C++ data array library. Available only if the component ``DATAARRAY_LIBRARY``
+# is requested.
# ``Matlab_LIBRARIES``
# the whole set of libraries of Matlab
# ``Matlab_MEX_COMPILER``
@@ -234,6 +242,8 @@ if(NOT MATLAB_ADDITIONAL_VERSIONS)
endif()
set(MATLAB_VERSIONS_MAPPING
+ "R2018b=9.5"
+ "R2018a=9.4"
"R2017b=9.3"
"R2017a=9.2"
"R2016b=9.1"
@@ -960,6 +970,14 @@ function(matlab_add_mex)
target_link_libraries(${${prefix}_NAME} ${Matlab_MX_LIBRARY})
endif()
+ if(DEFINED Matlab_ENGINE_LIBRARY)
+ target_link_libraries(${${prefix}_NAME} ${Matlab_ENGINE_LIBRARY})
+ endif()
+
+ if(DEFINED Matlab_DATAARRAY_LIBRARY)
+ target_link_libraries(${${prefix}_NAME} ${Matlab_DATAARRAY_LIBRARY})
+ endif()
+
target_link_libraries(${${prefix}_NAME} ${Matlab_MEX_LIBRARY} ${${prefix}_LINK_TO})
set_target_properties(${${prefix}_NAME}
PROPERTIES
@@ -980,6 +998,20 @@ function(matlab_add_mex)
endif() # documentation
# entry point in the mex file + taking care of visibility and symbol clashes.
+ if (MSVC)
+ get_target_property(
+ _previous_link_flags
+ ${${prefix}_NAME}
+ LINK_FLAGS)
+ if(NOT _previous_link_flags)
+ set(_previous_link_flags)
+ endif()
+
+ set_target_properties(${${prefix}_NAME}
+ PROPERTIES
+ LINK_FLAGS "${_previous_link_flags} /EXPORT:mexFunction")
+ endif()
+
if(WIN32)
set_target_properties(${${prefix}_NAME}
PROPERTIES
@@ -1416,6 +1448,8 @@ if(DEFINED Matlab_ROOT_DIR_LAST_CACHED)
Matlab_MX_LIBRARY
Matlab_ENG_LIBRARY
Matlab_MAT_LIBRARY
+ Matlab_ENGINE_LIBRARY
+ Matlab_DATAARRAY_LIBRARY
Matlab_MEX_EXTENSION
Matlab_SIMULINK_INCLUDE_DIR
@@ -1668,10 +1702,52 @@ if(_matlab_find_mcc_compiler GREATER -1)
endif()
unset(_matlab_find_mcc_compiler)
+# component MatlabEngine
+list(FIND Matlab_FIND_COMPONENTS ENGINE_LIBRARY _matlab_find_matlab_engine)
+if(_matlab_find_matlab_engine GREATER -1)
+ _Matlab_find_library(
+ ${_matlab_lib_prefix_for_search}
+ Matlab_ENGINE_LIBRARY
+ MatlabEngine
+ PATHS ${_matlab_lib_dir_for_search}
+ DOC "MatlabEngine Library"
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_ENGINE_LIBRARY)
+ set(Matlab_ENGINE_LIBRARY_FOUND TRUE)
+ endif()
+endif()
+unset(_matlab_find_matlab_engine)
+
+# component MatlabDataArray
+list(FIND Matlab_FIND_COMPONENTS DATAARRAY_LIBRARY _matlab_find_matlab_dataarray)
+if(_matlab_find_matlab_dataarray GREATER -1)
+ _Matlab_find_library(
+ ${_matlab_lib_prefix_for_search}
+ Matlab_DATAARRAY_LIBRARY
+ MatlabDataArray
+ PATHS ${_matlab_lib_dir_for_search}
+ DOC "MatlabDataArray Library"
+ NO_DEFAULT_PATH
+ )
+ if(Matlab_DATAARRAY_LIBRARY)
+ set(Matlab_DATAARRAY_LIBRARY_FOUND TRUE)
+ endif()
+endif()
+unset(_matlab_find_matlab_dataarray)
+
unset(_matlab_lib_dir_for_search)
set(Matlab_LIBRARIES ${Matlab_MEX_LIBRARY} ${Matlab_MX_LIBRARY} ${Matlab_ENG_LIBRARY} ${Matlab_MAT_LIBRARY})
+if(Matlab_DATAARRAY_LIBRARY_FOUND)
+ set(Matlab_LIBRARIES ${Matlab_LIBRARIES} ${Matlab_DATAARRAY_LIBRARY})
+endif()
+
+if(Matlab_ENGINE_LIBRARY_FOUND)
+ set(Matlab_LIBRARIES ${Matlab_LIBRARIES} ${Matlab_ENGINE_LIBRARY})
+endif()
+
find_package_handle_standard_args(
Matlab
FOUND_VAR Matlab_FOUND
@@ -1692,6 +1768,8 @@ if(Matlab_INCLUDE_DIRS AND Matlab_LIBRARIES)
Matlab_MEX_LIBRARY
Matlab_MX_LIBRARY
Matlab_ENG_LIBRARY
+ Matlab_ENGINE_LIBRARY
+ Matlab_DATAARRAY_LIBRARY
Matlab_MAT_LIBRARY
Matlab_INCLUDE_DIRS
Matlab_FOUND
diff --git a/Modules/Internal/CPack/CPackDeb.cmake b/Modules/Internal/CPack/CPackDeb.cmake
index ca3a004..3042a16 100644
--- a/Modules/Internal/CPack/CPackDeb.cmake
+++ b/Modules/Internal/CPack/CPackDeb.cmake
@@ -64,6 +64,8 @@ function(cpack_deb_prepare_package_vars)
endif()
set(WDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_DEB_PACKAGE_COMPONENT_PART_PATH}")
+ set(DBGSYMDIR "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_DEB_PACKAGE_COMPONENT_PART_PATH}-dbgsym")
+ file(REMOVE_RECURSE "${DBGSYMDIR}")
# per component automatic discover: some of the component might not have
# binaries.
@@ -80,7 +82,10 @@ function(cpack_deb_prepare_package_vars)
endif()
endif()
- if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OR CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS)
+ cpack_deb_variable_fallback("CPACK_DEBIAN_DEBUGINFO_PACKAGE"
+ "CPACK_DEBIAN_${_local_component_name}_DEBUGINFO_PACKAGE"
+ "CPACK_DEBIAN_DEBUGINFO_PACKAGE")
+ if(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OR CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS OR CPACK_DEBIAN_DEBUGINFO_PACKAGE)
# Generating binary list - Get type of all install files
file(GLOB_RECURSE FILE_PATHS_ LIST_DIRECTORIES false RELATIVE "${WDIR}" "${WDIR}/*")
@@ -92,7 +97,7 @@ function(cpack_deb_prepare_package_vars)
# get file info so that we can determine if file is executable or not
unset(CPACK_DEB_INSTALL_FILES)
foreach(FILE_ IN LISTS FILE_PATHS_)
- execute_process(COMMAND env LC_ALL=C ${FILE_EXECUTABLE} "./${FILE_}"
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${FILE_EXECUTABLE} "./${FILE_}"
WORKING_DIRECTORY "${WDIR}"
RESULT_VARIABLE FILE_RESULT_
OUTPUT_VARIABLE INSTALL_FILE_)
@@ -114,6 +119,81 @@ function(cpack_deb_prepare_package_vars)
string(REGEX MATCH "(^.*):" _FILE_NAME "${_FILE}")
list(APPEND CPACK_DEB_SHARED_OBJECT_FILES "${CMAKE_MATCH_1}")
endif()
+ if(_FILE MATCHES "ELF.*not stripped")
+ string(REGEX MATCH "(^.*):" _FILE_NAME "${_FILE}")
+ list(APPEND CPACK_DEB_UNSTRIPPED_FILES "${CMAKE_MATCH_1}")
+ endif()
+ endforeach()
+ endif()
+
+ find_program(READELF_EXECUTABLE NAMES readelf)
+
+ if(CPACK_DEBIAN_DEBUGINFO_PACKAGE AND CPACK_DEB_UNSTRIPPED_FILES)
+ find_program(OBJCOPY_EXECUTABLE NAMES objcopy)
+
+ if(NOT OBJCOPY_EXECUTABLE)
+ message(FATAL_ERROR "debuginfo packages require the objcopy tool")
+ endif()
+ if(NOT READELF_EXECUTABLE)
+ message(FATAL_ERROR "debuginfo packages require the readelf tool")
+ endif()
+
+ file(RELATIVE_PATH _DBGSYM_ROOT "${CPACK_TEMPORARY_DIRECTORY}" "${DBGSYMDIR}")
+ foreach(_FILE IN LISTS CPACK_DEB_UNSTRIPPED_FILES)
+
+ # Get the file's Build ID
+ execute_process(COMMAND env LC_ALL=C ${READELF_EXECUTABLE} -n "${_FILE}"
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE READELF_OUTPUT
+ RESULT_VARIABLE READELF_RESULT
+ ERROR_VARIABLE READELF_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(NOT READELF_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: readelf: '${READELF_ERROR}';\n"
+ "executed command: '${READELF_EXECUTABLE} -n ${_FILE}'")
+ endif()
+ if(READELF_OUTPUT MATCHES "Build ID: ([0-9a-zA-Z][0-9a-zA-Z])([0-9a-zA-Z]*)")
+ set(_BUILD_ID_START ${CMAKE_MATCH_1})
+ set(_BUILD_ID_REMAINING ${CMAKE_MATCH_2})
+ list(APPEND BUILD_IDS ${_BUILD_ID_START}${_BUILD_ID_REMAINING})
+ else()
+ message(FATAL_ERROR "Unable to determine Build ID for ${_FILE}")
+ endif()
+
+ # Split out the debug symbols from the binaries
+ set(_FILE_DBGSYM ${_DBGSYM_ROOT}/usr/lib/debug/.build-id/${_BUILD_ID_START}/${_BUILD_ID_REMAINING}.debug)
+ get_filename_component(_OUT_DIR "${_FILE_DBGSYM}" DIRECTORY)
+ file(MAKE_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}/${_OUT_DIR}")
+ execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --only-keep-debug "${_FILE}" "${_FILE_DBGSYM}"
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE OBJCOPY_OUTPUT
+ RESULT_VARIABLE OBJCOPY_RESULT
+ ERROR_VARIABLE OBJCOPY_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(NOT OBJCOPY_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
+ "executed command: '${OBJCOPY_EXECUTABLE} --only-keep-debug ${_FILE} ${_FILE_DBGSYM}'")
+ endif()
+ execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --strip-unneeded ${_FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE OBJCOPY_OUTPUT
+ RESULT_VARIABLE OBJCOPY_RESULT
+ ERROR_VARIABLE OBJCOPY_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(NOT OBJCOPY_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
+ "executed command: '${OBJCOPY_EXECUTABLE} --strip-debug ${_FILE}'")
+ endif()
+ execute_process(COMMAND ${OBJCOPY_EXECUTABLE} --add-gnu-debuglink=${_FILE_DBGSYM} ${_FILE}
+ WORKING_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}"
+ OUTPUT_VARIABLE OBJCOPY_OUTPUT
+ RESULT_VARIABLE OBJCOPY_RESULT
+ ERROR_VARIABLE OBJCOPY_ERROR
+ OUTPUT_STRIP_TRAILING_WHITESPACE )
+ if(NOT OBJCOPY_RESULT EQUAL 0)
+ message(FATAL_ERROR "CPackDeb: objcopy: '${OBJCOPY_ERROR}';\n"
+ "executed command: '${OBJCOPY_EXECUTABLE} --add-gnu-debuglink=${_FILE_DBGSYM} ${_FILE}'")
+ endif()
endforeach()
endif()
@@ -123,7 +203,7 @@ function(cpack_deb_prepare_package_vars)
if(SHLIBDEPS_EXECUTABLE)
# Check version of the dpkg-shlibdeps tool using CPackDEB method
- execute_process(COMMAND env LC_ALL=C ${SHLIBDEPS_EXECUTABLE} --version
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${SHLIBDEPS_EXECUTABLE} --version
OUTPUT_VARIABLE _TMP_VERSION
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -151,7 +231,7 @@ function(cpack_deb_prepare_package_vars)
file(MAKE_DIRECTORY "${CPACK_TEMPORARY_DIRECTORY}/DEBIAN")
# Add --ignore-missing-info if the tool supports it
- execute_process(COMMAND env LC_ALL=C ${SHLIBDEPS_EXECUTABLE} --help
+ execute_process(COMMAND ${CMAKE_COMMAND} -E env LC_ALL=C ${SHLIBDEPS_EXECUTABLE} --help
OUTPUT_VARIABLE _TMP_HELP
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -450,8 +530,6 @@ function(cpack_deb_prepare_package_vars)
set(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS_POLICY "=")
endif()
- find_program(READELF_EXECUTABLE NAMES readelf)
-
if(CPACK_DEBIAN_PACKAGE_GENERATE_SHLIBS)
if(READELF_EXECUTABLE)
foreach(_FILE IN LISTS CPACK_DEB_SHARED_OBJECT_FILES)
@@ -507,18 +585,24 @@ function(cpack_deb_prepare_package_vars)
# <foo>_<VersionNumber>-<DebianRevisionNumber>_<DebianArchitecture>.deb
set(CPACK_OUTPUT_FILE_NAME
"${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.deb")
+ set(CPACK_DBGSYM_OUTPUT_FILE_NAME
+ "${CPACK_DEBIAN_PACKAGE_NAME}-dbgsym_${CPACK_DEBIAN_PACKAGE_VERSION}_${CPACK_DEBIAN_PACKAGE_ARCHITECTURE}.ddeb")
else()
if(NOT CPACK_DEBIAN_FILE_NAME MATCHES ".*\\.(deb|ipk)")
message(FATAL_ERROR "'${CPACK_DEBIAN_FILE_NAME}' is not a valid DEB package file name as it must end with '.deb' or '.ipk'!")
endif()
set(CPACK_OUTPUT_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}")
+ string(REGEX REPLACE "\.deb$" "-dbgsym.ddeb" CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_DEBIAN_FILE_NAME}")
endif()
set(CPACK_TEMPORARY_PACKAGE_FILE_NAME "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_OUTPUT_FILE_NAME}")
get_filename_component(BINARY_DIR "${CPACK_OUTPUT_FILE_PATH}" DIRECTORY)
set(CPACK_OUTPUT_FILE_PATH "${BINARY_DIR}/${CPACK_OUTPUT_FILE_NAME}")
- endif() # else() back compatibility - don't change the name
+ else()
+ # back compatibility - don't change the name
+ string(REGEX REPLACE "\.deb$" "-dbgsym.ddeb" CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_OUTPUT_FILE_NAME}")
+ endif()
# Print out some debug information if we were asked for that
if(CPACK_DEBIAN_PACKAGE_DEBUG)
@@ -579,6 +663,14 @@ function(cpack_deb_prepare_package_vars)
set(GEN_CPACK_DEBIAN_GENERATE_POSTINST "${CPACK_DEBIAN_GENERATE_POSTINST}" PARENT_SCOPE)
set(GEN_CPACK_DEBIAN_GENERATE_POSTRM "${CPACK_DEBIAN_GENERATE_POSTRM}" PARENT_SCOPE)
set(GEN_WDIR "${WDIR}" PARENT_SCOPE)
+
+ set(GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE "${CPACK_DEBIAN_DEBUGINFO_PACKAGE}" PARENT_SCOPE)
+ if(BUILD_IDS)
+ set(GEN_DBGSYMDIR "${DBGSYMDIR}" PARENT_SCOPE)
+ set(GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME "${CPACK_DBGSYM_OUTPUT_FILE_NAME}" PARENT_SCOPE)
+ string(REPLACE ";" " " BUILD_IDS "${BUILD_IDS}")
+ set(GEN_BUILD_IDS "${BUILD_IDS}" PARENT_SCOPE)
+ endif()
endfunction()
cpack_deb_prepare_package_vars()
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 628cc6f..3cf6c8f 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -579,6 +579,8 @@ set(SRCS
cmTargetIncludeDirectoriesCommand.h
cmTargetLinkOptionsCommand.cxx
cmTargetLinkOptionsCommand.h
+ cmTargetLinkDirectoriesCommand.cxx
+ cmTargetLinkDirectoriesCommand.h
cmTargetLinkLibrariesCommand.cxx
cmTargetLinkLibrariesCommand.h
cmTargetPropCommandBase.cxx
@@ -1047,6 +1049,9 @@ target_link_libraries(cmake CMakeLib)
add_library(CMakeServerLib
cmConnection.h cmConnection.cxx
cmFileMonitor.cxx cmFileMonitor.h
+ cmJsonObjectDictionary.h
+ cmJsonObjects.h
+ cmJsonObjects.cxx
cmPipeConnection.cxx cmPipeConnection.h
cmServer.cxx cmServer.h
cmServerConnection.cxx cmServerConnection.h
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 22d519f..d9aa818 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 12)
-set(CMake_VERSION_PATCH 20180921)
+set(CMake_VERSION_PATCH 20180928)
#set(CMake_VERSION_RC 1)
diff --git a/Source/CPack/cmCPackDebGenerator.cxx b/Source/CPack/cmCPackDebGenerator.cxx
index 972fe6f..ea0ee58 100644
--- a/Source/CPack/cmCPackDebGenerator.cxx
+++ b/Source/CPack/cmCPackDebGenerator.cxx
@@ -12,11 +12,430 @@
#include "cm_sys_stat.h"
#include "cmsys/Glob.hxx"
+#include <map>
#include <ostream>
#include <set>
#include <string.h>
#include <utility>
+namespace {
+
+class DebGenerator
+{
+public:
+ DebGenerator(cmCPackLog* logger, std::string const& outputName,
+ std::string const& workDir, std::string const& topLevelDir,
+ std::string const& temporaryDir,
+ const char* debianCompressionType,
+ const char* debianArchiveType,
+ std::map<std::string, std::string> const& controlValues,
+ bool genShLibs, std::string const& shLibsFilename,
+ bool genPostInst, std::string const& postInst, bool genPostRm,
+ std::string const& postRm, const char* controlExtra,
+ bool permissionStrctPolicy,
+ std::vector<std::string> const& packageFiles);
+
+ bool generate() const;
+
+private:
+ void generateDebianBinaryFile() const;
+ void generateControlFile() const;
+ bool generateDataTar() const;
+ std::string generateMD5File() const;
+ bool generateControlTar(std::string const& md5Filename) const;
+ bool generateDeb() const;
+
+ cmCPackLog* Logger;
+ const std::string OutputName;
+ const std::string WorkDir;
+ std::string CompressionSuffix;
+ const std::string TopLevelDir;
+ const std::string TemporaryDir;
+ const char* DebianArchiveType;
+ const std::map<std::string, std::string> ControlValues;
+ const bool GenShLibs;
+ const std::string ShLibsFilename;
+ const bool GenPostInst;
+ const std::string PostInst;
+ const bool GenPostRm;
+ const std::string PostRm;
+ const char* ControlExtra;
+ const bool PermissionStrictPolicy;
+ const std::vector<std::string> PackageFiles;
+ cmArchiveWrite::Compress TarCompressionType;
+};
+
+DebGenerator::DebGenerator(
+ cmCPackLog* logger, std::string const& outputName,
+ std::string const& workDir, std::string const& topLevelDir,
+ std::string const& temporaryDir, const char* debianCompressionType,
+ const char* debianArchiveType,
+ std::map<std::string, std::string> const& controlValues, bool genShLibs,
+ std::string const& shLibsFilename, bool genPostInst,
+ std::string const& postInst, bool genPostRm, std::string const& postRm,
+ const char* controlExtra, bool permissionStrictPolicy,
+ std::vector<std::string> const& packageFiles)
+ : Logger(logger)
+ , OutputName(outputName)
+ , WorkDir(workDir)
+ , TopLevelDir(topLevelDir)
+ , TemporaryDir(temporaryDir)
+ , DebianArchiveType(debianArchiveType ? debianArchiveType : "paxr")
+ , ControlValues(controlValues)
+ , GenShLibs(genShLibs)
+ , ShLibsFilename(shLibsFilename)
+ , GenPostInst(genPostInst)
+ , PostInst(postInst)
+ , GenPostRm(genPostRm)
+ , PostRm(postRm)
+ , ControlExtra(controlExtra)
+ , PermissionStrictPolicy(permissionStrictPolicy)
+ , PackageFiles(packageFiles)
+{
+ if (!debianCompressionType) {
+ debianCompressionType = "gzip";
+ }
+
+ if (!strcmp(debianCompressionType, "lzma")) {
+ CompressionSuffix = ".lzma";
+ TarCompressionType = cmArchiveWrite::CompressLZMA;
+ } else if (!strcmp(debianCompressionType, "xz")) {
+ CompressionSuffix = ".xz";
+ TarCompressionType = cmArchiveWrite::CompressXZ;
+ } else if (!strcmp(debianCompressionType, "bzip2")) {
+ CompressionSuffix = ".bz2";
+ TarCompressionType = cmArchiveWrite::CompressBZip2;
+ } else if (!strcmp(debianCompressionType, "gzip")) {
+ CompressionSuffix = ".gz";
+ TarCompressionType = cmArchiveWrite::CompressGZip;
+ } else if (!strcmp(debianCompressionType, "none")) {
+ CompressionSuffix.clear();
+ TarCompressionType = cmArchiveWrite::CompressNone;
+ } else {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error unrecognized compression type: "
+ << debianCompressionType << std::endl);
+ }
+}
+
+bool DebGenerator::generate() const
+{
+ generateDebianBinaryFile();
+ generateControlFile();
+ if (!generateDataTar()) {
+ return false;
+ }
+ std::string md5Filename = generateMD5File();
+ if (!generateControlTar(md5Filename)) {
+ return false;
+ }
+ return generateDeb();
+}
+
+void DebGenerator::generateDebianBinaryFile() const
+{
+ // debian-binary file
+ const std::string dbfilename = WorkDir + "/debian-binary";
+ cmGeneratedFileStream out(dbfilename);
+ out << "2.0";
+ out << std::endl; // required for valid debian package
+}
+
+void DebGenerator::generateControlFile() const
+{
+ std::string ctlfilename = WorkDir + "/control";
+
+ cmGeneratedFileStream out(ctlfilename);
+ for (auto const& kv : ControlValues) {
+ out << kv.first << ": " << kv.second << "\n";
+ }
+
+ unsigned long totalSize = 0;
+ {
+ std::string dirName = TemporaryDir;
+ dirName += '/';
+ for (std::string const& file : PackageFiles) {
+ totalSize += cmSystemTools::FileLength(file);
+ }
+ }
+ out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n";
+ out << std::endl;
+}
+
+bool DebGenerator::generateDataTar() const
+{
+ std::string filename_data_tar = WorkDir + "/data.tar" + CompressionSuffix;
+ cmGeneratedFileStream fileStream_data_tar;
+ fileStream_data_tar.Open(filename_data_tar, false, true);
+ if (!fileStream_data_tar) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error opening the file \""
+ << filename_data_tar << "\" for writing" << std::endl);
+ return false;
+ }
+ cmArchiveWrite data_tar(fileStream_data_tar, TarCompressionType,
+ DebianArchiveType);
+
+ // uid/gid should be the one of the root user, and this root user has
+ // always uid/gid equal to 0.
+ data_tar.SetUIDAndGID(0u, 0u);
+ data_tar.SetUNAMEAndGNAME("root", "root");
+
+ // now add all directories which have to be compressed
+ // collect all top level install dirs for that
+ // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would
+ // give /usr and /opt
+ size_t topLevelLength = WorkDir.length();
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "WDIR: \"" << WorkDir << "\", length = " << topLevelLength
+ << std::endl);
+ std::set<std::string> orderedFiles;
+
+ // we have to reconstruct the parent folders as well
+
+ for (std::string currentPath : PackageFiles) {
+ while (currentPath != WorkDir) {
+ // the last one IS WorkDir, but we do not want this one:
+ // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
+ // should not add XXX/application
+ orderedFiles.insert(currentPath);
+ currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
+ }
+ }
+
+ for (std::string const& file : orderedFiles) {
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "FILEIT: \"" << file << "\"" << std::endl);
+ std::string::size_type slashPos = file.find('/', topLevelLength + 1);
+ std::string relativeDir =
+ file.substr(topLevelLength, slashPos - topLevelLength);
+ cmCPackLogger(cmCPackLog::LOG_DEBUG,
+ "RELATIVEDIR: \"" << relativeDir << "\"" << std::endl);
+
+#ifdef WIN32
+ std::string mode_t_adt_filename = file + ":cmake_mode_t";
+ cmsys::ifstream permissionStream(mode_t_adt_filename.c_str());
+
+ mode_t permissions = 0;
+
+ if (permissionStream) {
+ permissionStream >> std::oct >> permissions;
+ }
+
+ if (permissions != 0) {
+ data_tar.SetPermissions(permissions);
+ } else if (cmSystemTools::FileIsDirectory(file)) {
+ data_tar.SetPermissions(0755);
+ } else {
+ data_tar.ClearPermissions();
+ }
+#endif
+
+ // do not recurse because the loop will do it
+ if (!data_tar.Add(file, topLevelLength, ".", false)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem adding file to tar:"
+ << std::endl
+ << "#top level directory: " << WorkDir << std::endl
+ << "#file: " << file << std::endl
+ << "#error:" << data_tar.GetError() << std::endl);
+ return false;
+ }
+ }
+ return true;
+}
+
+std::string DebGenerator::generateMD5File() const
+{
+ std::string md5filename = WorkDir + "/md5sums";
+
+ cmGeneratedFileStream out(md5filename);
+
+ std::string topLevelWithTrailingSlash = TemporaryDir;
+ topLevelWithTrailingSlash += '/';
+ for (std::string const& file : PackageFiles) {
+ // hash only regular files
+ if (cmSystemTools::FileIsDirectory(file) ||
+ cmSystemTools::FileIsSymlink(file)) {
+ continue;
+ }
+
+ std::string output =
+ cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5);
+ if (output.empty()) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Problem computing the md5 of " << file << std::endl);
+ }
+
+ output += " " + file + "\n";
+ // debian md5sums entries are like this:
+ // 014f3604694729f3bf19263bac599765 usr/bin/ccmake
+ // thus strip the full path (with the trailing slash)
+ cmSystemTools::ReplaceString(output, topLevelWithTrailingSlash.c_str(),
+ "");
+ out << output;
+ }
+ // each line contains a eol.
+ // Do not end the md5sum file with yet another (invalid)
+ return md5filename;
+}
+
+bool DebGenerator::generateControlTar(std::string const& md5Filename) const
+{
+ std::string filename_control_tar = WorkDir + "/control.tar.gz";
+
+ cmGeneratedFileStream fileStream_control_tar;
+ fileStream_control_tar.Open(filename_control_tar, false, true);
+ if (!fileStream_control_tar) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error opening the file \""
+ << filename_control_tar << "\" for writing" << std::endl);
+ return false;
+ }
+ cmArchiveWrite control_tar(fileStream_control_tar,
+ cmArchiveWrite::CompressGZip, DebianArchiveType);
+
+ // sets permissions and uid/gid for the files
+ control_tar.SetUIDAndGID(0u, 0u);
+ control_tar.SetUNAMEAndGNAME("root", "root");
+
+ /* permissions are set according to
+ https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
+ and
+ https://lintian.debian.org/tags/control-file-has-bad-permissions.html
+ */
+ const mode_t permission644 = 0644;
+ const mode_t permissionExecute = 0111;
+ const mode_t permission755 = permission644 | permissionExecute;
+
+ // for md5sum and control (that we have generated here), we use 644
+ // (RW-R--R--)
+ // so that deb lintian doesn't warn about it
+ control_tar.SetPermissions(permission644);
+
+ // adds control and md5sums
+ if (!control_tar.Add(md5Filename, WorkDir.length(), ".") ||
+ !control_tar.Add(WorkDir + "/control", WorkDir.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << WorkDir << std::endl
+ << "#file: \"control\" or \"md5sums\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return false;
+ }
+
+ // adds generated shlibs file
+ if (GenShLibs) {
+ if (!control_tar.Add(ShLibsFilename, WorkDir.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << WorkDir << std::endl
+ << "#file: \"shlibs\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return false;
+ }
+ }
+
+ // adds LDCONFIG related files
+ if (GenPostInst) {
+ control_tar.SetPermissions(permission755);
+ if (!control_tar.Add(PostInst, WorkDir.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << WorkDir << std::endl
+ << "#file: \"postinst\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return false;
+ }
+ control_tar.SetPermissions(permission644);
+ }
+
+ if (GenPostRm) {
+ control_tar.SetPermissions(permission755);
+ if (!control_tar.Add(PostRm, WorkDir.length(), ".")) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error adding file to tar:"
+ << std::endl
+ << "#top level directory: " << WorkDir << std::endl
+ << "#file: \"postinst\"" << std::endl
+ << "#error:" << control_tar.GetError() << std::endl);
+ return false;
+ }
+ control_tar.SetPermissions(permission644);
+ }
+
+ // for the other files, we use
+ // -either the original permission on the files
+ // -either a permission strictly defined by the Debian policies
+ if (ControlExtra) {
+ // permissions are now controlled by the original file permissions
+
+ static const char* strictFiles[] = { "config", "postinst", "postrm",
+ "preinst", "prerm" };
+ std::set<std::string> setStrictFiles(
+ strictFiles, strictFiles + sizeof(strictFiles) / sizeof(strictFiles[0]));
+
+ // default
+ control_tar.ClearPermissions();
+
+ std::vector<std::string> controlExtraList;
+ cmSystemTools::ExpandListArgument(ControlExtra, controlExtraList);
+ for (std::string const& i : controlExtraList) {
+ std::string filenamename = cmsys::SystemTools::GetFilenameName(i);
+ std::string localcopy = WorkDir + "/" + filenamename;
+
+ if (PermissionStrictPolicy) {
+ control_tar.SetPermissions(
+ setStrictFiles.count(filenamename) ? permission755 : permission644);
+ }
+
+ // if we can copy the file, it means it does exist, let's add it:
+ if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
+ control_tar.Add(localcopy, WorkDir.length(), ".");
+ }
+ }
+ }
+
+ return true;
+}
+
+bool DebGenerator::generateDeb() const
+{
+ // ar -r your-package-name.deb debian-binary control.tar.* data.tar.*
+ // A debian package .deb is simply an 'ar' archive. The only subtle
+ // difference is that debian uses the BSD ar style archive whereas most
+ // Linux distro have a GNU ar.
+ // See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
+ std::string const outputPath = TopLevelDir + "/" + OutputName;
+ std::string const tlDir = WorkDir + "/";
+ cmGeneratedFileStream debStream;
+ debStream.Open(outputPath, false, true);
+ cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd");
+
+ // uid/gid should be the one of the root user, and this root user has
+ // always uid/gid equal to 0.
+ deb.SetUIDAndGID(0u, 0u);
+ deb.SetUNAMEAndGNAME("root", "root");
+
+ if (!deb.Add(tlDir + "debian-binary", tlDir.length()) ||
+ !deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
+ !deb.Add(tlDir + "data.tar" + CompressionSuffix, tlDir.length())) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Error creating debian package:"
+ << std::endl
+ << "#top level directory: " << TopLevelDir << std::endl
+ << "#file: " << OutputName << std::endl
+ << "#error:" << deb.GetError() << std::endl);
+ return false;
+ }
+ return true;
+}
+
+} // end anonymous namespace
+
cmCPackDebGenerator::cmCPackDebGenerator()
{
}
@@ -68,18 +487,20 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
return retval;
}
- cmsys::Glob gl;
- std::string findExpr(this->GetOption("GEN_WDIR"));
- findExpr += "/*";
- gl.RecurseOn();
- gl.SetRecurseListDirs(true);
- if (!gl.FindFiles(findExpr)) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Cannot find any files in the installed directory"
- << std::endl);
- return 0;
+ { // Isolate globbing of binaries vs. dbgsyms
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_WDIR"));
+ findExpr += "/*";
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ packageFiles = gl.GetFiles();
}
- packageFiles = gl.GetFiles();
int res = createDeb();
if (res != 1) {
@@ -90,6 +511,32 @@ int cmCPackDebGenerator::PackageOnePack(std::string const& initialTopLevel,
packageFileName += "/";
packageFileName += this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
packageFileNames.push_back(std::move(packageFileName));
+
+ if (this->IsOn("GEN_CPACK_DEBIAN_DEBUGINFO_PACKAGE")) {
+ cmsys::Glob gl;
+ std::string findExpr(this->GetOption("GEN_DBGSYMDIR"));
+ findExpr += "/*";
+ gl.RecurseOn();
+ gl.SetRecurseListDirs(true);
+ if (!gl.FindFiles(findExpr)) {
+ cmCPackLogger(cmCPackLog::LOG_ERROR,
+ "Cannot find any files in the installed directory"
+ << std::endl);
+ return 0;
+ }
+ packageFiles = gl.GetFiles();
+
+ res = createDbgsymDDeb();
+ if (res != 1) {
+ retval = 0;
+ }
+ // add the generated package to package file names list
+ packageFileName = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
+ packageFileName += "/";
+ packageFileName += this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME");
+ packageFileNames.push_back(std::move(packageFileName));
+ }
+
return retval;
}
@@ -234,112 +681,81 @@ int cmCPackDebGenerator::PackageFiles()
int cmCPackDebGenerator::createDeb()
{
- // debian-binary file
- const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
- const std::string dbfilename = strGenWDIR + "/debian-binary";
- { // the scope is needed for cmGeneratedFileStream
- cmGeneratedFileStream out(dbfilename);
- out << "2.0";
- out << std::endl; // required for valid debian package
- }
-
- // control file
- std::string ctlfilename = strGenWDIR + "/control";
+ std::map<std::string, std::string> controlValues;
// debian policy enforce lower case for package name
- // mandatory entries:
- std::string debian_pkg_name = cmsys::SystemTools::LowerCase(
+ controlValues["Package"] = cmsys::SystemTools::LowerCase(
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
- const char* debian_pkg_version =
+ controlValues["Version"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
- const char* debian_pkg_section =
+ controlValues["Section"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SECTION");
- const char* debian_pkg_priority =
+ controlValues["Priority"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PRIORITY");
- const char* debian_pkg_arch =
+ controlValues["Architecture"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
- const char* maintainer =
+ controlValues["Maintainer"] =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
- const char* desc = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
+ controlValues["Description"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DESCRIPTION");
- // optional entries
+ const char* debian_pkg_source =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
+ if (debian_pkg_source && *debian_pkg_source) {
+ controlValues["Source"] = debian_pkg_source;
+ }
const char* debian_pkg_dep =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_DEPENDS");
+ if (debian_pkg_dep && *debian_pkg_dep) {
+ controlValues["Depends"] = debian_pkg_dep;
+ }
const char* debian_pkg_rec =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_RECOMMENDS");
+ if (debian_pkg_rec && *debian_pkg_rec) {
+ controlValues["Recommends"] = debian_pkg_rec;
+ }
const char* debian_pkg_sug =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SUGGESTS");
+ if (debian_pkg_sug && *debian_pkg_sug) {
+ controlValues["Suggests"] = debian_pkg_sug;
+ }
const char* debian_pkg_url =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_HOMEPAGE");
+ if (debian_pkg_url && *debian_pkg_url) {
+ controlValues["Homepage"] = debian_pkg_url;
+ }
const char* debian_pkg_predep =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PREDEPENDS");
+ if (debian_pkg_predep && *debian_pkg_predep) {
+ controlValues["Pre-Depends"] = debian_pkg_predep;
+ }
const char* debian_pkg_enhances =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ENHANCES");
+ if (debian_pkg_enhances && *debian_pkg_enhances) {
+ controlValues["Enhances"] = debian_pkg_enhances;
+ }
const char* debian_pkg_breaks =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_BREAKS");
+ if (debian_pkg_breaks && *debian_pkg_breaks) {
+ controlValues["Breaks"] = debian_pkg_breaks;
+ }
const char* debian_pkg_conflicts =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONFLICTS");
+ if (debian_pkg_conflicts && *debian_pkg_conflicts) {
+ controlValues["Conflicts"] = debian_pkg_conflicts;
+ }
const char* debian_pkg_provides =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_PROVIDES");
+ if (debian_pkg_provides && *debian_pkg_provides) {
+ controlValues["Provides"] = debian_pkg_provides;
+ }
const char* debian_pkg_replaces =
this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_REPLACES");
- const char* debian_pkg_source =
- this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
-
- { // the scope is needed for cmGeneratedFileStream
- cmGeneratedFileStream out(ctlfilename);
- out << "Package: " << debian_pkg_name << "\n";
- out << "Version: " << debian_pkg_version << "\n";
- out << "Section: " << debian_pkg_section << "\n";
- out << "Priority: " << debian_pkg_priority << "\n";
- out << "Architecture: " << debian_pkg_arch << "\n";
- if (debian_pkg_source && *debian_pkg_source) {
- out << "Source: " << debian_pkg_source << "\n";
- }
- if (debian_pkg_dep && *debian_pkg_dep) {
- out << "Depends: " << debian_pkg_dep << "\n";
- }
- if (debian_pkg_rec && *debian_pkg_rec) {
- out << "Recommends: " << debian_pkg_rec << "\n";
- }
- if (debian_pkg_sug && *debian_pkg_sug) {
- out << "Suggests: " << debian_pkg_sug << "\n";
- }
- if (debian_pkg_url && *debian_pkg_url) {
- out << "Homepage: " << debian_pkg_url << "\n";
- }
- if (debian_pkg_predep && *debian_pkg_predep) {
- out << "Pre-Depends: " << debian_pkg_predep << "\n";
- }
- if (debian_pkg_enhances && *debian_pkg_enhances) {
- out << "Enhances: " << debian_pkg_enhances << "\n";
- }
- if (debian_pkg_breaks && *debian_pkg_breaks) {
- out << "Breaks: " << debian_pkg_breaks << "\n";
- }
- if (debian_pkg_conflicts && *debian_pkg_conflicts) {
- out << "Conflicts: " << debian_pkg_conflicts << "\n";
- }
- if (debian_pkg_provides && *debian_pkg_provides) {
- out << "Provides: " << debian_pkg_provides << "\n";
- }
- if (debian_pkg_replaces && *debian_pkg_replaces) {
- out << "Replaces: " << debian_pkg_replaces << "\n";
- }
- unsigned long totalSize = 0;
- {
- std::string dirName = this->GetOption("CPACK_TEMPORARY_DIRECTORY");
- dirName += '/';
- for (std::string const& file : packageFiles) {
- totalSize += cmSystemTools::FileLength(file);
- }
- }
- out << "Installed-Size: " << (totalSize + 1023) / 1024 << "\n";
- out << "Maintainer: " << maintainer << "\n";
- out << "Description: " << desc << "\n";
- out << std::endl;
+ if (debian_pkg_replaces && *debian_pkg_replaces) {
+ controlValues["Replaces"] = debian_pkg_replaces;
}
+ const std::string strGenWDIR(this->GetOption("GEN_WDIR"));
const std::string shlibsfilename = strGenWDIR + "/shlibs";
const char* debian_pkg_shlibs =
@@ -371,314 +787,74 @@ int cmCPackDebGenerator::createDeb()
"fi\n";
}
- cmArchiveWrite::Compress tar_compression_type = cmArchiveWrite::CompressGZip;
- const char* debian_compression_type =
- this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE");
- if (!debian_compression_type) {
- debian_compression_type = "gzip";
- }
-
- std::string compression_suffix;
- if (!strcmp(debian_compression_type, "lzma")) {
- compression_suffix = ".lzma";
- tar_compression_type = cmArchiveWrite::CompressLZMA;
- } else if (!strcmp(debian_compression_type, "xz")) {
- compression_suffix = ".xz";
- tar_compression_type = cmArchiveWrite::CompressXZ;
- } else if (!strcmp(debian_compression_type, "bzip2")) {
- compression_suffix = ".bz2";
- tar_compression_type = cmArchiveWrite::CompressBZip2;
- } else if (!strcmp(debian_compression_type, "gzip")) {
- compression_suffix = ".gz";
- tar_compression_type = cmArchiveWrite::CompressGZip;
- } else if (!strcmp(debian_compression_type, "none")) {
- compression_suffix.clear();
- tar_compression_type = cmArchiveWrite::CompressNone;
- } else {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error unrecognized compression type: "
- << debian_compression_type << std::endl);
- }
-
- const char* debian_archive_type =
- this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE");
- if (!debian_archive_type) {
- debian_archive_type = "paxr";
+ DebGenerator gen(
+ Logger, this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME"), strGenWDIR,
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
+ this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
+ this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, gen_shibs,
+ shlibsfilename, this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST"), postinst,
+ this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM"), postrm,
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA"),
+ this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
+ packageFiles);
+
+ if (!gen.generate()) {
+ return 0;
}
+ return 1;
+}
- std::string filename_data_tar =
- strGenWDIR + "/data.tar" + compression_suffix;
-
- // atomic file generation for data.tar
- {
- cmGeneratedFileStream fileStream_data_tar;
- fileStream_data_tar.Open(filename_data_tar, false, true);
- if (!fileStream_data_tar) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error opening the file \""
- << filename_data_tar << "\" for writing" << std::endl);
- return 0;
- }
- cmArchiveWrite data_tar(fileStream_data_tar, tar_compression_type,
- debian_archive_type);
-
- // uid/gid should be the one of the root user, and this root user has
- // always uid/gid equal to 0.
- data_tar.SetUIDAndGID(0u, 0u);
- data_tar.SetUNAMEAndGNAME("root", "root");
-
- // now add all directories which have to be compressed
- // collect all top level install dirs for that
- // e.g. /opt/bin/foo, /usr/bin/bar and /usr/bin/baz would
- // give /usr and /opt
- size_t topLevelLength = strGenWDIR.length();
- cmCPackLogger(cmCPackLog::LOG_DEBUG,
- "WDIR: \"" << strGenWDIR << "\", length = " << topLevelLength
- << std::endl);
- std::set<std::string> orderedFiles;
-
- // we have to reconstruct the parent folders as well
-
- for (std::string currentPath : packageFiles) {
- while (currentPath != strGenWDIR) {
- // the last one IS strGenWDIR, but we do not want this one:
- // XXX/application/usr/bin/myprogram with GEN_WDIR=XXX/application
- // should not add XXX/application
- orderedFiles.insert(currentPath);
- currentPath = cmSystemTools::CollapseCombinedPath(currentPath, "..");
- }
- }
-
- for (std::string const& file : orderedFiles) {
- cmCPackLogger(cmCPackLog::LOG_DEBUG,
- "FILEIT: \"" << file << "\"" << std::endl);
- std::string::size_type slashPos = file.find('/', topLevelLength + 1);
- std::string relativeDir =
- file.substr(topLevelLength, slashPos - topLevelLength);
- cmCPackLogger(cmCPackLog::LOG_DEBUG,
- "RELATIVEDIR: \"" << relativeDir << "\"" << std::endl);
-
-#ifdef WIN32
- std::string mode_t_adt_filename = file + ":cmake_mode_t";
- cmsys::ifstream permissionStream(mode_t_adt_filename.c_str());
-
- mode_t permissions = 0;
-
- if (permissionStream) {
- permissionStream >> std::oct >> permissions;
- }
-
- if (permissions != 0) {
- data_tar.SetPermissions(permissions);
- } else if (cmSystemTools::FileIsDirectory(file)) {
- data_tar.SetPermissions(0755);
- } else {
- data_tar.ClearPermissions();
- }
-#endif
-
- // do not recurse because the loop will do it
- if (!data_tar.Add(file, topLevelLength, ".", false)) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem adding file to tar:"
- << std::endl
- << "#top level directory: " << strGenWDIR << std::endl
- << "#file: " << file << std::endl
- << "#error:" << data_tar.GetError() << std::endl);
- return 0;
- }
- }
- } // scope for file generation
+int cmCPackDebGenerator::createDbgsymDDeb()
+{
+ // Packages containing debug symbols follow the same structure as .debs
+ // but have different metadata and content.
- std::string md5filename = strGenWDIR + "/md5sums";
- {
- // the scope is needed for cmGeneratedFileStream
- cmGeneratedFileStream out(md5filename);
-
- std::string topLevelWithTrailingSlash =
- this->GetOption("CPACK_TEMPORARY_DIRECTORY");
- topLevelWithTrailingSlash += '/';
- for (std::string const& file : packageFiles) {
- // hash only regular files
- if (cmSystemTools::FileIsDirectory(file) ||
- cmSystemTools::FileIsSymlink(file)) {
- continue;
- }
+ std::map<std::string, std::string> controlValues;
+ // debian policy enforce lower case for package name
+ std::string packageNameLower = cmsys::SystemTools::LowerCase(
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME"));
+ const char* debian_pkg_version =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_VERSION");
- std::string output =
- cmSystemTools::ComputeFileHash(file, cmCryptoHash::AlgoMD5);
- if (output.empty()) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Problem computing the md5 of " << file << std::endl);
- }
+ controlValues["Package"] = packageNameLower + "-dbgsym";
+ controlValues["Package-Type"] = "ddeb";
+ controlValues["Version"] = debian_pkg_version;
+ controlValues["Auto-Built-Package"] = "debug-symbols";
+ controlValues["Depends"] = this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_NAME") +
+ std::string(" (= ") + debian_pkg_version + ")";
+ controlValues["Section"] = "debug";
+ controlValues["Priority"] = "optional";
+ controlValues["Architecture"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_ARCHITECTURE");
+ controlValues["Maintainer"] =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_MAINTAINER");
+ controlValues["Description"] =
+ std::string("debug symbols for ") + packageNameLower;
- output += " " + file + "\n";
- // debian md5sums entries are like this:
- // 014f3604694729f3bf19263bac599765 usr/bin/ccmake
- // thus strip the full path (with the trailing slash)
- cmSystemTools::ReplaceString(output, topLevelWithTrailingSlash.c_str(),
- "");
- out << output;
- }
- // each line contains a eol.
- // Do not end the md5sum file with yet another (invalid)
+ const char* debian_pkg_source =
+ this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_SOURCE");
+ if (debian_pkg_source && *debian_pkg_source) {
+ controlValues["Source"] = debian_pkg_source;
}
-
- std::string filename_control_tar = strGenWDIR + "/control.tar.gz";
- // atomic file generation for control.tar
- {
- cmGeneratedFileStream fileStream_control_tar;
- fileStream_control_tar.Open(filename_control_tar, false, true);
- if (!fileStream_control_tar) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error opening the file \"" << filename_control_tar
- << "\" for writing"
- << std::endl);
- return 0;
- }
- cmArchiveWrite control_tar(fileStream_control_tar,
- cmArchiveWrite::CompressGZip,
- debian_archive_type);
-
- // sets permissions and uid/gid for the files
- control_tar.SetUIDAndGID(0u, 0u);
- control_tar.SetUNAMEAndGNAME("root", "root");
-
- /* permissions are set according to
- https://www.debian.org/doc/debian-policy/ch-files.html#s-permissions-owners
- and
- https://lintian.debian.org/tags/control-file-has-bad-permissions.html
- */
- const mode_t permission644 = 0644;
- const mode_t permissionExecute = 0111;
- const mode_t permission755 = permission644 | permissionExecute;
-
- // for md5sum and control (that we have generated here), we use 644
- // (RW-R--R--)
- // so that deb lintian doesn't warn about it
- control_tar.SetPermissions(permission644);
-
- // adds control and md5sums
- if (!control_tar.Add(md5filename, strGenWDIR.length(), ".") ||
- !control_tar.Add(strGenWDIR + "/control", strGenWDIR.length(), ".")) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error adding file to tar:"
- << std::endl
- << "#top level directory: " << strGenWDIR << std::endl
- << "#file: \"control\" or \"md5sums\"" << std::endl
- << "#error:" << control_tar.GetError() << std::endl);
- return 0;
- }
-
- // adds generated shlibs file
- if (gen_shibs) {
- if (!control_tar.Add(shlibsfilename, strGenWDIR.length(), ".")) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error adding file to tar:"
- << std::endl
- << "#top level directory: " << strGenWDIR << std::endl
- << "#file: \"shlibs\"" << std::endl
- << "#error:" << control_tar.GetError() << std::endl);
- return 0;
- }
- }
-
- // adds LDCONFIG related files
- if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTINST")) {
- control_tar.SetPermissions(permission755);
- if (!control_tar.Add(postinst, strGenWDIR.length(), ".")) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error adding file to tar:"
- << std::endl
- << "#top level directory: " << strGenWDIR << std::endl
- << "#file: \"postinst\"" << std::endl
- << "#error:" << control_tar.GetError() << std::endl);
- return 0;
- }
- control_tar.SetPermissions(permission644);
- }
-
- if (this->IsOn("GEN_CPACK_DEBIAN_GENERATE_POSTRM")) {
- control_tar.SetPermissions(permission755);
- if (!control_tar.Add(postrm, strGenWDIR.length(), ".")) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error adding file to tar:"
- << std::endl
- << "#top level directory: " << strGenWDIR << std::endl
- << "#file: \"postinst\"" << std::endl
- << "#error:" << control_tar.GetError() << std::endl);
- return 0;
- }
- control_tar.SetPermissions(permission644);
- }
-
- // for the other files, we use
- // -either the original permission on the files
- // -either a permission strictly defined by the Debian policies
- const char* controlExtra =
- this->GetOption("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA");
- if (controlExtra) {
- // permissions are now controlled by the original file permissions
-
- const bool permissionStrictPolicy =
- this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION");
-
- static const char* strictFiles[] = { "config", "postinst", "postrm",
- "preinst", "prerm" };
- std::set<std::string> setStrictFiles(
- strictFiles,
- strictFiles + sizeof(strictFiles) / sizeof(strictFiles[0]));
-
- // default
- control_tar.ClearPermissions();
-
- std::vector<std::string> controlExtraList;
- cmSystemTools::ExpandListArgument(controlExtra, controlExtraList);
- for (std::string const& i : controlExtraList) {
- std::string filenamename = cmsys::SystemTools::GetFilenameName(i);
- std::string localcopy = strGenWDIR + "/" + filenamename;
-
- if (permissionStrictPolicy) {
- control_tar.SetPermissions(setStrictFiles.count(filenamename)
- ? permission755
- : permission644);
- }
-
- // if we can copy the file, it means it does exist, let's add it:
- if (cmsys::SystemTools::CopyFileIfDifferent(i, localcopy)) {
- control_tar.Add(localcopy, strGenWDIR.length(), ".");
- }
- }
- }
+ const char* debian_build_ids = this->GetOption("GEN_BUILD_IDS");
+ if (debian_build_ids && *debian_build_ids) {
+ controlValues["Build-Ids"] = debian_build_ids;
}
- // ar -r your-package-name.deb debian-binary control.tar.* data.tar.*
- // A debian package .deb is simply an 'ar' archive. The only subtle
- // difference is that debian uses the BSD ar style archive whereas most
- // Linux distro have a GNU ar.
- // See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=161593 for more info
- std::string const outputDir = this->GetOption("CPACK_TOPLEVEL_DIRECTORY");
- std::string const outputName = this->GetOption("GEN_CPACK_OUTPUT_FILE_NAME");
- std::string const outputPath = outputDir + "/" + outputName;
- std::string const tlDir = strGenWDIR + "/";
- cmGeneratedFileStream debStream;
- debStream.Open(outputPath, false, true);
- cmArchiveWrite deb(debStream, cmArchiveWrite::CompressNone, "arbsd");
+ DebGenerator gen(
+ Logger, this->GetOption("GEN_CPACK_DBGSYM_OUTPUT_FILE_NAME"),
+ this->GetOption("GEN_DBGSYMDIR"),
- // uid/gid should be the one of the root user, and this root user has
- // always uid/gid equal to 0.
- deb.SetUIDAndGID(0u, 0u);
- deb.SetUNAMEAndGNAME("root", "root");
+ this->GetOption("CPACK_TOPLEVEL_DIRECTORY"),
+ this->GetOption("CPACK_TEMPORARY_DIRECTORY"),
+ this->GetOption("GEN_CPACK_DEBIAN_COMPRESSION_TYPE"),
+ this->GetOption("GEN_CPACK_DEBIAN_ARCHIVE_TYPE"), controlValues, false, "",
+ false, "", false, "", nullptr,
+ this->IsSet("GEN_CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION"),
+ packageFiles);
- if (!deb.Add(tlDir + "debian-binary", tlDir.length()) ||
- !deb.Add(tlDir + "control.tar.gz", tlDir.length()) ||
- !deb.Add(tlDir + "data.tar" + compression_suffix, tlDir.length())) {
- cmCPackLogger(cmCPackLog::LOG_ERROR,
- "Error creating debian package:"
- << std::endl
- << "#top level directory: " << outputDir << std::endl
- << "#file: " << outputName << std::endl
- << "#error:" << deb.GetError() << std::endl);
+ if (!gen.generate()) {
return 0;
}
return 1;
diff --git a/Source/CPack/cmCPackDebGenerator.h b/Source/CPack/cmCPackDebGenerator.h
index b4f0c79..2244fe7 100644
--- a/Source/CPack/cmCPackDebGenerator.h
+++ b/Source/CPack/cmCPackDebGenerator.h
@@ -65,6 +65,8 @@ protected:
private:
int createDeb();
+ int createDbgsymDDeb();
+
std::vector<std::string> packageFiles;
};
diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx
index fccbc95..668a387 100644
--- a/Source/CTest/cmCTestBuildAndTestHandler.cxx
+++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx
@@ -5,6 +5,7 @@
#include "cmCTest.h"
#include "cmCTestTestHandler.h"
#include "cmGlobalGenerator.h"
+#include "cmMakefile.h"
#include "cmSystemTools.h"
#include "cmWorkingDirectory.h"
#include "cmake.h"
@@ -210,9 +211,14 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring)
if (this->BuildNoCMake) {
// Make the generator available for the Build call below.
- cm.SetGlobalGenerator(cm.CreateGlobalGenerator(this->BuildGenerator));
- cm.SetGeneratorPlatform(this->BuildGeneratorPlatform);
- cm.SetGeneratorToolset(this->BuildGeneratorToolset);
+ cmGlobalGenerator* gen = cm.CreateGlobalGenerator(this->BuildGenerator);
+ cm.SetGlobalGenerator(gen);
+ if (!this->BuildGeneratorPlatform.empty()) {
+ cmMakefile mf(gen, cm.GetCurrentSnapshot());
+ if (!gen->SetGeneratorPlatform(this->BuildGeneratorPlatform, &mf)) {
+ return 1;
+ }
+ }
// Load the cache to make CMAKE_MAKE_PROGRAM available.
cm.LoadCache(this->BinaryDir);
diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index 3aa59d6..22ae340 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -171,7 +171,7 @@ void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
" for directory ", d);
return;
}
- t->AddLinkDirectory(d);
+ t->InsertLinkDirectory(d, mf->GetBacktrace());
}
void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs,
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index 15fbd40..873372f 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -101,6 +101,7 @@
# include "cmRemoveDefinitionsCommand.h"
# include "cmSourceGroupCommand.h"
# include "cmSubdirDependsCommand.h"
+# include "cmTargetLinkDirectoriesCommand.h"
# include "cmTargetLinkOptionsCommand.h"
# include "cmUseMangledMesaCommand.h"
# include "cmUtilitySourceCommand.h"
@@ -278,6 +279,8 @@ void GetProjectCommands(cmState* state)
state->AddBuiltinCommand("link_libraries", new cmLinkLibrariesCommand);
state->AddBuiltinCommand("target_link_options",
new cmTargetLinkOptionsCommand);
+ state->AddBuiltinCommand("target_link_directories",
+ new cmTargetLinkDirectoriesCommand);
state->AddBuiltinCommand("load_cache", new cmLoadCacheCommand);
state->AddBuiltinCommand("qt_wrap_cpp", new cmQTWrapCPPCommand);
state->AddBuiltinCommand("qt_wrap_ui", new cmQTWrapUICommand);
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index a3e135f..0e48ca8 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -357,10 +357,10 @@ cmComputeLinkInformation::cmComputeLinkInformation(
}
// Add the search path entries requested by the user to path ordering.
- this->OrderLinkerSearchPath->AddUserDirectories(
- this->Target->GetLinkDirectories());
- this->OrderRuntimeSearchPath->AddUserDirectories(
- this->Target->GetLinkDirectories());
+ std::vector<std::string> directories;
+ this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
+ this->OrderLinkerSearchPath->AddUserDirectories(directories);
+ this->OrderRuntimeSearchPath->AddUserDirectories(directories);
// Set up the implicit link directories.
this->LoadImplicitLinkInfo();
@@ -387,8 +387,7 @@ cmComputeLinkInformation::cmComputeLinkInformation(
if (this->OldLinkDirMode) {
// Construct a mask to not bother with this behavior for link
// directories already specified by the user.
- std::vector<std::string> const& dirs = this->Target->GetLinkDirectories();
- this->OldLinkDirMask.insert(dirs.begin(), dirs.end());
+ this->OldLinkDirMask.insert(directories.begin(), directories.end());
}
this->CMP0060Warn = this->Makefile->PolicyOptionalWarningEnabled(
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 7f42035..024e641 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -98,6 +98,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte,
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte,
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index d6573b8..4cf9dd7 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -451,6 +451,37 @@ void cmExportFileGenerator::PopulateLinkDependsInterface(
}
}
+void cmExportFileGenerator::PopulateLinkDirectoriesInterface(
+ cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget* gt = tei->Target;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ const char* propName = "INTERFACE_LINK_DIRECTORIES";
+ const char* input = gt->GetProperty(propName);
+
+ if (!input) {
+ return;
+ }
+
+ if (!*input) {
+ properties[propName].clear();
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(input, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets);
+
+ if (!checkInterfaceDirs(prepro, gt, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
+ }
+}
+
void cmExportFileGenerator::PopulateInterfaceProperty(
const std::string& propName, cmGeneratorTarget* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index 6ca2e07..41c6538 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -147,6 +147,10 @@ protected:
cmTargetExport* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+ void PopulateLinkDirectoriesInterface(
+ cmTargetExport* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
void PopulateLinkDependsInterface(
cmTargetExport* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index bfb7a05..e444087 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -106,6 +106,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt,
cmGeneratorExpression::InstallInterface,
properties, missingTargets);
+ this->PopulateLinkDirectoriesInterface(
+ te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
this->PopulateLinkDependsInterface(
te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 658e9a7..2727d9a 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -168,7 +168,7 @@ static std::string stripAllGeneratorExpressions(const std::string& input)
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
- if (c[0] == '$' && c[1] == '<') {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;
@@ -243,7 +243,7 @@ static std::string stripExportInterface(
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
- if (c[0] == '$' && c[1] == '<') {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;
@@ -310,7 +310,7 @@ void cmGeneratorExpression::Split(const std::string& input,
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
- if (c[0] == '$' && c[1] == '<') {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 8176d5c..9c05f60 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -63,6 +63,15 @@ public:
static std::string StripEmptyListElements(const std::string& input);
+ static inline bool StartsWithGeneratorExpression(const std::string& input)
+ {
+ return input.length() >= 2 && input[0] == '$' && input[1] == '<';
+ }
+ static inline bool StartsWithGeneratorExpression(const char* input)
+ {
+ return input != nullptr && input[0] == '$' && input[1] == '<';
+ }
+
private:
cmListFileBacktrace Backtrace;
};
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index 8b1697b..a5134c3 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -28,6 +28,7 @@ class cmGeneratorTarget;
SELECT(F, EvaluatingSources, SOURCES) \
SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \
SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) \
+ SELECT(F, EvaluatingLinkDirectories, LINK_DIRECTORIES) \
SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS)
#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index a58d3cb..29c6058 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -103,6 +103,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
, DebugCompileFeaturesDone(false)
, DebugCompileDefinitionsDone(false)
, DebugLinkOptionsDone(false)
+ , DebugLinkDirectoriesDone(false)
, DebugSourcesDone(false)
, LinkImplementationLanguageIsContextDependent(true)
, UtilityItemsDone(false)
@@ -133,6 +134,10 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
t->GetLinkOptionsBacktraces(),
this->LinkOptionsEntries);
+ CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
+ t->GetLinkDirectoriesBacktraces(),
+ this->LinkDirectoriesEntries);
+
CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
t->GetSourceBacktraces(),
this->SourceEntries, true);
@@ -150,6 +155,7 @@ cmGeneratorTarget::~cmGeneratorTarget()
cmDeleteAll(this->CompileFeaturesEntries);
cmDeleteAll(this->CompileDefinitionsEntries);
cmDeleteAll(this->LinkOptionsEntries);
+ cmDeleteAll(this->LinkDirectoriesEntries);
cmDeleteAll(this->SourceEntries);
cmDeleteAll(this->LinkInformation);
}
@@ -1704,11 +1710,6 @@ cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
return this->Target->GetBacktrace();
}
-const std::vector<std::string>& cmGeneratorTarget::GetLinkDirectories() const
-{
- return this->Target->GetLinkDirectories();
-}
-
const std::set<std::string>& cmGeneratorTarget::GetUtilities() const
{
return this->Target->GetUtilities();
@@ -3068,6 +3069,126 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions(
}
namespace {
+void processLinkDirectories(
+ cmGeneratorTarget const* tgt,
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+ std::vector<std::string>& directories,
+ std::unordered_set<std::string>& uniqueDirectories,
+ cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+ bool debugDirectories, std::string const& language)
+{
+ for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
+ cmLinkImplItem const& item = entry->LinkImplItem;
+ std::string const& targetName = item.AsStr();
+
+ std::vector<std::string> entryDirectories;
+ cmSystemTools::ExpandListArgument(
+ entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
+ dagChecker, language),
+ entryDirectories);
+
+ std::string usedDirectories;
+ for (std::string& entryDirectory : entryDirectories) {
+ if (!cmSystemTools::FileIsFullPath(entryDirectory)) {
+ std::ostringstream e;
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ if (!targetName.empty()) {
+ /* clang-format off */
+ e << "Target \"" << targetName << "\" contains relative "
+ "path in its INTERFACE_LINK_DIRECTORIES:\n"
+ " \"" << entryDirectory << "\"";
+ /* clang-format on */
+ } else {
+ switch (tgt->GetPolicyStatusCMP0081()) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0081) << "\n";
+ messageType = cmake::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+ e << "Found relative path while evaluating link directories of "
+ "\""
+ << tgt->GetName() << "\":\n \"" << entryDirectory << "\"\n";
+ }
+ if (!noMessage) {
+ tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return;
+ }
+ }
+ }
+
+ // Sanitize the path the same way the link_directories command does
+ // in case projects set the LINK_DIRECTORIES property directly.
+ cmSystemTools::ConvertToUnixSlashes(entryDirectory);
+ if (uniqueDirectories.insert(entryDirectory).second) {
+ directories.push_back(entryDirectory);
+ if (debugDirectories) {
+ usedDirectories += " * " + entryDirectory + "\n";
+ }
+ }
+ }
+ if (!usedDirectories.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::LOG,
+ std::string("Used link directories for target ") + tgt->GetName() +
+ ":\n" + usedDirectories,
+ entry->ge->GetBacktrace());
+ }
+ }
+}
+}
+
+void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const
+{
+ std::unordered_set<std::string> uniqueDirectories;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
+ nullptr);
+
+ std::vector<std::string> debugProperties;
+ const char* debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp) {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugDirectories = !this->DebugLinkDirectoriesDone &&
+ std::find(debugProperties.begin(), debugProperties.end(),
+ "LINK_DIRECTORIES") != debugProperties.end();
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugLinkDirectoriesDone = true;
+ }
+
+ processLinkDirectories(this, this->LinkDirectoriesEntries, result,
+ uniqueDirectories, &dagChecker, config,
+ debugDirectories, language);
+
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>
+ linkInterfaceLinkDirectoriesEntries;
+
+ AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES",
+ linkInterfaceLinkDirectoriesEntries);
+
+ processLinkDirectories(this, linkInterfaceLinkDirectoriesEntries, result,
+ uniqueDirectories, &dagChecker, config,
+ debugDirectories, language);
+
+ cmDeleteAll(linkInterfaceLinkDirectoriesEntries);
+}
+
+namespace {
void processLinkDepends(
cmGeneratorTarget const* tgt,
const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 9d8c9f5..bfd95ac 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -273,8 +273,6 @@ public:
cmListFileBacktrace GetBacktrace() const;
- const std::vector<std::string>& GetLinkDirectories() const;
-
std::set<std::string> const& GetUtilities() const;
cmListFileBacktrace const* GetUtilityBacktrace(const std::string& u) const;
@@ -435,6 +433,10 @@ public:
const std::string& config,
const std::string& language) const;
+ void GetLinkDirectories(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+
void GetLinkDepends(std::vector<std::string>& result,
const std::string& config,
const std::string& language) const;
@@ -825,6 +827,7 @@ private:
std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
std::vector<TargetPropertyEntry*> LinkOptionsEntries;
+ std::vector<TargetPropertyEntry*> LinkDirectoriesEntries;
std::vector<TargetPropertyEntry*> SourceEntries;
mutable std::set<std::string> LinkImplicitNullProperties;
@@ -874,6 +877,7 @@ private:
mutable bool DebugCompileFeaturesDone;
mutable bool DebugCompileDefinitionsDone;
mutable bool DebugLinkOptionsDone;
+ mutable bool DebugLinkDirectoriesDone;
mutable bool DebugSourcesDone;
mutable bool LinkImplementationLanguageIsContextDependent;
mutable bool UtilityItemsDone;
diff --git a/Source/cmGlobalVisualStudio10Generator.cxx b/Source/cmGlobalVisualStudio10Generator.cxx
index 5ea323a..82fcaad 100644
--- a/Source/cmGlobalVisualStudio10Generator.cxx
+++ b/Source/cmGlobalVisualStudio10Generator.cxx
@@ -938,6 +938,7 @@ void cmGlobalVisualStudio10Generator::GenerateBuildCommand(
configArg += "Debug";
}
makeCommand.push_back(configArg);
+ makeCommand.push_back("/p:Platform=" + this->GetPlatformName());
makeCommand.push_back(std::string("/p:VisualStudioVersion=") +
this->GetIDEVersion());
diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx
index eaaf64d..caec67d 100644
--- a/Source/cmIncludeDirectoryCommand.cxx
+++ b/Source/cmIncludeDirectoryCommand.cxx
@@ -5,6 +5,7 @@
#include <algorithm>
#include <set>
+#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"
@@ -69,11 +70,6 @@ bool cmIncludeDirectoryCommand::InitialPass(
return true;
}
-static bool StartsWithGeneratorExpression(const std::string& input)
-{
- return input[0] == '$' && input[1] == '<';
-}
-
// do a lot of cleanup on the arguments because this is one place where folks
// sometimes take the output of a program and pass it directly into this
// command not thinking that a single argument could be filled with spaces
@@ -124,7 +120,7 @@ void cmIncludeDirectoryCommand::NormalizeInclude(std::string& inc)
cmSystemTools::ConvertToUnixSlashes(inc);
if (!cmSystemTools::FileIsFullPath(inc)) {
- if (!StartsWithGeneratorExpression(inc)) {
+ if (!cmGeneratorExpression::StartsWithGeneratorExpression(inc)) {
std::string tmp = this->Makefile->GetCurrentSourceDirectory();
tmp += "/";
tmp += inc;
diff --git a/Source/cmJsonObjectDictionary.h b/Source/cmJsonObjectDictionary.h
new file mode 100644
index 0000000..a4d41f3
--- /dev/null
+++ b/Source/cmJsonObjectDictionary.h
@@ -0,0 +1,46 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#pragma once
+
+#include <string>
+
+// Vocabulary:
+
+static const std::string kARTIFACTS_KEY = "artifacts";
+static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
+static const std::string kCOMPILE_FLAGS_KEY = "compileFlags";
+static const std::string kCONFIGURATIONS_KEY = "configurations";
+static const std::string kDEFINES_KEY = "defines";
+static const std::string kFILE_GROUPS_KEY = "fileGroups";
+static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath";
+static const std::string kFULL_NAME_KEY = "fullName";
+static const std::string kINCLUDE_PATH_KEY = "includePath";
+static const std::string kIS_CMAKE_KEY = "isCMake";
+static const std::string kIS_GENERATED_KEY = "isGenerated";
+static const std::string kIS_SYSTEM_KEY = "isSystem";
+static const std::string kIS_TEMPORARY_KEY = "isTemporary";
+static const std::string kKEY_KEY = "key";
+static const std::string kLANGUAGE_KEY = "language";
+static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage";
+static const std::string kLINK_FLAGS_KEY = "linkFlags";
+static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags";
+static const std::string kLINK_LIBRARIES_KEY = "linkLibraries";
+static const std::string kLINK_PATH_KEY = "linkPath";
+static const std::string kNAME_KEY = "name";
+static const std::string kPATH_KEY = "path";
+static const std::string kPROJECTS_KEY = "projects";
+static const std::string kPROPERTIES_KEY = "properties";
+static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
+static const std::string kSOURCES_KEY = "sources";
+static const std::string kSYSROOT_KEY = "sysroot";
+static const std::string kTARGETS_KEY = "targets";
+static const std::string kTYPE_KEY = "type";
+static const std::string kVALUE_KEY = "value";
+static const std::string kHAS_INSTALL_RULE = "hasInstallRule";
+static const std::string kINSTALL_PATHS = "installPaths";
+static const std::string kCTEST_NAME = "ctestName";
+static const std::string kCTEST_COMMAND = "ctestCommand";
+static const std::string kCTEST_INFO = "ctestInfo";
+static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion";
+static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided";
+static const std::string kIS_INTERFACE_SOURCES_KEY = "isInterfaceSources";
diff --git a/Source/cmJsonObjects.cxx b/Source/cmJsonObjects.cxx
new file mode 100644
index 0000000..a7db75f
--- /dev/null
+++ b/Source/cmJsonObjects.cxx
@@ -0,0 +1,823 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmJsonObjects.h" // IWYU pragma: keep
+
+#include "cmGeneratorExpression.h"
+#include "cmGeneratorTarget.h"
+#include "cmGlobalGenerator.h"
+#include "cmInstallGenerator.h"
+#include "cmInstallTargetGenerator.h"
+#include "cmJsonObjectDictionary.h"
+#include "cmJsonObjects.h"
+#include "cmLinkLineComputer.h"
+#include "cmLocalGenerator.h"
+#include "cmMakefile.h"
+#include "cmProperty.h"
+#include "cmSourceFile.h"
+#include "cmState.h"
+#include "cmStateDirectory.h"
+#include "cmStateSnapshot.h"
+#include "cmStateTypes.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmTest.h"
+#include "cmake.h"
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <functional>
+#include <limits>
+#include <map>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+namespace {
+
+std::vector<std::string> getConfigurations(const cmake* cm)
+{
+ std::vector<std::string> configurations;
+ auto makefiles = cm->GetGlobalGenerator()->GetMakefiles();
+ if (makefiles.empty()) {
+ return configurations;
+ }
+
+ makefiles[0]->GetConfigurations(configurations);
+ if (configurations.empty()) {
+ configurations.push_back("");
+ }
+ return configurations;
+}
+
+bool hasString(const Json::Value& v, const std::string& s)
+{
+ return !v.isNull() &&
+ std::any_of(v.begin(), v.end(),
+ [s](const Json::Value& i) { return i.asString() == s; });
+}
+
+template <class T>
+Json::Value fromStringList(const T& in)
+{
+ Json::Value result = Json::arrayValue;
+ for (std::string const& i : in) {
+ result.append(i);
+ }
+ return result;
+}
+
+} // namespace
+
+void cmGetCMakeInputs(const cmGlobalGenerator* gg,
+ const std::string& sourceDir,
+ const std::string& buildDir,
+ std::vector<std::string>* internalFiles,
+ std::vector<std::string>* explicitFiles,
+ std::vector<std::string>* tmpFiles)
+{
+ const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/';
+ std::vector<cmMakefile*> const& makefiles = gg->GetMakefiles();
+ for (cmMakefile const* mf : makefiles) {
+ for (std::string const& lf : mf->GetListFiles()) {
+
+ const std::string startOfFile = lf.substr(0, cmakeRootDir.size());
+ const bool isInternal = (startOfFile == cmakeRootDir);
+ const bool isTemporary = !isInternal && (lf.find(buildDir + '/') == 0);
+
+ std::string toAdd = lf;
+ if (!sourceDir.empty()) {
+ const std::string& relative =
+ cmSystemTools::RelativePath(sourceDir, lf);
+ if (toAdd.size() > relative.size()) {
+ toAdd = relative;
+ }
+ }
+
+ if (isInternal) {
+ if (internalFiles) {
+ internalFiles->push_back(std::move(toAdd));
+ }
+ } else {
+ if (isTemporary) {
+ if (tmpFiles) {
+ tmpFiles->push_back(std::move(toAdd));
+ }
+ } else {
+ if (explicitFiles) {
+ explicitFiles->push_back(std::move(toAdd));
+ }
+ }
+ }
+ }
+ }
+}
+
+Json::Value cmDumpCMakeInputs(const cmake* cm)
+{
+ const cmGlobalGenerator* gg = cm->GetGlobalGenerator();
+ const std::string& buildDir = cm->GetHomeOutputDirectory();
+ const std::string& sourceDir = cm->GetHomeDirectory();
+
+ std::vector<std::string> internalFiles;
+ std::vector<std::string> explicitFiles;
+ std::vector<std::string> tmpFiles;
+ cmGetCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles,
+ &tmpFiles);
+
+ Json::Value array = Json::arrayValue;
+
+ Json::Value tmp = Json::objectValue;
+ tmp[kIS_CMAKE_KEY] = true;
+ tmp[kIS_TEMPORARY_KEY] = false;
+ tmp[kSOURCES_KEY] = fromStringList(internalFiles);
+ array.append(tmp);
+
+ tmp = Json::objectValue;
+ tmp[kIS_CMAKE_KEY] = false;
+ tmp[kIS_TEMPORARY_KEY] = false;
+ tmp[kSOURCES_KEY] = fromStringList(explicitFiles);
+ array.append(tmp);
+
+ tmp = Json::objectValue;
+ tmp[kIS_CMAKE_KEY] = false;
+ tmp[kIS_TEMPORARY_KEY] = true;
+ tmp[kSOURCES_KEY] = fromStringList(tmpFiles);
+ array.append(tmp);
+
+ return array;
+}
+
+const std::string kInterfaceSourcesLanguageDataKey =
+ "INTERFACE_SOURCES_LD_KEY";
+class LanguageData
+{
+public:
+ bool operator==(const LanguageData& other) const;
+
+ void SetDefines(const std::set<std::string>& defines);
+
+ bool IsGenerated = false;
+ std::string Language;
+ std::string Flags;
+ std::vector<std::string> Defines;
+ std::vector<std::pair<std::string, bool>> IncludePathList;
+};
+
+bool LanguageData::operator==(const LanguageData& other) const
+{
+ return Language == other.Language && Defines == other.Defines &&
+ Flags == other.Flags && IncludePathList == other.IncludePathList &&
+ IsGenerated == other.IsGenerated;
+}
+
+void LanguageData::SetDefines(const std::set<std::string>& defines)
+{
+ std::vector<std::string> result;
+ result.reserve(defines.size());
+ for (std::string const& i : defines) {
+ result.push_back(i);
+ }
+ std::sort(result.begin(), result.end());
+ Defines = std::move(result);
+}
+
+struct FileGroupSources
+{
+ bool IsInterfaceSources;
+ std::vector<std::string> Files;
+};
+
+namespace std {
+
+template <>
+struct hash<LanguageData>
+{
+ std::size_t operator()(const LanguageData& in) const
+ {
+ using std::hash;
+ size_t result =
+ hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags);
+ for (auto const& i : in.IncludePathList) {
+ result = result ^
+ (hash<std::string>()(i.first) ^
+ (i.second ? std::numeric_limits<size_t>::max() : 0));
+ }
+ for (auto const& i : in.Defines) {
+ result = result ^ hash<std::string>()(i);
+ }
+ result =
+ result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0);
+ return result;
+ }
+};
+
+} // namespace std
+
+static Json::Value DumpSourceFileGroup(const LanguageData& data,
+ bool isInterfaceSource,
+ const std::vector<std::string>& files,
+ const std::string& baseDir)
+{
+ Json::Value result = Json::objectValue;
+
+ if (isInterfaceSource) {
+ result[kIS_INTERFACE_SOURCES_KEY] = true;
+ }
+ if (!data.Language.empty()) {
+ result[kLANGUAGE_KEY] = data.Language;
+ }
+ if (!data.Flags.empty()) {
+ result[kCOMPILE_FLAGS_KEY] = data.Flags;
+ }
+ if (!data.IncludePathList.empty()) {
+ Json::Value includes = Json::arrayValue;
+ for (auto const& i : data.IncludePathList) {
+ Json::Value tmp = Json::objectValue;
+ tmp[kPATH_KEY] = i.first;
+ if (i.second) {
+ tmp[kIS_SYSTEM_KEY] = i.second;
+ }
+ includes.append(tmp);
+ }
+ result[kINCLUDE_PATH_KEY] = includes;
+ }
+ if (!data.Defines.empty()) {
+ result[kDEFINES_KEY] = fromStringList(data.Defines);
+ }
+
+ result[kIS_GENERATED_KEY] = data.IsGenerated;
+
+ Json::Value sourcesValue = Json::arrayValue;
+ for (auto const& i : files) {
+ const std::string relPath = cmSystemTools::RelativePath(baseDir, i);
+ sourcesValue.append(relPath.size() < i.size() ? relPath : i);
+ }
+
+ result[kSOURCES_KEY] = sourcesValue;
+ return result;
+}
+
+static void PopulateFileGroupData(
+ cmGeneratorTarget* target, bool isInterfaceSources,
+ const std::vector<cmSourceFile*>& files, const std::string& config,
+ const std::map<std::string, LanguageData>& languageDataMap,
+ std::unordered_map<LanguageData, FileGroupSources>& fileGroups)
+{
+ for (cmSourceFile* file : files) {
+ LanguageData fileData;
+ fileData.Language = file->GetLanguage();
+ if (!fileData.Language.empty() || isInterfaceSources) {
+ const LanguageData& ld = isInterfaceSources
+ ? languageDataMap.at(kInterfaceSourcesLanguageDataKey)
+ : languageDataMap.at(fileData.Language);
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
+ fileData.Language);
+
+ std::string compileFlags = ld.Flags;
+ const std::string COMPILE_FLAGS("COMPILE_FLAGS");
+ if (const char* cflags = file->GetProperty(COMPILE_FLAGS)) {
+ lg->AppendFlags(compileFlags,
+ genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
+ }
+ const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
+ if (const char* coptions = file->GetProperty(COMPILE_OPTIONS)) {
+ lg->AppendCompileOptions(
+ compileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
+ }
+ fileData.Flags = compileFlags;
+
+ // Add include directories from source file properties.
+ std::vector<std::string> includes;
+
+ const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
+ if (const char* cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) {
+ const std::string& evaluatedIncludes =
+ genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES);
+ lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file);
+
+ for (const auto& include : includes) {
+ // INTERFACE_LIBRARY targets do not support the
+ // IsSystemIncludeDirectory call so just set it to false.
+ const bool isSystemInclude = isInterfaceSources
+ ? false
+ : target->IsSystemIncludeDirectory(include, config,
+ fileData.Language);
+ fileData.IncludePathList.push_back(
+ std::make_pair(include, isSystemInclude));
+ }
+ }
+
+ fileData.IncludePathList.insert(fileData.IncludePathList.end(),
+ ld.IncludePathList.begin(),
+ ld.IncludePathList.end());
+
+ const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
+ std::set<std::string> defines;
+ if (const char* defs = file->GetProperty(COMPILE_DEFINITIONS)) {
+ lg->AppendDefines(
+ defines, genexInterpreter.Evaluate(defs, COMPILE_DEFINITIONS));
+ }
+
+ const std::string defPropName =
+ "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
+ if (const char* config_defs = file->GetProperty(defPropName)) {
+ lg->AppendDefines(
+ defines,
+ genexInterpreter.Evaluate(config_defs, COMPILE_DEFINITIONS));
+ }
+
+ defines.insert(ld.Defines.begin(), ld.Defines.end());
+
+ fileData.SetDefines(defines);
+ }
+
+ fileData.IsGenerated = file->GetPropertyAsBool("GENERATED");
+ FileGroupSources& groupFileList = fileGroups[fileData];
+ groupFileList.IsInterfaceSources = isInterfaceSources;
+ groupFileList.Files.push_back(file->GetFullPath());
+ }
+}
+
+static Json::Value DumpSourceFilesList(
+ cmGeneratorTarget* target, const std::string& config,
+ const std::map<std::string, LanguageData>& languageDataMap)
+{
+ const cmStateEnums::TargetType type = target->GetType();
+ std::unordered_map<LanguageData, FileGroupSources> fileGroups;
+
+ // Collect sourcefile groups:
+
+ std::vector<cmSourceFile*> files;
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ // INTERFACE_LIBRARY targets do not create all the data structures
+ // associated with regular targets. If properties are explicitly specified
+ // for files in INTERFACE_SOURCES then we can get them through the Makefile
+ // rather than the target.
+ files = target->Makefile->GetSourceFiles();
+ } else {
+ target->GetSourceFiles(files, config);
+ PopulateFileGroupData(target, false /* isInterfaceSources */, files,
+ config, languageDataMap, fileGroups);
+ }
+
+ // Collect interface sourcefile groups:
+
+ auto targetProp = target->Target->GetProperty("INTERFACE_SOURCES");
+ if (targetProp != nullptr) {
+ cmGeneratorExpressionInterpreter genexInterpreter(
+ target->GetLocalGenerator(), config, target);
+
+ auto evaluatedSources = cmsys::SystemTools::SplitString(
+ genexInterpreter.Evaluate(targetProp, "INTERFACE_SOURCES"), ';');
+
+ std::map<std::string, cmSourceFile*> filesMap;
+ for (auto file : files) {
+ filesMap[file->GetFullPath()] = file;
+ }
+
+ std::vector<cmSourceFile*> interfaceSourceFiles;
+ for (const std::string& interfaceSourceFilePath : evaluatedSources) {
+ auto entry = filesMap.find(interfaceSourceFilePath);
+ if (entry != filesMap.end()) {
+ // use what we have since it has all the associated properties
+ interfaceSourceFiles.push_back(entry->second);
+ } else {
+ interfaceSourceFiles.push_back(
+ new cmSourceFile(target->Makefile, interfaceSourceFilePath));
+ }
+ }
+
+ PopulateFileGroupData(target, true /* isInterfaceSources */,
+ interfaceSourceFiles, config, languageDataMap,
+ fileGroups);
+ }
+
+ const std::string& baseDir = target->Makefile->GetCurrentSourceDirectory();
+ Json::Value result = Json::arrayValue;
+ for (auto const& it : fileGroups) {
+ Json::Value group = DumpSourceFileGroup(
+ it.first, it.second.IsInterfaceSources, it.second.Files, baseDir);
+ if (!group.isNull()) {
+ result.append(group);
+ }
+ }
+
+ return result;
+}
+
+static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo,
+ const std::string& config)
+{
+ Json::Value result = Json::objectValue;
+ result[kCTEST_NAME] = testInfo->GetName();
+
+ // Concat command entries together. After the first should be the arguments
+ // for the command
+ std::string command;
+ for (auto const& cmd : testInfo->GetCommand()) {
+ command.append(cmd);
+ command.append(" ");
+ }
+
+ // Remove any config specific variables from the output.
+ cmGeneratorExpression ge;
+ auto cge = ge.Parse(command);
+ const std::string& processed = cge->Evaluate(lg, config);
+ result[kCTEST_COMMAND] = processed;
+
+ // Build up the list of properties that may have been specified
+ Json::Value properties = Json::arrayValue;
+ for (auto& prop : testInfo->GetProperties()) {
+ Json::Value entry = Json::objectValue;
+ entry[kKEY_KEY] = prop.first;
+
+ // Remove config variables from the value too.
+ auto cge_value = ge.Parse(prop.second.GetValue());
+ const std::string& processed_value = cge_value->Evaluate(lg, config);
+ entry[kVALUE_KEY] = processed_value;
+ properties.append(entry);
+ }
+ result[kPROPERTIES_KEY] = properties;
+
+ return result;
+}
+
+static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config,
+ Json::Value* result)
+{
+ auto mf = lg->GetMakefile();
+ std::vector<cmTest*> tests;
+ mf->GetTests(config, tests);
+ for (auto test : tests) {
+ Json::Value tmp = DumpCTestInfo(lg, test, config);
+ if (!tmp.isNull()) {
+ result->append(tmp);
+ }
+ }
+}
+
+static Json::Value DumpCTestProjectList(const cmake* cm,
+ std::string const& config)
+{
+ Json::Value result = Json::arrayValue;
+
+ auto globalGen = cm->GetGlobalGenerator();
+
+ for (const auto& projectIt : globalGen->GetProjectMap()) {
+ Json::Value pObj = Json::objectValue;
+ pObj[kNAME_KEY] = projectIt.first;
+
+ Json::Value tests = Json::arrayValue;
+
+ // Gather tests for every generator
+ for (const auto& lg : projectIt.second) {
+ // Make sure they're generated.
+ lg->GenerateTestFiles();
+ DumpMakefileTests(lg, config, &tests);
+ }
+
+ pObj[kCTEST_INFO] = tests;
+
+ result.append(pObj);
+ }
+
+ return result;
+}
+
+static Json::Value DumpCTestConfiguration(const cmake* cm,
+ const std::string& config)
+{
+ Json::Value result = Json::objectValue;
+ result[kNAME_KEY] = config;
+
+ result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config);
+
+ return result;
+}
+
+static Json::Value DumpCTestConfigurationsList(const cmake* cm)
+{
+ Json::Value result = Json::arrayValue;
+
+ for (const std::string& c : getConfigurations(cm)) {
+ result.append(DumpCTestConfiguration(cm, c));
+ }
+
+ return result;
+}
+
+Json::Value cmDumpCTestInfo(const cmake* cm)
+{
+ Json::Value result = Json::objectValue;
+ result[kCONFIGURATIONS_KEY] = DumpCTestConfigurationsList(cm);
+ return result;
+}
+
+static void GetTargetProperty(
+ cmGeneratorExpressionInterpreter& genexInterpreter,
+ cmGeneratorTarget* target, const char* propertyName,
+ std::vector<std::string>& propertyValue)
+{
+ auto targetProp = target->Target->GetProperty(propertyName);
+ if (targetProp != nullptr) {
+ propertyValue = cmsys::SystemTools::SplitString(
+ genexInterpreter.Evaluate(targetProp, propertyName), ';');
+ }
+}
+
+static void CreateInterfaceSourcesEntry(
+ cmLocalGenerator* lg, cmGeneratorTarget* target, const std::string& config,
+ std::map<std::string, LanguageData>& languageDataMap)
+{
+ LanguageData& ld = languageDataMap[kInterfaceSourcesLanguageDataKey];
+ ld.Language = "";
+
+ cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target);
+ std::vector<std::string> propertyValue;
+ GetTargetProperty(genexInterpreter, target, "INTERFACE_INCLUDE_DIRECTORIES",
+ propertyValue);
+ for (std::string const& i : propertyValue) {
+ ld.IncludePathList.push_back(
+ std::make_pair(i, false /* isSystemInclude */));
+ }
+
+ propertyValue.clear();
+ GetTargetProperty(genexInterpreter, target,
+ "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", propertyValue);
+ for (std::string const& i : propertyValue) {
+ ld.IncludePathList.push_back(
+ std::make_pair(i, true /* isSystemInclude */));
+ }
+
+ propertyValue.clear();
+ GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_OPTIONS",
+ propertyValue);
+ for (const auto& s : propertyValue) {
+ ld.Flags += " " + s;
+ }
+
+ propertyValue.clear();
+ GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_DEFINITIONS",
+ propertyValue);
+ if (!propertyValue.empty()) {
+ std::set<std::string> defines(propertyValue.begin(), propertyValue.end());
+ ld.SetDefines(defines);
+ }
+}
+
+static Json::Value DumpTarget(cmGeneratorTarget* target,
+ const std::string& config)
+{
+ cmLocalGenerator* lg = target->GetLocalGenerator();
+ const cmState* state = lg->GetState();
+
+ const cmStateEnums::TargetType type = target->GetType();
+ const std::string typeName = state->GetTargetTypeName(type);
+
+ Json::Value ttl = Json::arrayValue;
+ ttl.append("EXECUTABLE");
+ ttl.append("STATIC_LIBRARY");
+ ttl.append("SHARED_LIBRARY");
+ ttl.append("MODULE_LIBRARY");
+ ttl.append("OBJECT_LIBRARY");
+ ttl.append("UTILITY");
+ ttl.append("INTERFACE_LIBRARY");
+
+ if (!hasString(ttl, typeName) || target->IsImported()) {
+ return Json::Value();
+ }
+
+ Json::Value result = Json::objectValue;
+ result[kNAME_KEY] = target->GetName();
+ result[kIS_GENERATOR_PROVIDED_KEY] =
+ target->Target->GetIsGeneratorProvided();
+ result[kTYPE_KEY] = typeName;
+ result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory();
+ result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory();
+ result[kFULL_NAME_KEY] = target->GetFullName(config);
+
+ if (target->Target->GetHaveInstallRule()) {
+ result[kHAS_INSTALL_RULE] = true;
+
+ Json::Value installPaths = Json::arrayValue;
+ auto targetGenerators = target->Makefile->GetInstallGenerators();
+ for (auto installGenerator : targetGenerators) {
+ auto installTargetGenerator =
+ dynamic_cast<cmInstallTargetGenerator*>(installGenerator);
+ if (installTargetGenerator != nullptr &&
+ installTargetGenerator->GetTarget()->Target == target->Target) {
+ auto dest = installTargetGenerator->GetDestination(config);
+
+ std::string installPath;
+ if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) {
+ installPath = dest;
+ } else {
+ std::string installPrefix =
+ target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
+ installPath = installPrefix + '/' + dest;
+ }
+
+ installPaths.append(installPath);
+ }
+ }
+
+ result[kINSTALL_PATHS] = installPaths;
+ }
+
+ if (target->HaveWellDefinedOutputFiles()) {
+ Json::Value artifacts = Json::arrayValue;
+ artifacts.append(
+ target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact));
+ if (target->IsDLLPlatform()) {
+ artifacts.append(
+ target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
+ const cmGeneratorTarget::OutputInfo* output =
+ target->GetOutputInfo(config);
+ if (output && !output->PdbDir.empty()) {
+ artifacts.append(output->PdbDir + '/' + target->GetPDBName(config));
+ }
+ }
+ result[kARTIFACTS_KEY] = artifacts;
+
+ result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config);
+
+ std::string linkLibs;
+ std::string linkFlags;
+ std::string linkLanguageFlags;
+ std::string frameworkPath;
+ std::string linkPath;
+ cmLinkLineComputer linkLineComputer(lg,
+ lg->GetStateSnapshot().GetDirectory());
+ lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags,
+ linkFlags, frameworkPath, linkPath, target);
+
+ linkLibs = cmSystemTools::TrimWhitespace(linkLibs);
+ linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
+ linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags);
+ frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath);
+ linkPath = cmSystemTools::TrimWhitespace(linkPath);
+
+ if (!cmSystemTools::TrimWhitespace(linkLibs).empty()) {
+ result[kLINK_LIBRARIES_KEY] = linkLibs;
+ }
+ if (!cmSystemTools::TrimWhitespace(linkFlags).empty()) {
+ result[kLINK_FLAGS_KEY] = linkFlags;
+ }
+ if (!cmSystemTools::TrimWhitespace(linkLanguageFlags).empty()) {
+ result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags;
+ }
+ if (!frameworkPath.empty()) {
+ result[kFRAMEWORK_PATH_KEY] = frameworkPath;
+ }
+ if (!linkPath.empty()) {
+ result[kLINK_PATH_KEY] = linkPath;
+ }
+ const std::string sysroot =
+ lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT");
+ if (!sysroot.empty()) {
+ result[kSYSROOT_KEY] = sysroot;
+ }
+ }
+
+ std::set<std::string> languages;
+ std::map<std::string, LanguageData> languageDataMap;
+ if (type == cmStateEnums::INTERFACE_LIBRARY) {
+ // INTERFACE_LIBRARY targets do not create all the data structures
+ // associated with regular targets. If properties are explicitly specified
+ // for files in INTERFACE_SOURCES then we can get them through the Makefile
+ // rather than the target.
+ for (auto file : target->Makefile->GetSourceFiles()) {
+ const std::string& language = file->GetLanguage();
+ if (!language.empty()) {
+ languages.insert(language);
+ }
+ }
+ } else {
+ target->GetLanguages(languages, config);
+ }
+
+ for (std::string const& lang : languages) {
+ LanguageData& ld = languageDataMap[lang];
+ ld.Language = lang;
+ lg->GetTargetCompileFlags(target, config, lang, ld.Flags);
+ std::set<std::string> defines;
+ lg->GetTargetDefines(target, config, lang, defines);
+ ld.SetDefines(defines);
+ std::vector<std::string> includePathList;
+ lg->GetIncludeDirectories(includePathList, target, lang, config, true);
+ for (std::string const& i : includePathList) {
+ ld.IncludePathList.push_back(
+ std::make_pair(i, target->IsSystemIncludeDirectory(i, config, lang)));
+ }
+ }
+
+ if (target->Target->GetProperty("INTERFACE_SOURCES") != nullptr) {
+ // Create an entry in the languageDataMap for interface sources.
+ CreateInterfaceSourcesEntry(lg, target, config, languageDataMap);
+ }
+
+ Json::Value sourceGroupsValue =
+ DumpSourceFilesList(target, config, languageDataMap);
+ if (!sourceGroupsValue.empty()) {
+ result[kFILE_GROUPS_KEY] = sourceGroupsValue;
+ }
+
+ return result;
+}
+
+static Json::Value DumpTargetsList(
+ const std::vector<cmLocalGenerator*>& generators, const std::string& config)
+{
+ Json::Value result = Json::arrayValue;
+
+ std::vector<cmGeneratorTarget*> targetList;
+ for (auto const& lgIt : generators) {
+ const auto& list = lgIt->GetGeneratorTargets();
+ targetList.insert(targetList.end(), list.begin(), list.end());
+ }
+ std::sort(targetList.begin(), targetList.end());
+
+ for (cmGeneratorTarget* target : targetList) {
+ Json::Value tmp = DumpTarget(target, config);
+ if (!tmp.isNull()) {
+ result.append(tmp);
+ }
+ }
+
+ return result;
+}
+
+static Json::Value DumpProjectList(const cmake* cm, std::string const& config)
+{
+ Json::Value result = Json::arrayValue;
+
+ auto globalGen = cm->GetGlobalGenerator();
+
+ for (auto const& projectIt : globalGen->GetProjectMap()) {
+ Json::Value pObj = Json::objectValue;
+ pObj[kNAME_KEY] = projectIt.first;
+
+ // All Projects must have at least one local generator
+ assert(!projectIt.second.empty());
+ const cmLocalGenerator* lg = projectIt.second.at(0);
+
+ // Project structure information:
+ const cmMakefile* mf = lg->GetMakefile();
+ auto minVersion = mf->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
+ pObj[kMINIMUM_CMAKE_VERSION] = minVersion ? minVersion : "";
+ pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory();
+ pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory();
+ pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config);
+
+ // For a project-level install rule it might be defined in any of its
+ // associated generators.
+ bool hasInstallRule = false;
+ for (const auto generator : projectIt.second) {
+ hasInstallRule =
+ generator->GetMakefile()->GetInstallGenerators().empty() == false;
+
+ if (hasInstallRule) {
+ break;
+ }
+ }
+
+ pObj[kHAS_INSTALL_RULE] = hasInstallRule;
+
+ result.append(pObj);
+ }
+
+ return result;
+}
+
+static Json::Value DumpConfiguration(const cmake* cm,
+ const std::string& config)
+{
+ Json::Value result = Json::objectValue;
+ result[kNAME_KEY] = config;
+
+ result[kPROJECTS_KEY] = DumpProjectList(cm, config);
+
+ return result;
+}
+
+static Json::Value DumpConfigurationsList(const cmake* cm)
+{
+ Json::Value result = Json::arrayValue;
+
+ for (std::string const& c : getConfigurations(cm)) {
+ result.append(DumpConfiguration(cm, c));
+ }
+
+ return result;
+}
+
+Json::Value cmDumpCodeModel(const cmake* cm)
+{
+ Json::Value result = Json::objectValue;
+ result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(cm);
+ return result;
+}
diff --git a/Source/cmJsonObjects.h b/Source/cmJsonObjects.h
new file mode 100644
index 0000000..cd4da94
--- /dev/null
+++ b/Source/cmJsonObjects.h
@@ -0,0 +1,27 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmJsonObjects_h
+#define cmJsonObjects_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include "cm_jsoncpp_value.h"
+
+#include <string>
+#include <vector>
+
+class cmake;
+class cmGlobalGenerator;
+
+extern void cmGetCMakeInputs(const cmGlobalGenerator* gg,
+ const std::string& sourceDir,
+ const std::string& buildDir,
+ std::vector<std::string>* internalFiles,
+ std::vector<std::string>* explicitFiles,
+ std::vector<std::string>* tmpFiles);
+
+extern Json::Value cmDumpCodeModel(const cmake* cm);
+extern Json::Value cmDumpCTestInfo(const cmake* cm);
+extern Json::Value cmDumpCMakeInputs(const cmake* cm);
+
+#endif
diff --git a/Source/cmLinkDirectoriesCommand.cxx b/Source/cmLinkDirectoriesCommand.cxx
index 1371c53..10425fd 100644
--- a/Source/cmLinkDirectoriesCommand.cxx
+++ b/Source/cmLinkDirectoriesCommand.cxx
@@ -4,6 +4,8 @@
#include <sstream>
+#include "cmAlgorithms.h"
+#include "cmGeneratorExpression.h"
#include "cmMakefile.h"
#include "cmPolicies.h"
#include "cmSystemTools.h"
@@ -19,17 +21,34 @@ bool cmLinkDirectoriesCommand::InitialPass(
return true;
}
- for (std::string const& i : args) {
- this->AddLinkDir(i);
+ bool before = this->Makefile->IsOn("CMAKE_LINK_DIRECTORIES_BEFORE");
+
+ auto i = args.cbegin();
+ if ((*i) == "BEFORE") {
+ before = true;
+ ++i;
+ } else if ((*i) == "AFTER") {
+ before = false;
+ ++i;
+ }
+
+ std::vector<std::string> directories;
+ for (; i != args.cend(); ++i) {
+ this->AddLinkDir(*i, directories);
}
+
+ this->Makefile->AddLinkDirectory(cmJoin(directories, ";"), before);
+
return true;
}
-void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
+void cmLinkDirectoriesCommand::AddLinkDir(
+ std::string const& dir, std::vector<std::string>& directories)
{
std::string unixPath = dir;
cmSystemTools::ConvertToUnixSlashes(unixPath);
- if (!cmSystemTools::FileIsFullPath(unixPath)) {
+ if (!cmSystemTools::FileIsFullPath(unixPath) &&
+ !cmGeneratorExpression::StartsWithGeneratorExpression(unixPath)) {
bool convertToAbsolute = false;
std::ostringstream e;
/* clang-format off */
@@ -41,6 +60,7 @@ void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
case cmPolicies::WARN:
e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0015);
this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, e.str());
+ break;
case cmPolicies::OLD:
// OLD behavior does not convert
break;
@@ -61,5 +81,5 @@ void cmLinkDirectoriesCommand::AddLinkDir(std::string const& dir)
unixPath = tmp;
}
}
- this->Makefile->AppendProperty("LINK_DIRECTORIES", unixPath.c_str());
+ directories.push_back(unixPath);
}
diff --git a/Source/cmLinkDirectoriesCommand.h b/Source/cmLinkDirectoriesCommand.h
index 3fd4e50..ae4fb7f 100644
--- a/Source/cmLinkDirectoriesCommand.h
+++ b/Source/cmLinkDirectoriesCommand.h
@@ -36,7 +36,8 @@ public:
cmExecutionStatus& status) override;
private:
- void AddLinkDir(std::string const& dir);
+ void AddLinkDir(std::string const& dir,
+ std::vector<std::string>& directories);
};
#endif
diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx
index b468257..4d7e1e2 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -11,6 +11,7 @@
#include <algorithm>
#include <assert.h>
+#include <memory>
#include <sstream>
cmCommandContext::cmCommandName& cmCommandContext::cmCommandName::operator=(
@@ -285,91 +286,66 @@ bool cmListFileParser::AddArgument(cmListFileLexer_Token* token,
return true;
}
-struct cmListFileBacktrace::Entry : public cmListFileContext
+// We hold either the bottom scope of a directory or a call/file context.
+// Discriminate these cases via the parent pointer.
+struct cmListFileBacktrace::Entry
{
- Entry(cmListFileContext const& lfc, Entry* up)
- : cmListFileContext(lfc)
- , Up(up)
- , RefCount(0)
+ Entry(cmStateSnapshot bottom)
+ : Bottom(bottom)
{
- if (this->Up) {
- this->Up->Ref();
- }
}
- ~Entry()
+
+ Entry(std::shared_ptr<Entry const> parent, cmListFileContext lfc)
+ : Context(std::move(lfc))
+ , Parent(std::move(parent))
{
- if (this->Up) {
- this->Up->Unref();
- }
}
- void Ref() { ++this->RefCount; }
- void Unref()
+
+ ~Entry()
{
- if (--this->RefCount == 0) {
- delete this;
+ if (this->Parent) {
+ this->Context.~cmListFileContext();
+ } else {
+ this->Bottom.~cmStateSnapshot();
}
}
- Entry* Up;
- unsigned int RefCount;
-};
-cmListFileBacktrace::cmListFileBacktrace(cmStateSnapshot const& bottom,
- Entry* up,
- cmListFileContext const& lfc)
- : Bottom(bottom)
- , Cur(new Entry(lfc, up))
-{
- assert(this->Bottom.IsValid());
- this->Cur->Ref();
-}
-
-cmListFileBacktrace::cmListFileBacktrace(cmStateSnapshot const& bottom,
- Entry* cur)
- : Bottom(bottom)
- , Cur(cur)
-{
- if (this->Cur) {
- assert(this->Bottom.IsValid());
- this->Cur->Ref();
- }
-}
+ bool IsBottom() const { return !this->Parent; }
-cmListFileBacktrace::cmListFileBacktrace()
- : Bottom()
- , Cur(nullptr)
-{
-}
+ union
+ {
+ cmStateSnapshot Bottom;
+ cmListFileContext Context;
+ };
+ std::shared_ptr<Entry const> Parent;
+};
cmListFileBacktrace::cmListFileBacktrace(cmStateSnapshot const& snapshot)
- : Bottom(snapshot.GetCallStackBottom())
- , Cur(nullptr)
+ : TopEntry(std::make_shared<Entry const>(snapshot.GetCallStackBottom()))
{
}
-cmListFileBacktrace::cmListFileBacktrace(cmListFileBacktrace const& r)
- : Bottom(r.Bottom)
- , Cur(r.Cur)
+cmListFileBacktrace::cmListFileBacktrace(std::shared_ptr<Entry const> parent,
+ cmListFileContext const& lfc)
+ : TopEntry(std::make_shared<Entry const>(std::move(parent), lfc))
{
- if (this->Cur) {
- assert(this->Bottom.IsValid());
- this->Cur->Ref();
- }
}
-cmListFileBacktrace& cmListFileBacktrace::operator=(
- cmListFileBacktrace const& r)
+cmListFileBacktrace::cmListFileBacktrace(std::shared_ptr<Entry const> top)
+ : TopEntry(std::move(top))
{
- cmListFileBacktrace tmp(r);
- std::swap(this->Cur, tmp.Cur);
- std::swap(this->Bottom, tmp.Bottom);
- return *this;
}
-cmListFileBacktrace::~cmListFileBacktrace()
+cmStateSnapshot cmListFileBacktrace::GetBottom() const
{
- if (this->Cur) {
- this->Cur->Unref();
+ cmStateSnapshot bottom;
+ if (Entry const* cur = this->TopEntry.get()) {
+ while (Entry const* parent = cur->Parent.get()) {
+ cur = parent;
+ }
+ bottom = cur->Bottom;
}
+ return bottom;
}
cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const
@@ -380,54 +356,62 @@ cmListFileBacktrace cmListFileBacktrace::Push(std::string const& file) const
// skipped during call stack printing.
cmListFileContext lfc;
lfc.FilePath = file;
- return cmListFileBacktrace(this->Bottom, this->Cur, lfc);
+ return this->Push(lfc);
}
cmListFileBacktrace cmListFileBacktrace::Push(
cmListFileContext const& lfc) const
{
- return cmListFileBacktrace(this->Bottom, this->Cur, lfc);
+ assert(this->TopEntry);
+ assert(!this->TopEntry->IsBottom() || this->TopEntry->Bottom.IsValid());
+ return cmListFileBacktrace(this->TopEntry, lfc);
}
cmListFileBacktrace cmListFileBacktrace::Pop() const
{
- assert(this->Cur);
- return cmListFileBacktrace(this->Bottom, this->Cur->Up);
+ assert(this->TopEntry);
+ assert(!this->TopEntry->IsBottom());
+ return cmListFileBacktrace(this->TopEntry->Parent);
}
cmListFileContext const& cmListFileBacktrace::Top() const
{
- if (this->Cur) {
- return *this->Cur;
- }
- static cmListFileContext const empty;
- return empty;
+ assert(this->TopEntry);
+ assert(!this->TopEntry->IsBottom());
+ return this->TopEntry->Context;
}
void cmListFileBacktrace::PrintTitle(std::ostream& out) const
{
- if (!this->Cur) {
+ // The title exists only if we have a call on top of the bottom.
+ if (!this->TopEntry || this->TopEntry->IsBottom()) {
return;
}
- cmOutputConverter converter(this->Bottom);
- cmListFileContext lfc = *this->Cur;
- if (!this->Bottom.GetState()->GetIsInTryCompile()) {
+ cmListFileContext lfc = this->TopEntry->Context;
+ cmStateSnapshot bottom = this->GetBottom();
+ cmOutputConverter converter(bottom);
+ if (!bottom.GetState()->GetIsInTryCompile()) {
lfc.FilePath = converter.ConvertToRelativePath(
- this->Bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
+ bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
}
out << (lfc.Line ? " at " : " in ") << lfc;
}
void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
{
- if (!this->Cur || !this->Cur->Up) {
+ // The call stack exists only if we have at least two calls on top
+ // of the bottom.
+ if (!this->TopEntry || this->TopEntry->IsBottom() ||
+ this->TopEntry->Parent->IsBottom()) {
return;
}
bool first = true;
- cmOutputConverter converter(this->Bottom);
- for (Entry* i = this->Cur->Up; i; i = i->Up) {
- if (i->Name.empty()) {
+ cmStateSnapshot bottom = this->GetBottom();
+ cmOutputConverter converter(bottom);
+ for (Entry const* cur = this->TopEntry->Parent.get(); !cur->IsBottom();
+ cur = cur->Parent.get()) {
+ if (cur->Context.Name.empty()) {
// Skip this whole-file scope. When we get here we already will
// have printed a more-specific context within the file.
continue;
@@ -436,10 +420,10 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
first = false;
out << "Call Stack (most recent call first):\n";
}
- cmListFileContext lfc = *i;
- if (!this->Bottom.GetState()->GetIsInTryCompile()) {
+ cmListFileContext lfc = cur->Context;
+ if (!bottom.GetState()->GetIsInTryCompile()) {
lfc.FilePath = converter.ConvertToRelativePath(
- this->Bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
+ bottom.GetState()->GetSourceDirectory(), lfc.FilePath);
}
out << " " << lfc << "\n";
}
@@ -448,16 +432,19 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const
size_t cmListFileBacktrace::Depth() const
{
size_t depth = 0;
- if (this->Cur == nullptr) {
- return 0;
- }
-
- for (Entry* i = this->Cur->Up; i; i = i->Up) {
- depth++;
+ if (Entry const* cur = this->TopEntry.get()) {
+ for (; !cur->IsBottom(); cur = cur->Parent.get()) {
+ ++depth;
+ }
}
return depth;
}
+bool cmListFileBacktrace::Empty() const
+{
+ return !this->TopEntry || this->TopEntry->IsBottom();
+}
+
std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
{
os << lfc.FilePath;
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
index 70f7166..3d3afdf 100644
--- a/Source/cmListFileCache.h
+++ b/Source/cmListFileCache.h
@@ -6,6 +6,7 @@
#include "cmConfigure.h" // IWYU pragma: keep
#include <iosfwd>
+#include <memory> // IWYU pragma: keep
#include <stddef.h>
#include <string>
#include <vector>
@@ -115,18 +116,22 @@ public:
// Default-constructed backtrace may not be used until after
// set via assignment from a backtrace constructed with a
// valid snapshot.
- cmListFileBacktrace();
+ cmListFileBacktrace() = default;
// Construct an empty backtrace whose bottom sits in the directory
// indicated by the given valid snapshot.
cmListFileBacktrace(cmStateSnapshot const& snapshot);
- // Backtraces may be copied and assigned as values.
- cmListFileBacktrace(cmListFileBacktrace const& r);
- cmListFileBacktrace& operator=(cmListFileBacktrace const& r);
- ~cmListFileBacktrace();
+ // Backtraces may be copied, moved, and assigned as values.
+ cmListFileBacktrace(cmListFileBacktrace const&) = default;
+ cmListFileBacktrace(cmListFileBacktrace&&) // NOLINT(clang-tidy)
+ noexcept = default;
+ cmListFileBacktrace& operator=(cmListFileBacktrace const&) = default;
+ cmListFileBacktrace& operator=(cmListFileBacktrace&&) // NOLINT(clang-tidy)
+ noexcept = default;
+ ~cmListFileBacktrace() = default;
- cmStateSnapshot GetBottom() const { return this->Bottom; }
+ cmStateSnapshot GetBottom() const;
// Get a backtrace with the given file scope added to the top.
// May not be called until after construction with a valid snapshot.
@@ -141,7 +146,7 @@ public:
cmListFileBacktrace Pop() const;
// Get the context at the top of the backtrace.
- // Returns an empty context if the backtrace is empty.
+ // This may be called only if Empty() would return false.
cmListFileContext const& Top() const;
// Print the top of the backtrace.
@@ -153,14 +158,15 @@ public:
// Get the number of 'frames' in this backtrace
size_t Depth() const;
+ // Return true if this backtrace is empty.
+ bool Empty() const;
+
private:
struct Entry;
-
- cmStateSnapshot Bottom;
- Entry* Cur;
- cmListFileBacktrace(cmStateSnapshot const& bottom, Entry* up,
+ std::shared_ptr<Entry const> TopEntry;
+ cmListFileBacktrace(std::shared_ptr<Entry const> parent,
cmListFileContext const& lfc);
- cmListFileBacktrace(cmStateSnapshot const& bottom, Entry* cur);
+ cmListFileBacktrace(std::shared_ptr<Entry const> top);
};
struct cmListFile
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 354da4e..8d163b7 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -243,6 +243,17 @@ cmBacktraceRange cmMakefile::GetLinkOptionsBacktraces() const
return this->StateSnapshot.GetDirectory().GetLinkOptionsEntryBacktraces();
}
+cmStringRange cmMakefile::GetLinkDirectoriesEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetLinkDirectoriesEntries();
+}
+
+cmBacktraceRange cmMakefile::GetLinkDirectoriesBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory()
+ .GetLinkDirectoriesEntryBacktraces();
+}
+
cmListFileBacktrace cmMakefile::GetBacktrace() const
{
return this->Backtrace;
@@ -1237,6 +1248,18 @@ void cmMakefile::AddLinkOption(std::string const& option)
this->AppendProperty("LINK_OPTIONS", option.c_str());
}
+void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
+{
+ cmListFileBacktrace lfbt = this->GetBacktrace();
+ if (before) {
+ this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(directory,
+ lfbt);
+ } else {
+ this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(directory,
+ lfbt);
+ }
+}
+
bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
{
// Create a regular expression to match valid definitions.
@@ -1335,10 +1358,6 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent)
// link libraries
this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES"));
- // link directories
- this->SetProperty("LINK_DIRECTORIES",
- parent->GetProperty("LINK_DIRECTORIES"));
-
// the initial project name
this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
@@ -1872,17 +1891,6 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target)
return;
default:;
}
- if (const char* linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
- std::vector<std::string> linkDirs;
- cmSystemTools::ExpandListArgument(linkDirsProp, linkDirs);
-
- for (std::string& linkDir : linkDirs) {
- // Sanitize the path the same way the link_directories command does
- // in case projects set the LINK_DIRECTORIES property directly.
- cmSystemTools::ConvertToUnixSlashes(linkDir);
- target.AddLinkDirectory(linkDir);
- }
- }
if (const char* linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
std::vector<std::string> linkLibs;
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index bb01c0b..b30f281 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -182,6 +182,7 @@ public:
void AddCompileDefinition(std::string const& definition);
void AddCompileOption(std::string const& option);
void AddLinkOption(std::string const& option);
+ void AddLinkDirectory(std::string const& directory, bool before = false);
/** Create a new imported target with the name and type given. */
cmTarget* AddImportedTarget(const std::string& name,
@@ -802,6 +803,8 @@ public:
cmBacktraceRange GetCompileDefinitionsBacktraces() const;
cmStringRange GetLinkOptionsEntries() const;
cmBacktraceRange GetLinkOptionsBacktraces() const;
+ cmStringRange GetLinkDirectoriesEntries() const;
+ cmBacktraceRange GetLinkDirectoriesBacktraces() const;
std::set<std::string> const& GetSystemIncludeDirectories() const
{
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index f99cc0f..a367e47 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -237,7 +237,10 @@ class cmMakefile;
13, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0080, \
"BundleUtilities cannot be included at configure time", 3, 13, 0, \
- cmPolicies::WARN)
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0081, \
+ "Relative paths not allowed in LINK_DIRECTORIES target property.", \
+ 3, 13, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -263,7 +266,8 @@ class cmMakefile;
F(CMP0068) \
F(CMP0069) \
F(CMP0073) \
- F(CMP0076)
+ F(CMP0076) \
+ F(CMP0081)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies
diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx
index 1b04ca2..f15a14a 100644
--- a/Source/cmServer.cxx
+++ b/Source/cmServer.cxx
@@ -5,6 +5,7 @@
#include "cmAlgorithms.h"
#include "cmConnection.h"
#include "cmFileMonitor.h"
+#include "cmJsonObjectDictionary.h"
#include "cmServerDictionary.h"
#include "cmServerProtocol.h"
#include "cmSystemTools.h"
diff --git a/Source/cmServerDictionary.h b/Source/cmServerDictionary.h
index ebf16eb..961e4b7 100644
--- a/Source/cmServerDictionary.h
+++ b/Source/cmServerDictionary.h
@@ -25,78 +25,40 @@ static const std::string kSET_GLOBAL_SETTINGS_TYPE = "setGlobalSettings";
static const std::string kSIGNAL_TYPE = "signal";
static const std::string kCTEST_INFO_TYPE = "ctestInfo";
-static const std::string kARTIFACTS_KEY = "artifacts";
-static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory";
static const std::string kBUILD_FILES_KEY = "buildFiles";
static const std::string kCACHE_ARGUMENTS_KEY = "cacheArguments";
static const std::string kCACHE_KEY = "cache";
static const std::string kCAPABILITIES_KEY = "capabilities";
static const std::string kCHECK_SYSTEM_VARS_KEY = "checkSystemVars";
static const std::string kCMAKE_ROOT_DIRECTORY_KEY = "cmakeRootDirectory";
-static const std::string kCOMPILE_FLAGS_KEY = "compileFlags";
-static const std::string kCONFIGURATIONS_KEY = "configurations";
static const std::string kCOOKIE_KEY = "cookie";
static const std::string kDEBUG_OUTPUT_KEY = "debugOutput";
-static const std::string kDEFINES_KEY = "defines";
static const std::string kERROR_MESSAGE_KEY = "errorMessage";
static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator";
-static const std::string kFILE_GROUPS_KEY = "fileGroups";
-static const std::string kFRAMEWORK_PATH_KEY = "frameworkPath";
-static const std::string kFULL_NAME_KEY = "fullName";
static const std::string kGENERATOR_KEY = "generator";
-static const std::string kINCLUDE_PATH_KEY = "includePath";
-static const std::string kIS_CMAKE_KEY = "isCMake";
static const std::string kIS_EXPERIMENTAL_KEY = "isExperimental";
-static const std::string kIS_GENERATED_KEY = "isGenerated";
-static const std::string kIS_SYSTEM_KEY = "isSystem";
-static const std::string kIS_TEMPORARY_KEY = "isTemporary";
-static const std::string kKEY_KEY = "key";
static const std::string kKEYS_KEY = "keys";
-static const std::string kLANGUAGE_KEY = "language";
-static const std::string kLINKER_LANGUAGE_KEY = "linkerLanguage";
-static const std::string kLINK_FLAGS_KEY = "linkFlags";
-static const std::string kLINK_LANGUAGE_FLAGS_KEY = "linkLanguageFlags";
-static const std::string kLINK_LIBRARIES_KEY = "linkLibraries";
-static const std::string kLINK_PATH_KEY = "linkPath";
static const std::string kMAJOR_KEY = "major";
static const std::string kMESSAGE_KEY = "message";
static const std::string kMINOR_KEY = "minor";
-static const std::string kNAME_KEY = "name";
-static const std::string kPATH_KEY = "path";
static const std::string kPLATFORM_KEY = "platform";
static const std::string kPROGRESS_CURRENT_KEY = "progressCurrent";
static const std::string kPROGRESS_MAXIMUM_KEY = "progressMaximum";
static const std::string kPROGRESS_MESSAGE_KEY = "progressMessage";
static const std::string kPROGRESS_MINIMUM_KEY = "progressMinimum";
-static const std::string kPROJECTS_KEY = "projects";
-static const std::string kPROPERTIES_KEY = "properties";
static const std::string kPROTOCOL_VERSION_KEY = "protocolVersion";
static const std::string kREPLY_TO_KEY = "inReplyTo";
-static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory";
-static const std::string kSOURCES_KEY = "sources";
static const std::string kSUPPORTED_PROTOCOL_VERSIONS =
"supportedProtocolVersions";
-static const std::string kSYSROOT_KEY = "sysroot";
-static const std::string kTARGETS_KEY = "targets";
static const std::string kTITLE_KEY = "title";
static const std::string kTOOLSET_KEY = "toolset";
static const std::string kTRACE_EXPAND_KEY = "traceExpand";
static const std::string kTRACE_KEY = "trace";
-static const std::string kTYPE_KEY = "type";
-static const std::string kVALUE_KEY = "value";
static const std::string kWARN_UNINITIALIZED_KEY = "warnUninitialized";
static const std::string kWARN_UNUSED_CLI_KEY = "warnUnusedCli";
static const std::string kWARN_UNUSED_KEY = "warnUnused";
static const std::string kWATCHED_DIRECTORIES_KEY = "watchedDirectories";
static const std::string kWATCHED_FILES_KEY = "watchedFiles";
-static const std::string kHAS_INSTALL_RULE = "hasInstallRule";
-static const std::string kINSTALL_PATHS = "installPaths";
-static const std::string kCTEST_NAME = "ctestName";
-static const std::string kCTEST_COMMAND = "ctestCommand";
-static const std::string kCTEST_INFO = "ctestInfo";
-static const std::string kMINIMUM_CMAKE_VERSION = "minimumCMakeVersion";
-static const std::string kIS_GENERATOR_PROVIDED_KEY = "isGeneratorProvided";
-static const std::string kIS_INTERFACE_SOURCES_KEY = "isInterfaceSources";
static const std::string kSTART_MAGIC = "[== \"CMake Server\" ==[";
static const std::string kEND_MAGIC = "]== \"CMake Server\" ==]";
diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx
index 2cad657..f75a5ce 100644
--- a/Source/cmServerProtocol.cxx
+++ b/Source/cmServerProtocol.cxx
@@ -5,38 +5,21 @@
#include "cmAlgorithms.h"
#include "cmExternalMakefileProjectGenerator.h"
#include "cmFileMonitor.h"
-#include "cmGeneratorExpression.h"
-#include "cmGeneratorTarget.h"
#include "cmGlobalGenerator.h"
-#include "cmInstallGenerator.h"
-#include "cmInstallTargetGenerator.h"
-#include "cmLinkLineComputer.h"
-#include "cmLocalGenerator.h"
-#include "cmMakefile.h"
-#include "cmProperty.h"
+#include "cmJsonObjectDictionary.h"
+#include "cmJsonObjects.h"
#include "cmServer.h"
#include "cmServerDictionary.h"
-#include "cmSourceFile.h"
#include "cmState.h"
-#include "cmStateDirectory.h"
-#include "cmStateSnapshot.h"
-#include "cmStateTypes.h"
#include "cmSystemTools.h"
-#include "cmTarget.h"
-#include "cmTest.h"
#include "cm_uv.h"
#include "cmake.h"
#include <algorithm>
#include <cassert>
-#include <cstddef>
#include <functional>
-#include <limits>
-#include <map>
#include <memory>
-#include <set>
#include <string>
-#include <unordered_map>
#include <vector>
// Get rid of some windows macros:
@@ -44,38 +27,6 @@
namespace {
-std::vector<std::string> getConfigurations(const cmake* cm)
-{
- std::vector<std::string> configurations;
- auto makefiles = cm->GetGlobalGenerator()->GetMakefiles();
- if (makefiles.empty()) {
- return configurations;
- }
-
- makefiles[0]->GetConfigurations(configurations);
- if (configurations.empty()) {
- configurations.push_back("");
- }
- return configurations;
-}
-
-bool hasString(const Json::Value& v, const std::string& s)
-{
- return !v.isNull() &&
- std::any_of(v.begin(), v.end(),
- [s](const Json::Value& i) { return i.asString() == s; });
-}
-
-template <class T>
-Json::Value fromStringList(const T& in)
-{
- Json::Value result = Json::arrayValue;
- for (std::string const& i : in) {
- result.append(i);
- }
- return result;
-}
-
std::vector<std::string> toStringList(const Json::Value& in)
{
std::vector<std::string> result;
@@ -85,49 +36,6 @@ std::vector<std::string> toStringList(const Json::Value& in)
return result;
}
-void getCMakeInputs(const cmGlobalGenerator* gg, const std::string& sourceDir,
- const std::string& buildDir,
- std::vector<std::string>* internalFiles,
- std::vector<std::string>* explicitFiles,
- std::vector<std::string>* tmpFiles)
-{
- const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot() + '/';
- std::vector<cmMakefile*> const& makefiles = gg->GetMakefiles();
- for (cmMakefile const* mf : makefiles) {
- for (std::string const& lf : mf->GetListFiles()) {
-
- const std::string startOfFile = lf.substr(0, cmakeRootDir.size());
- const bool isInternal = (startOfFile == cmakeRootDir);
- const bool isTemporary = !isInternal && (lf.find(buildDir + '/') == 0);
-
- std::string toAdd = lf;
- if (!sourceDir.empty()) {
- const std::string& relative =
- cmSystemTools::RelativePath(sourceDir, lf);
- if (toAdd.size() > relative.size()) {
- toAdd = relative;
- }
- }
-
- if (isInternal) {
- if (internalFiles) {
- internalFiles->push_back(std::move(toAdd));
- }
- } else {
- if (isTemporary) {
- if (tmpFiles) {
- tmpFiles->push_back(std::move(toAdd));
- }
- } else {
- if (explicitFiles) {
- explicitFiles->push_back(std::move(toAdd));
- }
- }
- }
- }
- }
-}
-
} // namespace
cmServerRequest::cmServerRequest(cmServer* server, cmConnection* connection,
@@ -558,704 +466,16 @@ cmServerResponse cmServerProtocol1::ProcessCMakeInputs(
}
const cmake* cm = this->CMakeInstance();
- const cmGlobalGenerator* gg = cm->GetGlobalGenerator();
const std::string cmakeRootDir = cmSystemTools::GetCMakeRoot();
- const std::string& buildDir = cm->GetHomeOutputDirectory();
const std::string& sourceDir = cm->GetHomeDirectory();
Json::Value result = Json::objectValue;
result[kSOURCE_DIRECTORY_KEY] = sourceDir;
result[kCMAKE_ROOT_DIRECTORY_KEY] = cmakeRootDir;
-
- std::vector<std::string> internalFiles;
- std::vector<std::string> explicitFiles;
- std::vector<std::string> tmpFiles;
- getCMakeInputs(gg, sourceDir, buildDir, &internalFiles, &explicitFiles,
- &tmpFiles);
-
- Json::Value array = Json::arrayValue;
-
- Json::Value tmp = Json::objectValue;
- tmp[kIS_CMAKE_KEY] = true;
- tmp[kIS_TEMPORARY_KEY] = false;
- tmp[kSOURCES_KEY] = fromStringList(internalFiles);
- array.append(tmp);
-
- tmp = Json::objectValue;
- tmp[kIS_CMAKE_KEY] = false;
- tmp[kIS_TEMPORARY_KEY] = false;
- tmp[kSOURCES_KEY] = fromStringList(explicitFiles);
- array.append(tmp);
-
- tmp = Json::objectValue;
- tmp[kIS_CMAKE_KEY] = false;
- tmp[kIS_TEMPORARY_KEY] = true;
- tmp[kSOURCES_KEY] = fromStringList(tmpFiles);
- array.append(tmp);
-
- result[kBUILD_FILES_KEY] = array;
-
+ result[kBUILD_FILES_KEY] = cmDumpCMakeInputs(cm);
return request.Reply(result);
}
-const std::string kInterfaceSourcesLanguageDataKey =
- "INTERFACE_SOURCES_LD_KEY";
-class LanguageData
-{
-public:
- bool operator==(const LanguageData& other) const;
-
- void SetDefines(const std::set<std::string>& defines);
-
- bool IsGenerated = false;
- std::string Language;
- std::string Flags;
- std::vector<std::string> Defines;
- std::vector<std::pair<std::string, bool>> IncludePathList;
-};
-
-bool LanguageData::operator==(const LanguageData& other) const
-{
- return Language == other.Language && Defines == other.Defines &&
- Flags == other.Flags && IncludePathList == other.IncludePathList &&
- IsGenerated == other.IsGenerated;
-}
-
-void LanguageData::SetDefines(const std::set<std::string>& defines)
-{
- std::vector<std::string> result;
- result.reserve(defines.size());
- for (std::string const& i : defines) {
- result.push_back(i);
- }
- std::sort(result.begin(), result.end());
- Defines = std::move(result);
-}
-
-struct FileGroupSources
-{
- bool IsInterfaceSources;
- std::vector<std::string> Files;
-};
-
-namespace std {
-
-template <>
-struct hash<LanguageData>
-{
- std::size_t operator()(const LanguageData& in) const
- {
- using std::hash;
- size_t result =
- hash<std::string>()(in.Language) ^ hash<std::string>()(in.Flags);
- for (auto const& i : in.IncludePathList) {
- result = result ^
- (hash<std::string>()(i.first) ^
- (i.second ? std::numeric_limits<size_t>::max() : 0));
- }
- for (auto const& i : in.Defines) {
- result = result ^ hash<std::string>()(i);
- }
- result =
- result ^ (in.IsGenerated ? std::numeric_limits<size_t>::max() : 0);
- return result;
- }
-};
-
-} // namespace std
-
-static Json::Value DumpSourceFileGroup(const LanguageData& data,
- bool isInterfaceSource,
- const std::vector<std::string>& files,
- const std::string& baseDir)
-{
- Json::Value result = Json::objectValue;
-
- if (isInterfaceSource) {
- result[kIS_INTERFACE_SOURCES_KEY] = true;
- }
- if (!data.Language.empty()) {
- result[kLANGUAGE_KEY] = data.Language;
- }
- if (!data.Flags.empty()) {
- result[kCOMPILE_FLAGS_KEY] = data.Flags;
- }
- if (!data.IncludePathList.empty()) {
- Json::Value includes = Json::arrayValue;
- for (auto const& i : data.IncludePathList) {
- Json::Value tmp = Json::objectValue;
- tmp[kPATH_KEY] = i.first;
- if (i.second) {
- tmp[kIS_SYSTEM_KEY] = i.second;
- }
- includes.append(tmp);
- }
- result[kINCLUDE_PATH_KEY] = includes;
- }
- if (!data.Defines.empty()) {
- result[kDEFINES_KEY] = fromStringList(data.Defines);
- }
-
- result[kIS_GENERATED_KEY] = data.IsGenerated;
-
- Json::Value sourcesValue = Json::arrayValue;
- for (auto const& i : files) {
- const std::string relPath = cmSystemTools::RelativePath(baseDir, i);
- sourcesValue.append(relPath.size() < i.size() ? relPath : i);
- }
-
- result[kSOURCES_KEY] = sourcesValue;
- return result;
-}
-
-static void PopulateFileGroupData(
- cmGeneratorTarget* target, bool isInterfaceSources,
- const std::vector<cmSourceFile*>& files, const std::string& config,
- const std::map<std::string, LanguageData>& languageDataMap,
- std::unordered_map<LanguageData, FileGroupSources>& fileGroups)
-{
- for (cmSourceFile* file : files) {
- LanguageData fileData;
- fileData.Language = file->GetLanguage();
- if (!fileData.Language.empty() || isInterfaceSources) {
- const LanguageData& ld = isInterfaceSources
- ? languageDataMap.at(kInterfaceSourcesLanguageDataKey)
- : languageDataMap.at(fileData.Language);
- cmLocalGenerator* lg = target->GetLocalGenerator();
- cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target,
- fileData.Language);
-
- std::string compileFlags = ld.Flags;
- const std::string COMPILE_FLAGS("COMPILE_FLAGS");
- if (const char* cflags = file->GetProperty(COMPILE_FLAGS)) {
- lg->AppendFlags(compileFlags,
- genexInterpreter.Evaluate(cflags, COMPILE_FLAGS));
- }
- const std::string COMPILE_OPTIONS("COMPILE_OPTIONS");
- if (const char* coptions = file->GetProperty(COMPILE_OPTIONS)) {
- lg->AppendCompileOptions(
- compileFlags, genexInterpreter.Evaluate(coptions, COMPILE_OPTIONS));
- }
- fileData.Flags = compileFlags;
-
- // Add include directories from source file properties.
- std::vector<std::string> includes;
-
- const std::string INCLUDE_DIRECTORIES("INCLUDE_DIRECTORIES");
- if (const char* cincludes = file->GetProperty(INCLUDE_DIRECTORIES)) {
- const std::string& evaluatedIncludes =
- genexInterpreter.Evaluate(cincludes, INCLUDE_DIRECTORIES);
- lg->AppendIncludeDirectories(includes, evaluatedIncludes, *file);
-
- for (const auto& include : includes) {
- // INTERFACE_LIBRARY targets do not support the
- // IsSystemIncludeDirectory call so just set it to false.
- const bool isSystemInclude = isInterfaceSources
- ? false
- : target->IsSystemIncludeDirectory(include, config,
- fileData.Language);
- fileData.IncludePathList.push_back(
- std::make_pair(include, isSystemInclude));
- }
- }
-
- fileData.IncludePathList.insert(fileData.IncludePathList.end(),
- ld.IncludePathList.begin(),
- ld.IncludePathList.end());
-
- const std::string COMPILE_DEFINITIONS("COMPILE_DEFINITIONS");
- std::set<std::string> defines;
- if (const char* defs = file->GetProperty(COMPILE_DEFINITIONS)) {
- lg->AppendDefines(
- defines, genexInterpreter.Evaluate(defs, COMPILE_DEFINITIONS));
- }
-
- const std::string defPropName =
- "COMPILE_DEFINITIONS_" + cmSystemTools::UpperCase(config);
- if (const char* config_defs = file->GetProperty(defPropName)) {
- lg->AppendDefines(
- defines,
- genexInterpreter.Evaluate(config_defs, COMPILE_DEFINITIONS));
- }
-
- defines.insert(ld.Defines.begin(), ld.Defines.end());
-
- fileData.SetDefines(defines);
- }
-
- fileData.IsGenerated = file->GetPropertyAsBool("GENERATED");
- FileGroupSources& groupFileList = fileGroups[fileData];
- groupFileList.IsInterfaceSources = isInterfaceSources;
- groupFileList.Files.push_back(file->GetFullPath());
- }
-}
-
-static Json::Value DumpSourceFilesList(
- cmGeneratorTarget* target, const std::string& config,
- const std::map<std::string, LanguageData>& languageDataMap)
-{
- const cmStateEnums::TargetType type = target->GetType();
- std::unordered_map<LanguageData, FileGroupSources> fileGroups;
-
- // Collect sourcefile groups:
-
- std::vector<cmSourceFile*> files;
- if (type == cmStateEnums::INTERFACE_LIBRARY) {
- // INTERFACE_LIBRARY targets do not create all the data structures
- // associated with regular targets. If properties are explicitly specified
- // for files in INTERFACE_SOURCES then we can get them through the Makefile
- // rather than the target.
- files = target->Makefile->GetSourceFiles();
- } else {
- target->GetSourceFiles(files, config);
- PopulateFileGroupData(target, false /* isInterfaceSources */, files,
- config, languageDataMap, fileGroups);
- }
-
- // Collect interface sourcefile groups:
-
- auto targetProp = target->Target->GetProperty("INTERFACE_SOURCES");
- if (targetProp != nullptr) {
- cmGeneratorExpressionInterpreter genexInterpreter(
- target->GetLocalGenerator(), config, target);
-
- auto evaluatedSources = cmsys::SystemTools::SplitString(
- genexInterpreter.Evaluate(targetProp, "INTERFACE_SOURCES"), ';');
-
- std::map<std::string, cmSourceFile*> filesMap;
- for (auto file : files) {
- filesMap[file->GetFullPath()] = file;
- }
-
- std::vector<cmSourceFile*> interfaceSourceFiles;
- for (const std::string& interfaceSourceFilePath : evaluatedSources) {
- auto entry = filesMap.find(interfaceSourceFilePath);
- if (entry != filesMap.end()) {
- // use what we have since it has all the associated properties
- interfaceSourceFiles.push_back(entry->second);
- } else {
- interfaceSourceFiles.push_back(
- new cmSourceFile(target->Makefile, interfaceSourceFilePath));
- }
- }
-
- PopulateFileGroupData(target, true /* isInterfaceSources */,
- interfaceSourceFiles, config, languageDataMap,
- fileGroups);
- }
-
- const std::string& baseDir = target->Makefile->GetCurrentSourceDirectory();
- Json::Value result = Json::arrayValue;
- for (auto const& it : fileGroups) {
- Json::Value group = DumpSourceFileGroup(
- it.first, it.second.IsInterfaceSources, it.second.Files, baseDir);
- if (!group.isNull()) {
- result.append(group);
- }
- }
-
- return result;
-}
-
-static Json::Value DumpCTestInfo(cmLocalGenerator* lg, cmTest* testInfo,
- const std::string& config)
-{
- Json::Value result = Json::objectValue;
- result[kCTEST_NAME] = testInfo->GetName();
-
- // Concat command entries together. After the first should be the arguments
- // for the command
- std::string command;
- for (auto const& cmd : testInfo->GetCommand()) {
- command.append(cmd);
- command.append(" ");
- }
-
- // Remove any config specific variables from the output.
- cmGeneratorExpression ge;
- auto cge = ge.Parse(command);
- const std::string& processed = cge->Evaluate(lg, config);
- result[kCTEST_COMMAND] = processed;
-
- // Build up the list of properties that may have been specified
- Json::Value properties = Json::arrayValue;
- for (auto& prop : testInfo->GetProperties()) {
- Json::Value entry = Json::objectValue;
- entry[kKEY_KEY] = prop.first;
-
- // Remove config variables from the value too.
- auto cge_value = ge.Parse(prop.second.GetValue());
- const std::string& processed_value = cge_value->Evaluate(lg, config);
- entry[kVALUE_KEY] = processed_value;
- properties.append(entry);
- }
- result[kPROPERTIES_KEY] = properties;
-
- return result;
-}
-
-static void DumpMakefileTests(cmLocalGenerator* lg, const std::string& config,
- Json::Value* result)
-{
- auto mf = lg->GetMakefile();
- std::vector<cmTest*> tests;
- mf->GetTests(config, tests);
- for (auto test : tests) {
- Json::Value tmp = DumpCTestInfo(lg, test, config);
- if (!tmp.isNull()) {
- result->append(tmp);
- }
- }
-}
-
-static Json::Value DumpCTestProjectList(const cmake* cm,
- std::string const& config)
-{
- Json::Value result = Json::arrayValue;
-
- auto globalGen = cm->GetGlobalGenerator();
-
- for (const auto& projectIt : globalGen->GetProjectMap()) {
- Json::Value pObj = Json::objectValue;
- pObj[kNAME_KEY] = projectIt.first;
-
- Json::Value tests = Json::arrayValue;
-
- // Gather tests for every generator
- for (const auto& lg : projectIt.second) {
- // Make sure they're generated.
- lg->GenerateTestFiles();
- DumpMakefileTests(lg, config, &tests);
- }
-
- pObj[kCTEST_INFO] = tests;
-
- result.append(pObj);
- }
-
- return result;
-}
-
-static Json::Value DumpCTestConfiguration(const cmake* cm,
- const std::string& config)
-{
- Json::Value result = Json::objectValue;
- result[kNAME_KEY] = config;
-
- result[kPROJECTS_KEY] = DumpCTestProjectList(cm, config);
-
- return result;
-}
-
-static Json::Value DumpCTestConfigurationsList(const cmake* cm)
-{
- Json::Value result = Json::arrayValue;
-
- for (const std::string& c : getConfigurations(cm)) {
- result.append(DumpCTestConfiguration(cm, c));
- }
-
- return result;
-}
-
-static void GetTargetProperty(
- cmGeneratorExpressionInterpreter& genexInterpreter,
- cmGeneratorTarget* target, const char* propertyName,
- std::vector<std::string>& propertyValue)
-{
- auto targetProp = target->Target->GetProperty(propertyName);
- if (targetProp != nullptr) {
- propertyValue = cmsys::SystemTools::SplitString(
- genexInterpreter.Evaluate(targetProp, propertyName), ';');
- }
-}
-
-static void CreateInterfaceSourcesEntry(
- cmLocalGenerator* lg, cmGeneratorTarget* target, const std::string& config,
- std::map<std::string, LanguageData>& languageDataMap)
-{
- LanguageData& ld = languageDataMap[kInterfaceSourcesLanguageDataKey];
- ld.Language = "";
-
- cmGeneratorExpressionInterpreter genexInterpreter(lg, config, target);
- std::vector<std::string> propertyValue;
- GetTargetProperty(genexInterpreter, target, "INTERFACE_INCLUDE_DIRECTORIES",
- propertyValue);
- for (std::string const& i : propertyValue) {
- ld.IncludePathList.push_back(
- std::make_pair(i, false /* isSystemInclude */));
- }
-
- propertyValue.clear();
- GetTargetProperty(genexInterpreter, target,
- "INTERFACE_SYSTEM_INCLUDE_DIRECTORIES", propertyValue);
- for (std::string const& i : propertyValue) {
- ld.IncludePathList.push_back(
- std::make_pair(i, true /* isSystemInclude */));
- }
-
- propertyValue.clear();
- GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_OPTIONS",
- propertyValue);
- for (const auto& s : propertyValue) {
- ld.Flags += " " + s;
- }
-
- propertyValue.clear();
- GetTargetProperty(genexInterpreter, target, "INTERFACE_COMPILE_DEFINITIONS",
- propertyValue);
- if (!propertyValue.empty()) {
- std::set<std::string> defines(propertyValue.begin(), propertyValue.end());
- ld.SetDefines(defines);
- }
-}
-
-static Json::Value DumpTarget(cmGeneratorTarget* target,
- const std::string& config)
-{
- cmLocalGenerator* lg = target->GetLocalGenerator();
- const cmState* state = lg->GetState();
-
- const cmStateEnums::TargetType type = target->GetType();
- const std::string typeName = state->GetTargetTypeName(type);
-
- Json::Value ttl = Json::arrayValue;
- ttl.append("EXECUTABLE");
- ttl.append("STATIC_LIBRARY");
- ttl.append("SHARED_LIBRARY");
- ttl.append("MODULE_LIBRARY");
- ttl.append("OBJECT_LIBRARY");
- ttl.append("UTILITY");
- ttl.append("INTERFACE_LIBRARY");
-
- if (!hasString(ttl, typeName) || target->IsImported()) {
- return Json::Value();
- }
-
- Json::Value result = Json::objectValue;
- result[kNAME_KEY] = target->GetName();
- result[kIS_GENERATOR_PROVIDED_KEY] =
- target->Target->GetIsGeneratorProvided();
- result[kTYPE_KEY] = typeName;
- result[kSOURCE_DIRECTORY_KEY] = lg->GetCurrentSourceDirectory();
- result[kBUILD_DIRECTORY_KEY] = lg->GetCurrentBinaryDirectory();
- result[kFULL_NAME_KEY] = target->GetFullName(config);
-
- if (target->Target->GetHaveInstallRule()) {
- result[kHAS_INSTALL_RULE] = true;
-
- Json::Value installPaths = Json::arrayValue;
- auto targetGenerators = target->Makefile->GetInstallGenerators();
- for (auto installGenerator : targetGenerators) {
- auto installTargetGenerator =
- dynamic_cast<cmInstallTargetGenerator*>(installGenerator);
- if (installTargetGenerator != nullptr &&
- installTargetGenerator->GetTarget()->Target == target->Target) {
- auto dest = installTargetGenerator->GetDestination(config);
-
- std::string installPath;
- if (!dest.empty() && cmSystemTools::FileIsFullPath(dest)) {
- installPath = dest;
- } else {
- std::string installPrefix =
- target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX");
- installPath = installPrefix + '/' + dest;
- }
-
- installPaths.append(installPath);
- }
- }
-
- result[kINSTALL_PATHS] = installPaths;
- }
-
- if (target->HaveWellDefinedOutputFiles()) {
- Json::Value artifacts = Json::arrayValue;
- artifacts.append(
- target->GetFullPath(config, cmStateEnums::RuntimeBinaryArtifact));
- if (target->IsDLLPlatform()) {
- artifacts.append(
- target->GetFullPath(config, cmStateEnums::ImportLibraryArtifact));
- const cmGeneratorTarget::OutputInfo* output =
- target->GetOutputInfo(config);
- if (output && !output->PdbDir.empty()) {
- artifacts.append(output->PdbDir + '/' + target->GetPDBName(config));
- }
- }
- result[kARTIFACTS_KEY] = artifacts;
-
- result[kLINKER_LANGUAGE_KEY] = target->GetLinkerLanguage(config);
-
- std::string linkLibs;
- std::string linkFlags;
- std::string linkLanguageFlags;
- std::string frameworkPath;
- std::string linkPath;
- cmLinkLineComputer linkLineComputer(lg,
- lg->GetStateSnapshot().GetDirectory());
- lg->GetTargetFlags(&linkLineComputer, config, linkLibs, linkLanguageFlags,
- linkFlags, frameworkPath, linkPath, target);
-
- linkLibs = cmSystemTools::TrimWhitespace(linkLibs);
- linkFlags = cmSystemTools::TrimWhitespace(linkFlags);
- linkLanguageFlags = cmSystemTools::TrimWhitespace(linkLanguageFlags);
- frameworkPath = cmSystemTools::TrimWhitespace(frameworkPath);
- linkPath = cmSystemTools::TrimWhitespace(linkPath);
-
- if (!cmSystemTools::TrimWhitespace(linkLibs).empty()) {
- result[kLINK_LIBRARIES_KEY] = linkLibs;
- }
- if (!cmSystemTools::TrimWhitespace(linkFlags).empty()) {
- result[kLINK_FLAGS_KEY] = linkFlags;
- }
- if (!cmSystemTools::TrimWhitespace(linkLanguageFlags).empty()) {
- result[kLINK_LANGUAGE_FLAGS_KEY] = linkLanguageFlags;
- }
- if (!frameworkPath.empty()) {
- result[kFRAMEWORK_PATH_KEY] = frameworkPath;
- }
- if (!linkPath.empty()) {
- result[kLINK_PATH_KEY] = linkPath;
- }
- const std::string sysroot =
- lg->GetMakefile()->GetSafeDefinition("CMAKE_SYSROOT");
- if (!sysroot.empty()) {
- result[kSYSROOT_KEY] = sysroot;
- }
- }
-
- std::set<std::string> languages;
- std::map<std::string, LanguageData> languageDataMap;
- if (type == cmStateEnums::INTERFACE_LIBRARY) {
- // INTERFACE_LIBRARY targets do not create all the data structures
- // associated with regular targets. If properties are explicitly specified
- // for files in INTERFACE_SOURCES then we can get them through the Makefile
- // rather than the target.
- for (auto file : target->Makefile->GetSourceFiles()) {
- const std::string& language = file->GetLanguage();
- if (!language.empty()) {
- languages.insert(language);
- }
- }
- } else {
- target->GetLanguages(languages, config);
- }
-
- for (std::string const& lang : languages) {
- LanguageData& ld = languageDataMap[lang];
- ld.Language = lang;
- lg->GetTargetCompileFlags(target, config, lang, ld.Flags);
- std::set<std::string> defines;
- lg->GetTargetDefines(target, config, lang, defines);
- ld.SetDefines(defines);
- std::vector<std::string> includePathList;
- lg->GetIncludeDirectories(includePathList, target, lang, config, true);
- for (std::string const& i : includePathList) {
- ld.IncludePathList.push_back(
- std::make_pair(i, target->IsSystemIncludeDirectory(i, config, lang)));
- }
- }
-
- if (target->Target->GetProperty("INTERFACE_SOURCES") != nullptr) {
- // Create an entry in the languageDataMap for interface sources.
- CreateInterfaceSourcesEntry(lg, target, config, languageDataMap);
- }
-
- Json::Value sourceGroupsValue =
- DumpSourceFilesList(target, config, languageDataMap);
- if (!sourceGroupsValue.empty()) {
- result[kFILE_GROUPS_KEY] = sourceGroupsValue;
- }
-
- return result;
-}
-
-static Json::Value DumpTargetsList(
- const std::vector<cmLocalGenerator*>& generators, const std::string& config)
-{
- Json::Value result = Json::arrayValue;
-
- std::vector<cmGeneratorTarget*> targetList;
- for (auto const& lgIt : generators) {
- const auto& list = lgIt->GetGeneratorTargets();
- targetList.insert(targetList.end(), list.begin(), list.end());
- }
- std::sort(targetList.begin(), targetList.end());
-
- for (cmGeneratorTarget* target : targetList) {
- Json::Value tmp = DumpTarget(target, config);
- if (!tmp.isNull()) {
- result.append(tmp);
- }
- }
-
- return result;
-}
-
-static Json::Value DumpProjectList(const cmake* cm, std::string const& config)
-{
- Json::Value result = Json::arrayValue;
-
- auto globalGen = cm->GetGlobalGenerator();
-
- for (auto const& projectIt : globalGen->GetProjectMap()) {
- Json::Value pObj = Json::objectValue;
- pObj[kNAME_KEY] = projectIt.first;
-
- // All Projects must have at least one local generator
- assert(!projectIt.second.empty());
- const cmLocalGenerator* lg = projectIt.second.at(0);
-
- // Project structure information:
- const cmMakefile* mf = lg->GetMakefile();
- auto minVersion = mf->GetDefinition("CMAKE_MINIMUM_REQUIRED_VERSION");
- pObj[kMINIMUM_CMAKE_VERSION] = minVersion ? minVersion : "";
- pObj[kSOURCE_DIRECTORY_KEY] = mf->GetCurrentSourceDirectory();
- pObj[kBUILD_DIRECTORY_KEY] = mf->GetCurrentBinaryDirectory();
- pObj[kTARGETS_KEY] = DumpTargetsList(projectIt.second, config);
-
- // For a project-level install rule it might be defined in any of its
- // associated generators.
- bool hasInstallRule = false;
- for (const auto generator : projectIt.second) {
- hasInstallRule =
- generator->GetMakefile()->GetInstallGenerators().empty() == false;
-
- if (hasInstallRule) {
- break;
- }
- }
-
- pObj[kHAS_INSTALL_RULE] = hasInstallRule;
-
- result.append(pObj);
- }
-
- return result;
-}
-
-static Json::Value DumpConfiguration(const cmake* cm,
- const std::string& config)
-{
- Json::Value result = Json::objectValue;
- result[kNAME_KEY] = config;
-
- result[kPROJECTS_KEY] = DumpProjectList(cm, config);
-
- return result;
-}
-
-static Json::Value DumpConfigurationsList(const cmake* cm)
-{
- Json::Value result = Json::arrayValue;
-
- for (std::string const& c : getConfigurations(cm)) {
- result.append(DumpConfiguration(cm, c));
- }
-
- return result;
-}
-
cmServerResponse cmServerProtocol1::ProcessCodeModel(
const cmServerRequest& request)
{
@@ -1263,9 +483,7 @@ cmServerResponse cmServerProtocol1::ProcessCodeModel(
return request.ReportError("No build system was generated yet.");
}
- Json::Value result = Json::objectValue;
- result[kCONFIGURATIONS_KEY] = DumpConfigurationsList(this->CMakeInstance());
- return request.Reply(result);
+ return request.Reply(cmDumpCodeModel(this->CMakeInstance()));
}
cmServerResponse cmServerProtocol1::ProcessCompute(
@@ -1382,7 +600,8 @@ cmServerResponse cmServerProtocol1::ProcessConfigure(
}
std::vector<std::string> toWatchList;
- getCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList, nullptr);
+ cmGetCMakeInputs(gg, std::string(), buildDir, nullptr, &toWatchList,
+ nullptr);
FileMonitor()->MonitorPaths(toWatchList,
[this](const std::string& p, int e, int s) {
@@ -1488,10 +707,7 @@ cmServerResponse cmServerProtocol1::ProcessCTests(
return request.ReportError("This instance was not yet computed.");
}
- Json::Value result = Json::objectValue;
- result[kCONFIGURATIONS_KEY] =
- DumpCTestConfigurationsList(this->CMakeInstance());
- return request.Reply(result);
+ return request.Reply(cmDumpCTestInfo(this->CMakeInstance()));
}
cmServerProtocol1::GeneratorInformation::GeneratorInformation(
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index c6667f6..4b65cf1 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -284,6 +284,8 @@ cmStateSnapshot cmState::Reset()
it->CompileOptionsBacktraces.clear();
it->LinkOptions.clear();
it->LinkOptionsBacktraces.clear();
+ it->LinkDirectories.clear();
+ it->LinkDirectoriesBacktraces.clear();
it->DirectoryEnd = pos;
it->NormalTargetNames.clear();
it->Properties.clear();
@@ -660,6 +662,7 @@ cmStateSnapshot cmState::CreateBaseSnapshot()
pos->CompileDefinitionsPosition = 0;
pos->CompileOptionsPosition = 0;
pos->LinkOptionsPosition = 0;
+ pos->LinkDirectoriesPosition = 0;
pos->BuildSystemDirectory->DirectoryEnd = pos;
pos->Policies = this->PolicyStack.Root();
pos->PolicyRoot = this->PolicyStack.Root();
@@ -813,6 +816,8 @@ cmStateSnapshot cmState::Pop(cmStateSnapshot const& originSnapshot)
prevPos->BuildSystemDirectory->CompileOptions.size();
prevPos->LinkOptionsPosition =
prevPos->BuildSystemDirectory->LinkOptions.size();
+ prevPos->LinkDirectoriesPosition =
+ prevPos->BuildSystemDirectory->LinkDirectories.size();
prevPos->BuildSystemDirectory->DirectoryEnd = prevPos;
if (!pos->Keep && this->SnapshotData.IsLast(pos)) {
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 925b161..f94e714 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -396,6 +396,70 @@ void cmStateDirectory::ClearLinkOptions()
this->Snapshot_.Position->LinkOptionsPosition);
}
+cmStringRange cmStateDirectory::GetLinkDirectoriesEntries() const
+{
+ return GetPropertyContent(this->DirectoryState->LinkDirectories,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
+cmBacktraceRange cmStateDirectory::GetLinkDirectoriesEntryBacktraces() const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
+void cmStateDirectory::AppendLinkDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
+}
+void cmStateDirectory::PrependLinkDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ std::vector<std::string>::iterator entryEnd =
+ this->DirectoryState->LinkDirectories.begin() +
+ this->Snapshot_.Position->LinkDirectoriesPosition;
+
+ std::vector<std::string>::reverse_iterator rend =
+ this->DirectoryState->LinkDirectories.rend();
+ std::vector<std::string>::reverse_iterator rbegin =
+ cmMakeReverseIterator(entryEnd);
+ rbegin = std::find(rbegin, rend, cmPropertySentinal);
+
+ std::vector<std::string>::iterator entryIt = rbegin.base();
+ std::vector<std::string>::iterator entryBegin =
+ this->DirectoryState->LinkDirectories.begin();
+
+ std::vector<cmListFileBacktrace>::iterator btIt =
+ this->DirectoryState->LinkDirectoriesBacktraces.begin() +
+ std::distance(entryBegin, entryIt);
+
+ this->DirectoryState->LinkDirectories.insert(entryIt, vec);
+ this->DirectoryState->LinkDirectoriesBacktraces.insert(btIt, lfbt);
+
+ this->Snapshot_.Position->LinkDirectoriesPosition =
+ this->DirectoryState->LinkDirectories.size();
+}
+
+void cmStateDirectory::SetLinkDirectories(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
+}
+
+void cmStateDirectory::ClearLinkDirectories()
+{
+ ClearContent(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
cmListFileBacktrace const& lfbt)
{
@@ -431,6 +495,14 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
this->SetLinkOptions(value, lfbt);
return;
}
+ if (prop == "LINK_DIRECTORIES") {
+ if (!value) {
+ this->ClearLinkDirectories();
+ return;
+ }
+ this->SetLinkDirectories(value, lfbt);
+ return;
+ }
this->DirectoryState->Properties.SetProperty(prop, value);
}
@@ -455,6 +527,10 @@ void cmStateDirectory::AppendProperty(const std::string& prop,
this->AppendLinkOptionsEntry(value, lfbt);
return;
}
+ if (prop == "LINK_DIRECTORIES") {
+ this->AppendLinkDirectoriesEntry(value, lfbt);
+ return;
+ }
this->DirectoryState->Properties.AppendProperty(prop, value, asString);
}
@@ -542,6 +618,10 @@ const char* cmStateDirectory::GetProperty(const std::string& prop,
output = cmJoin(this->GetLinkOptionsEntries(), ";");
return output.c_str();
}
+ if (prop == "LINK_DIRECTORIES") {
+ output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
+ return output.c_str();
+ }
const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
if (!retVal && chain) {
diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h
index 412664f..e5f4d05 100644
--- a/Source/cmStateDirectory.h
+++ b/Source/cmStateDirectory.h
@@ -62,9 +62,19 @@ public:
cmBacktraceRange GetLinkOptionsEntryBacktraces() const;
void AppendLinkOptionsEntry(std::string const& vec,
cmListFileBacktrace const& lfbt);
+ void PrependLinkDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
void SetLinkOptions(std::string const& vec, cmListFileBacktrace const& lfbt);
void ClearLinkOptions();
+ cmStringRange GetLinkDirectoriesEntries() const;
+ cmBacktraceRange GetLinkDirectoriesEntryBacktraces() const;
+ void AppendLinkDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetLinkDirectories(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearLinkDirectories();
+
void SetProperty(const std::string& prop, const char* value,
cmListFileBacktrace const& lfbt);
void AppendProperty(const std::string& prop, const char* value,
diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h
index 7177221..e76f2af 100644
--- a/Source/cmStatePrivate.h
+++ b/Source/cmStatePrivate.h
@@ -43,6 +43,7 @@ struct cmStateDetail::SnapshotDataType
std::vector<std::string>::size_type CompileDefinitionsPosition;
std::vector<std::string>::size_type CompileOptionsPosition;
std::vector<std::string>::size_type LinkOptionsPosition;
+ std::vector<std::string>::size_type LinkDirectoriesPosition;
};
struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap
@@ -88,6 +89,9 @@ struct cmStateDetail::BuildsystemDirectoryStateType
std::vector<std::string> LinkOptions;
std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
+ std::vector<std::string> LinkDirectories;
+ std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
+
std::vector<std::string> NormalTargetNames;
std::string ProjectName;
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index 0379e7e..c2510f3 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -398,6 +398,13 @@ void cmStateSnapshot::InitializeFromParent()
this->Position->BuildSystemDirectory->LinkOptionsBacktraces,
this->Position->LinkOptionsPosition);
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->LinkDirectories,
+ this->Position->BuildSystemDirectory->LinkDirectories,
+ parent->BuildSystemDirectory->LinkDirectoriesBacktraces,
+ this->Position->BuildSystemDirectory->LinkDirectoriesBacktraces,
+ this->Position->LinkDirectoriesPosition);
+
const char* include_regex =
parent->BuildSystemDirectory->Properties.GetPropertyValue(
"INCLUDE_REGULAR_EXPRESSION");
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index a338fe3..f0d6519 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -168,6 +168,8 @@ public:
std::vector<cmListFileBacktrace> SourceBacktraces;
std::vector<std::string> LinkOptionsEntries;
std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
+ std::vector<std::string> LinkDirectoriesEntries;
+ std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
std::vector<std::string> LinkImplementationPropertyEntries;
std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
};
@@ -391,6 +393,18 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
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());
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -539,9 +553,7 @@ void cmTarget::AddSources(std::vector<std::string> const& srcs)
std::string srcFiles;
const char* sep = "";
for (auto filename : srcs) {
- const char* src = filename.c_str();
-
- if (!(src[0] == '$' && src[1] == '<')) {
+ if (!cmGeneratorExpression::StartsWithGeneratorExpression(filename)) {
if (!filename.empty()) {
filename = this->ProcessSourceItemCMP0049(filename);
if (filename.empty()) {
@@ -681,19 +693,6 @@ cmSourceFile* cmTarget::AddSource(const std::string& src)
cmSourceFileLocationKind::Known);
}
-void cmTarget::AddLinkDirectory(const std::string& d)
-{
- // Make sure we don't add unnecessary search directories.
- if (this->LinkDirectoriesEmmitted.insert(d).second) {
- this->LinkDirectories.push_back(d);
- }
-}
-
-const std::vector<std::string>& cmTarget::GetLinkDirectories() const
-{
- return this->LinkDirectories;
-}
-
void cmTarget::ClearDependencyInformation(cmMakefile& mf)
{
std::string depname = this->GetName();
@@ -901,6 +900,16 @@ cmBacktraceRange cmTarget::GetLinkOptionsBacktraces() const
return cmMakeRange(this->Internal->LinkOptionsBacktraces);
}
+cmStringRange cmTarget::GetLinkDirectoriesEntries() const
+{
+ return cmMakeRange(this->Internal->LinkDirectoriesEntries);
+}
+
+cmBacktraceRange cmTarget::GetLinkDirectoriesBacktraces() const
+{
+ return cmMakeRange(this->Internal->LinkDirectoriesBacktraces);
+}
+
cmStringRange cmTarget::GetLinkImplementationEntries() const
{
return cmMakeRange(this->Internal->LinkImplementationPropertyEntries);
@@ -927,6 +936,7 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
MAKE_STATIC_PROP(IMPORTED_GLOBAL);
MAKE_STATIC_PROP(INCLUDE_DIRECTORIES);
MAKE_STATIC_PROP(LINK_OPTIONS);
+ MAKE_STATIC_PROP(LINK_DIRECTORIES);
MAKE_STATIC_PROP(LINK_LIBRARIES);
MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
MAKE_STATIC_PROP(NAME);
@@ -1013,6 +1023,14 @@ void cmTarget::SetProperty(const std::string& prop, const char* value)
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
this->Internal->LinkOptionsBacktraces.push_back(lfbt);
}
+ } else if (prop == propLINK_DIRECTORIES) {
+ this->Internal->LinkDirectoriesEntries.clear();
+ this->Internal->LinkDirectoriesBacktraces.clear();
+ if (value) {
+ this->Internal->LinkDirectoriesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
+ }
} else if (prop == propLINK_LIBRARIES) {
this->Internal->LinkImplementationPropertyEntries.clear();
this->Internal->LinkImplementationPropertyBacktraces.clear();
@@ -1124,6 +1142,12 @@ void cmTarget::AppendProperty(const std::string& prop, const char* value,
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
this->Internal->LinkOptionsBacktraces.push_back(lfbt);
}
+ } else if (prop == "LINK_DIRECTORIES") {
+ if (value && *value) {
+ this->Internal->LinkDirectoriesEntries.push_back(value);
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+ this->Internal->LinkDirectoriesBacktraces.push_back(lfbt);
+ }
} else if (prop == "LINK_LIBRARIES") {
if (value && *value) {
cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
@@ -1221,6 +1245,21 @@ void cmTarget::InsertLinkOption(std::string const& entry,
this->Internal->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();
+
+ std::vector<cmListFileBacktrace>::iterator btPosition = before
+ ? this->Internal->LinkDirectoriesBacktraces.begin()
+ : this->Internal->LinkDirectoriesBacktraces.end();
+
+ this->Internal->LinkDirectoriesEntries.insert(position, entry);
+ this->Internal->LinkDirectoriesBacktraces.insert(btPosition, bt);
+}
+
static void cmTargetCheckLINK_INTERFACE_LIBRARIES(const std::string& prop,
const char* value,
cmMakefile* context,
@@ -1341,6 +1380,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const
MAKE_STATIC_PROP(COMPILE_OPTIONS);
MAKE_STATIC_PROP(COMPILE_DEFINITIONS);
MAKE_STATIC_PROP(LINK_OPTIONS);
+ MAKE_STATIC_PROP(LINK_DIRECTORIES);
MAKE_STATIC_PROP(IMPORTED);
MAKE_STATIC_PROP(IMPORTED_GLOBAL);
MAKE_STATIC_PROP(MANUALLY_ADDED_DEPENDENCIES);
@@ -1357,6 +1397,7 @@ const char* cmTarget::GetProperty(const std::string& prop) const
specialProps.insert(propCOMPILE_OPTIONS);
specialProps.insert(propCOMPILE_DEFINITIONS);
specialProps.insert(propLINK_OPTIONS);
+ specialProps.insert(propLINK_DIRECTORIES);
specialProps.insert(propIMPORTED);
specialProps.insert(propIMPORTED_GLOBAL);
specialProps.insert(propMANUALLY_ADDED_DEPENDENCIES);
@@ -1424,6 +1465,16 @@ const char* cmTarget::GetProperty(const std::string& prop) const
output = cmJoin(this->Internal->LinkOptionsEntries, ";");
return output.c_str();
}
+ if (prop == propLINK_DIRECTORIES) {
+ if (this->Internal->LinkDirectoriesEntries.empty()) {
+ return nullptr;
+ }
+
+ static std::string output;
+ output = cmJoin(this->Internal->LinkDirectoriesEntries, ";");
+
+ return output.c_str();
+ }
if (prop == propMANUALLY_ADDED_DEPENDENCIES) {
if (this->Utilities.empty()) {
return nullptr;
diff --git a/Source/cmTarget.h b/Source/cmTarget.h
index 1f380df..694de1c 100644
--- a/Source/cmTarget.h
+++ b/Source/cmTarget.h
@@ -154,10 +154,6 @@ public:
cmListFileContext const& lfc);
void GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const;
- const std::vector<std::string>& GetLinkDirectories() const;
-
- void AddLinkDirectory(const std::string& d);
-
/**
* Set the path where this target should be installed. This is relative to
* INSTALL_PREFIX
@@ -247,6 +243,8 @@ public:
cmListFileBacktrace const& bt);
void InsertLinkOption(std::string const& entry,
cmListFileBacktrace const& bt, bool before = false);
+ void InsertLinkDirectory(std::string const& entry,
+ cmListFileBacktrace const& bt, bool before = false);
void AppendBuildInterfaceIncludes();
@@ -277,6 +275,9 @@ public:
cmStringRange GetLinkOptionsEntries() const;
cmBacktraceRange GetLinkOptionsBacktraces() const;
+ cmStringRange GetLinkDirectoriesEntries() const;
+ cmBacktraceRange GetLinkDirectoriesBacktraces() const;
+
cmStringRange GetLinkImplementationEntries() const;
cmBacktraceRange GetLinkImplementationBacktraces() const;
@@ -306,14 +307,12 @@ private:
bool IsGeneratorProvided;
cmPropertyMap Properties;
std::set<std::string> SystemIncludeDirectories;
- std::set<std::string> LinkDirectoriesEmmitted;
std::set<std::string> Utilities;
std::map<std::string, cmListFileBacktrace> UtilityBacktraces;
cmPolicies::PolicyMap PolicyMap;
std::string Name;
std::string InstallPath;
std::string RuntimeInstallPath;
- std::vector<std::string> LinkDirectories;
std::vector<cmCustomCommand> PreBuildCommands;
std::vector<cmCustomCommand> PreLinkCommands;
std::vector<cmCustomCommand> PostBuildCommands;
diff --git a/Source/cmTargetLinkDirectoriesCommand.cxx b/Source/cmTargetLinkDirectoriesCommand.cxx
new file mode 100644
index 0000000..bca3e45
--- /dev/null
+++ b/Source/cmTargetLinkDirectoriesCommand.cxx
@@ -0,0 +1,61 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#include "cmTargetLinkDirectoriesCommand.h"
+
+#include <sstream>
+
+#include "cmAlgorithms.h"
+#include "cmGeneratorExpression.h"
+#include "cmListFileCache.h"
+#include "cmMakefile.h"
+#include "cmSystemTools.h"
+#include "cmTarget.h"
+#include "cmake.h"
+
+class cmExecutionStatus;
+
+bool cmTargetLinkDirectoriesCommand::InitialPass(
+ std::vector<std::string> const& args, cmExecutionStatus&)
+{
+ return this->HandleArguments(args, "LINK_DIRECTORIES", PROCESS_BEFORE);
+}
+
+void cmTargetLinkDirectoriesCommand::HandleMissingTarget(
+ const std::string& name)
+{
+ std::ostringstream e;
+ e << "Cannot specify link directories for target \"" << name
+ << "\" which is not built by this project.";
+ this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str());
+}
+
+std::string cmTargetLinkDirectoriesCommand::Join(
+ const std::vector<std::string>& content)
+{
+ std::vector<std::string> directories;
+
+ for (const auto& dir : content) {
+ auto unixPath = dir;
+ cmSystemTools::ConvertToUnixSlashes(unixPath);
+ if (!cmSystemTools::FileIsFullPath(unixPath) &&
+ !cmGeneratorExpression::StartsWithGeneratorExpression(unixPath)) {
+ auto tmp = this->Makefile->GetCurrentSourceDirectory();
+ tmp += "/";
+ tmp += unixPath;
+ unixPath = tmp;
+ }
+ directories.push_back(unixPath);
+ }
+
+ return cmJoin(directories, ";");
+}
+
+bool cmTargetLinkDirectoriesCommand::HandleDirectContent(
+ cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool)
+{
+ cmListFileBacktrace lfbt = this->Makefile->GetBacktrace();
+
+ tgt->InsertLinkDirectory(this->Join(content), lfbt, prepend);
+
+ return true; // Successfully handled.
+}
diff --git a/Source/cmTargetLinkDirectoriesCommand.h b/Source/cmTargetLinkDirectoriesCommand.h
new file mode 100644
index 0000000..52c75a0
--- /dev/null
+++ b/Source/cmTargetLinkDirectoriesCommand.h
@@ -0,0 +1,41 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmTargetLinkDirectoriesCommand_h
+#define cmTargetLinkDirectoriesCommand_h
+
+#include "cmConfigure.h" // IWYU pragma: keep
+
+#include <string>
+#include <vector>
+
+#include "cmTargetPropCommandBase.h"
+
+class cmCommand;
+class cmExecutionStatus;
+class cmTarget;
+
+class cmTargetLinkDirectoriesCommand : public cmTargetPropCommandBase
+{
+public:
+ /**
+ * This is a virtual constructor for the command.
+ */
+ cmCommand* Clone() override { return new cmTargetLinkDirectoriesCommand; }
+
+ /**
+ * This is called when the command is first encountered in
+ * the CMakeLists.txt file.
+ */
+ bool InitialPass(std::vector<std::string> const& args,
+ cmExecutionStatus& status) override;
+
+private:
+ void HandleMissingTarget(const std::string& name) override;
+
+ std::string Join(const std::vector<std::string>& content) override;
+ bool HandleDirectContent(cmTarget* tgt,
+ const std::vector<std::string>& content,
+ bool prepend, bool system) override;
+};
+
+#endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 6c14834..889a5fb 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -225,10 +225,8 @@ cmake::~cmake()
}
#if defined(CMAKE_BUILD_WITH_CMAKE)
-Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
+Json::Value cmake::ReportVersionJson() const
{
- Json::Value obj = Json::objectValue;
- // Version information:
Json::Value version = Json::objectValue;
version["string"] = CMake_VERSION;
version["major"] = CMake_VERSION_MAJOR;
@@ -236,8 +234,15 @@ Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
version["suffix"] = CMake_VERSION_SUFFIX;
version["isDirty"] = (CMake_VERSION_IS_DIRTY == 1);
version["patch"] = CMake_VERSION_PATCH;
+ return version;
+}
- obj["version"] = version;
+Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const
+{
+ Json::Value obj = Json::objectValue;
+
+ // Version information:
+ obj["version"] = this->ReportVersionJson();
// Generators:
std::vector<cmake::GeneratorInfo> generatorInfoList;
@@ -2462,6 +2467,14 @@ int cmake::Build(int jobs, const std::string& dir, const std::string& target,
return 1;
}
}
+ const char* cachedGeneratorPlatform =
+ this->State->GetCacheEntryValue("CMAKE_GENERATOR_PLATFORM");
+ if (cachedGeneratorPlatform) {
+ cmMakefile mf(gen, this->GetCurrentSnapshot());
+ if (!gen->SetGeneratorPlatform(cachedGeneratorPlatform, &mf)) {
+ return 1;
+ }
+ }
std::string output;
std::string projName;
const char* cachedProjectName =
diff --git a/Source/cmake.h b/Source/cmake.h
index f7dc3f7..d3d0e80 100644
--- a/Source/cmake.h
+++ b/Source/cmake.h
@@ -128,6 +128,7 @@ public:
~cmake();
#if defined(CMAKE_BUILD_WITH_CMAKE)
+ Json::Value ReportVersionJson() const;
Json::Value ReportCapabilitiesJson(bool haveServerMode) const;
#endif
std::string ReportCapabilities(bool haveServerMode) const;
diff --git a/Tests/CMakeCommands/link_directories/CMakeLists.txt b/Tests/CMakeCommands/link_directories/CMakeLists.txt
new file mode 100644
index 0000000..60c07b6
--- /dev/null
+++ b/Tests/CMakeCommands/link_directories/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.12)
+
+project(link_directories LANGUAGES C)
+
+
+link_directories(/A)
+link_directories(BEFORE /B)
+
+set(CMAKE_LINK_DIRECTORIES_BEFORE ON)
+link_directories(/C)
+
+get_directory_property(result LINK_DIRECTORIES)
+if (NOT result MATCHES "/C;/B;/A")
+ message(SEND_ERROR "link_directories not populated the LINK_DIRECTORIES directory property")
+endif()
+
+
+add_executable(link_directories EXCLUDE_FROM_ALL LinkDirectoriesExe.c)
+
+get_target_property(result link_directories LINK_DIRECTORIES)
+if (NOT result MATCHES "/C;/B;/A")
+ message(SEND_ERROR "link_directories not populated the LINK_DIRECTORIES target property")
+endif()
+
+
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(result imp LINK_DIRECTORIES)
+if (result)
+ message(FATAL_ERROR "link_directories populated the LINK_DIRECTORIES target property")
+endif()
diff --git a/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c b/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_directories/CMakeLists.txt b/Tests/CMakeCommands/target_link_directories/CMakeLists.txt
new file mode 100644
index 0000000..bc7b9b2
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/CMakeLists.txt
@@ -0,0 +1,40 @@
+
+cmake_minimum_required(VERSION 3.12)
+
+project(target_link_directories LANGUAGES C)
+
+add_library(target_link_directories SHARED LinkDirectoriesLib.c)
+# Test no items
+target_link_directories(target_link_directories PRIVATE)
+
+add_library(target_link_directories_2 SHARED EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_2 PRIVATE /private/dir INTERFACE /interface/dir)
+get_target_property(result target_link_directories_2 LINK_DIRECTORIES)
+if (NOT result MATCHES "/private/dir")
+ message(SEND_ERROR "${result} target_link_directories not populated the LINK_DIRECTORIES target property")
+endif()
+get_target_property(result target_link_directories_2 INTERFACE_LINK_DIRECTORIES)
+if (NOT result MATCHES "/interface/dir")
+ message(SEND_ERROR "target_link_directories not populated the INTERFACE_LINK_DIRECTORIES target property of shared library")
+endif()
+
+add_library(target_link_directories_3 STATIC EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_3 INTERFACE /interface/dir)
+get_target_property(result target_link_directories_3 INTERFACE_LINK_DIRECTORIES)
+if (NOT result MATCHES "/interface/dir")
+ message(SEND_ERROR "target_link_directories not populated the INTERFACE_LINK_DIRECTORIES target property of static library")
+endif()
+
+add_library(target_link_directories_4 SHARED EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_4 PRIVATE relative/dir)
+get_target_property(result target_link_directories_4 LINK_DIRECTORIES)
+if (NOT result MATCHES "${CMAKE_CURRENT_SOURCE_DIR}/relative/dir")
+ message(SEND_ERROR "target_link_directories not populated the LINK_DIRECTORIES with relative path")
+endif()
+
+add_subdirectory(subdir)
+target_link_directories(target_link_directories_5 PRIVATE relative/dir)
+get_target_property(result target_link_directories_5 LINK_DIRECTORIES)
+if (NOT result MATCHES "${CMAKE_CURRENT_SOURCE_DIR}/relative/dir")
+ message(SEND_ERROR "target_link_directories not populated the LINK_DIRECTORIES with relative path")
+endif()
diff --git a/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c b/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c
new file mode 100644
index 0000000..9bbd24c
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c
@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+ int flags_lib(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt b/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt
new file mode 100644
index 0000000..7e7ad2a
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_library(target_link_directories_5 SHARED EXCLUDE_FROM_ALL ../LinkDirectoriesLib.c)
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index fb44077..0de6c41 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -2128,12 +2128,13 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
get_filename_component(ntver "[HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion;CurrentVersion]" NAME)
if(WIN32 AND ntver VERSION_GREATER 6.1) # Windows >= 8.0
- macro(add_test_VSWinStorePhone name generator systemName systemVersion)
+ macro(add_test_VSWinStorePhone name generator systemName systemVersion architecture)
add_test(NAME VSWinStorePhone.${name} COMMAND ${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMake_SOURCE_DIR}/Tests/VSWinStorePhone"
"${CMake_BINARY_DIR}/Tests/VSWinStorePhone/${name}"
--build-generator "${generator}"
+ --build-generator-platform "${architecture}"
--build-project VSWinStorePhone
--build-config $<CONFIGURATION>
--build-options -DCMAKE_SYSTEM_NAME=${systemName}
@@ -2143,14 +2144,14 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
endmacro()
if(vs11 AND ws80)
- add_test_VSWinStorePhone(vs11-store80-X86 "Visual Studio 11 2012" WindowsStore 8.0)
- add_test_VSWinStorePhone(vs11-store80-ARM "Visual Studio 11 2012 ARM" WindowsStore 8.0)
- add_test_VSWinStorePhone(vs11-store80-X64 "Visual Studio 11 2012 Win64" WindowsStore 8.0)
+ add_test_VSWinStorePhone(vs11-store80-X86 "Visual Studio 11 2012" WindowsStore 8.0 Win32)
+ add_test_VSWinStorePhone(vs11-store80-ARM "Visual Studio 11 2012" WindowsStore 8.0 ARM)
+ add_test_VSWinStorePhone(vs11-store80-X64 "Visual Studio 11 2012" WindowsStore 8.0 x64)
endif()
if(vs12 AND ws81)
- add_test_VSWinStorePhone(vs12-store81-X86 "Visual Studio 12 2013" WindowsStore 8.1)
- add_test_VSWinStorePhone(vs12-store81-ARM "Visual Studio 12 2013 ARM" WindowsStore 8.1)
- add_test_VSWinStorePhone(vs12-store81-X64 "Visual Studio 12 2013 Win64" WindowsStore 8.1)
+ add_test_VSWinStorePhone(vs12-store81-X86 "Visual Studio 12 2013" WindowsStore 8.1 Win32)
+ add_test_VSWinStorePhone(vs12-store81-ARM "Visual Studio 12 2013" WindowsStore 8.1 ARM)
+ add_test_VSWinStorePhone(vs12-store81-X64 "Visual Studio 12 2013" WindowsStore 8.1 x64)
add_test(NAME VSXaml COMMAND ${CMAKE_CTEST_COMMAND}
--build-and-test
@@ -2164,22 +2165,23 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
)
endif()
if(CMake_TEST_VSWinStorePhone_VS_2017 AND ws10_0)
- add_test_VSWinStorePhone(vs15-store10_0-X86 "Visual Studio 15 2017" WindowsStore 10.0)
- add_test_VSWinStorePhone(vs15-store10_0-ARM "Visual Studio 15 2017 ARM" WindowsStore 10.0)
- add_test_VSWinStorePhone(vs15-store10_0-X64 "Visual Studio 15 2017 Win64" WindowsStore 10.0)
+ add_test_VSWinStorePhone(vs15-store10_0-X86 "Visual Studio 15 2017" WindowsStore 10.0 Win32)
+ add_test_VSWinStorePhone(vs15-store10_0-ARM "Visual Studio 15 2017" WindowsStore 10.0 ARM)
+ add_test_VSWinStorePhone(vs15-store10_0-X64 "Visual Studio 15 2017" WindowsStore 10.0 x64)
+ add_test_VSWinStorePhone(vs15-store10_0-ARM64 "Visual Studio 15 2017" WindowsStore 10.0 ARM64)
endif()
if(vs14 AND ws10_0)
- add_test_VSWinStorePhone(vs14-store10_0-X86 "Visual Studio 14 2015" WindowsStore 10.0)
- add_test_VSWinStorePhone(vs14-store10_0-ARM "Visual Studio 14 2015 ARM" WindowsStore 10.0)
- add_test_VSWinStorePhone(vs14-store10_0-X64 "Visual Studio 14 2015 Win64" WindowsStore 10.0)
+ add_test_VSWinStorePhone(vs14-store10_0-X86 "Visual Studio 14 2015" WindowsStore 10.0 Win32)
+ add_test_VSWinStorePhone(vs14-store10_0-ARM "Visual Studio 14 2015" WindowsStore 10.0 ARM)
+ add_test_VSWinStorePhone(vs14-store10_0-X64 "Visual Studio 14 2015" WindowsStore 10.0 x64)
endif()
if(vs11 AND wp80)
- add_test_VSWinStorePhone(vs11-phone80-X86 "Visual Studio 11 2012" WindowsPhone 8.0)
- add_test_VSWinStorePhone(vs11-phone80-ARM "Visual Studio 11 2012 ARM" WindowsPhone 8.0)
+ add_test_VSWinStorePhone(vs11-phone80-X86 "Visual Studio 11 2012" WindowsPhone 8.0 Win32)
+ add_test_VSWinStorePhone(vs11-phone80-ARM "Visual Studio 11 2012" WindowsPhone 8.0 ARM)
endif()
if(vs12 AND wp81)
- add_test_VSWinStorePhone(vs12-phone81-X86 "Visual Studio 12 2013" WindowsPhone 8.1)
- add_test_VSWinStorePhone(vs12-phone81-ARM "Visual Studio 12 2013 ARM" WindowsPhone 8.1)
+ add_test_VSWinStorePhone(vs12-phone81-X86 "Visual Studio 12 2013" WindowsPhone 8.1 Win32)
+ add_test_VSWinStorePhone(vs12-phone81-ARM "Visual Studio 12 2013" WindowsPhone 8.1 ARM)
endif()
endif()
@@ -2830,6 +2832,8 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
ADD_TEST_MACRO(CMakeCommands.add_link_options)
ADD_TEST_MACRO(CMakeCommands.target_link_options)
+ ADD_TEST_MACRO(CMakeCommands.link_directories)
+ ADD_TEST_MACRO(CMakeCommands.target_link_directories)
# The cmake server-mode test requires python for a simple client.
find_package(PythonInterp QUIET)
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index cb048be..c6b7dbc 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -619,6 +619,18 @@ export(TARGETS testLinkOptions NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
#------------------------------------------------------------------------------
+# test export of INTERFACE_LINK_DIRECTORIES
+add_library(testLinkDirectories INTERFACE)
+target_link_directories(testLinkDirectories INTERFACE
+ $<BUILD_INTERFACE:/interface/build>
+ $<INSTALL_INTERFACE:interface/install>)
+
+install(TARGETS testLinkDirectories
+ EXPORT RequiredExp DESTINATION lib)
+export(TARGETS testLinkDirectories NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
+
+
+#------------------------------------------------------------------------------
# test export of INTERFACE_LINK_DEPENDS
if(CMAKE_GENERATOR MATCHES "Make|Ninja")
add_library(testLinkDepends INTERFACE)
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index 8791a19..67fcc02 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -490,6 +490,11 @@ checkForProperty(bld_testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
checkForProperty(Req::testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
#---------------------------------------------------------------------------------
+# check that imported libraries have the expected INTERFACE_LINK_DIRECTORIES property
+checkForProperty(bld_testLinkDirectories "INTERFACE_LINK_DIRECTORIES" "/interface/build")
+checkForProperty(Req::testLinkDirectories "INTERFACE_LINK_DIRECTORIES" "${CMAKE_INSTALL_PREFIX}/interface/install")
+
+#---------------------------------------------------------------------------------
# check that imported libraries have the expected INTERFACE_LINK_DEPENDS property
if(CMAKE_GENERATOR MATCHES "Make|Ninja")
checkForProperty(bld_testLinkDepends "INTERFACE_LINK_DEPENDS" "BUILD_LINK_DEPENDS")
diff --git a/Tests/LinkDirectory/External/CMakeLists.txt b/Tests/LinkDirectory/External/CMakeLists.txt
index f7c840f..d2a1f9f 100644
--- a/Tests/LinkDirectory/External/CMakeLists.txt
+++ b/Tests/LinkDirectory/External/CMakeLists.txt
@@ -1,6 +1,20 @@
cmake_minimum_required(VERSION 2.8)
project(LinkDirectoryExternal C)
+
+add_executable(myexe2 myexe.c)
+set_property(TARGET myexe2 PROPERTY OUTPUT_NAME LinkDirectory2)
+target_link_directories(myexe2 PRIVATE lib "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
+target_link_libraries(myexe2 PRIVATE mylibA mylibB)
+
+add_library (mylibs INTERFACE)
+target_link_directories(mylibs INTERFACE lib "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
+target_link_libraries(mylibs INTERFACE mylibA mylibB)
+add_executable(myexe3 myexe.c)
+set_property(TARGET myexe3 PROPERTY OUTPUT_NAME LinkDirectory3)
+target_link_libraries(myexe3 PRIVATE mylibs)
+
+
# Test CMP0015 OLD behavior: -L../lib
cmake_policy(SET CMP0015 OLD)
link_directories(../lib)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-Common.cmake b/Tests/RunCMake/CMP0081/CMP0081-Common.cmake
new file mode 100644
index 0000000..3ea5277
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-Common.cmake
@@ -0,0 +1,5 @@
+
+enable_language(CXX)
+
+add_library(foo SHARED empty.cpp)
+set_target_properties(foo PROPERTIES LINK_DIRECTORIES "../lib")
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt b/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt
new file mode 100644
index 0000000..d31c149
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error in CMakeLists.txt:
+ Found relative path while evaluating link directories of "foo":
+
+ "../lib"
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake b/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake
new file mode 100644
index 0000000..9b927a2
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0081 NEW)
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt b/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake b/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake
new file mode 100644
index 0000000..2e91bf6
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0081 OLD)
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt b/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt
new file mode 100644
index 0000000..eac0648
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0081 is not set: Relative paths not allowed in LINK_DIRECTORIES
+ target property. Run "cmake --help-policy CMP0081" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+
+ Found relative path while evaluating link directories of "foo":
+
+ "../lib"
+
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake b/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake
new file mode 100644
index 0000000..33bb21d
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake
@@ -0,0 +1,2 @@
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMakeLists.txt b/Tests/RunCMake/CMP0081/CMakeLists.txt
new file mode 100644
index 0000000..ef2163c
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0081/RunCMakeTest.cmake b/Tests/RunCMake/CMP0081/RunCMakeTest.cmake
new file mode 100644
index 0000000..335d8c5
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0081-OLD)
+run_cmake(CMP0081-NEW)
+run_cmake(CMP0081-WARN)
diff --git a/Tests/RunCMake/CMP0081/empty.cpp b/Tests/RunCMake/CMP0081/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 69cb5b7..080d0d0 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -106,6 +106,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Darwin AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG)
add_RunCMake_test(CMP0068)
endif()
add_RunCMake_test(CMP0069)
+add_RunCMake_test(CMP0081)
# The test for Policy 65 requires the use of the
# CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode
diff --git a/Tests/RunCMake/CPack/DEB/Helpers.cmake b/Tests/RunCMake/CPack/DEB/Helpers.cmake
index e01f81d..9b98ed4 100644
--- a/Tests/RunCMake/CPack/DEB/Helpers.cmake
+++ b/Tests/RunCMake/CPack/DEB/Helpers.cmake
@@ -1,4 +1,4 @@
-set(ALL_FILES_GLOB "*.deb")
+set(ALL_FILES_GLOB "*.deb" "*.ddeb")
function(getPackageContent FILE RESULT_VAR)
execute_process(COMMAND ${CMAKE_COMMAND} -E env TZ=Etc/UTC ${DPKG_EXECUTABLE} -c "${FILE}"
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 91fed3e..91d3cb7 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -6,7 +6,7 @@ include("${RunCMake_SOURCE_DIR}/CPackTestHelpers.cmake")
# run_cpack_test args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP "PACKAGING_TYPES"
run_cpack_test(CUSTOM_BINARY_SPEC_FILE "RPM" false "MONOLITHIC;COMPONENT")
run_cpack_test(CUSTOM_NAMES "RPM;DEB;TGZ" true "COMPONENT")
-run_cpack_test(DEBUGINFO "RPM" true "COMPONENT")
+run_cpack_test(DEBUGINFO "RPM;DEB" true "COMPONENT")
run_cpack_test_subtests(DEFAULT_PERMISSIONS "CMAKE_var_set;CPACK_var_set;both_set;invalid_CMAKE_var;invalid_CPACK_var" "RPM;DEB" false "MONOLITHIC;COMPONENT")
run_cpack_test(DEPENDENCIES "RPM;DEB" true "COMPONENT")
run_cpack_test(DIST "RPM" false "MONOLITHIC")
diff --git a/Tests/RunCMake/CPack/VerifyResult.cmake b/Tests/RunCMake/CPack/VerifyResult.cmake
index af12d37..345b37f 100644
--- a/Tests/RunCMake/CPack/VerifyResult.cmake
+++ b/Tests/RunCMake/CPack/VerifyResult.cmake
@@ -92,7 +92,7 @@ if(NOT EXPECTED_FILES_COUNT EQUAL 0)
# check that there were no extra files generated
foreach(all_files_glob_ IN LISTS ALL_FILES_GLOB)
file(GLOB foundAll_ RELATIVE "${bin_dir}" "${all_files_glob_}")
- list(APPEND allFoundFiles_ "${foundAll_}")
+ list(APPEND allFoundFiles_ ${foundAll_})
endforeach()
list(LENGTH foundFiles_ foundFilesCount_)
diff --git a/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
index c745828..cf2e8ac 100644
--- a/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
+++ b/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
@@ -3,16 +3,39 @@ set(whitespaces_ "[\t\n\r ]*")
set(EXPECTED_FILES_COUNT "5")
set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
-set(EXPECTED_FILE_1_NAME "Debuginfo")
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(NAME "Debuginfo")
+ set(DEBUG_SUFFIX "debuginfo")
+ set(PKG "rpm")
+ set(DEBUG_PKG "rpm")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(NAME "debuginfo")
+ set(DEBUG_SUFFIX "dbgsym")
+ set(PKG "deb")
+ set(DEBUG_PKG "ddeb")
+endif()
+
+set(EXPECTED_FILE_1_NAME "${NAME}")
set(EXPECTED_FILE_1_COMPONENT "applications")
set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
-set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.rpm")
+
+set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.${PKG}")
set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
-set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.rpm")
+
+set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.${PKG}")
set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so")
-set(EXPECTED_FILE_4_NAME "Debuginfo")
-set(EXPECTED_FILE_4_COMPONENT "applications-debuginfo")
-set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
-set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
-set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
+set(EXPECTED_FILE_4 "${NAME}-applications-${DEBUG_SUFFIX}*.${DEBUG_PKG}")
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(EXPECTED_FILE_CONTENT_4 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+endif()
+
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
+ set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(EXPECTED_FILE_5 "TestDinfo-pkg-libs-dbgsym.ddeb")
+ set(EXPECTED_FILE_CONTENT_5 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake b/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
index 71457d4..161a36a 100644
--- a/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
+++ b/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
@@ -29,12 +29,16 @@ install(TARGETS test_lib DESTINATION bas COMPONENT libs)
set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT")
set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_APPLICATIONS_FILE_NAME "DEB-DEFAULT")
+set(CPACK_DEBIAN_APPLICATIONS_DEBUGINFO_PACKAGE ON)
# test that components with debuginfo enabled still honor
# CPACK_PACKAGE_FILE_NAME setting
set(CPACK_RPM_PACKAGE_NAME "Debuginfo")
set(CPACK_PACKAGE_FILE_NAME "TestDinfo-pkg")
set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_PACKAGE_NAME "Debuginfo")
+set(CPACK_DEBIAN_LIBS_DEBUGINFO_PACKAGE ON)
# test debuginfo package rename
set(CPACK_RPM_DEBUGINFO_FILE_NAME
diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
index 6c861fa..2441a9c 100644
--- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
+++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
@@ -25,6 +25,7 @@
\* CMP0069
\* CMP0073
\* CMP0076
+ \* CMP0081
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt b/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt
new file mode 100644
index 0000000..580c373
--- /dev/null
+++ b/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt
@@ -0,0 +1,2 @@
+-- Target LINK_DIRECTORIES is 'a;b;c;d;;e'
+-- Directory LINK_DIRECTORIES is 'a;b;c;d;;e'
diff --git a/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake b/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake
new file mode 100644
index 0000000..8529ef5
--- /dev/null
+++ b/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake
@@ -0,0 +1,3 @@
+include(Common.cmake)
+test_target_property(LINK_DIRECTORIES)
+test_directory_property(LINK_DIRECTORIES)
diff --git a/Tests/RunCMake/set_property/RunCMakeTest.cmake b/Tests/RunCMake/set_property/RunCMakeTest.cmake
index 77da703..8d4614c 100644
--- a/Tests/RunCMake/set_property/RunCMakeTest.cmake
+++ b/Tests/RunCMake/set_property/RunCMakeTest.cmake
@@ -6,6 +6,7 @@ run_cmake(COMPILE_OPTIONS)
run_cmake(IMPORTED_GLOBAL)
run_cmake(INCLUDE_DIRECTORIES)
run_cmake(LINK_OPTIONS)
+run_cmake(LINK_DIRECTORIES)
run_cmake(LINK_LIBRARIES)
run_cmake(SOURCES)
run_cmake(TYPE)
diff --git a/Utilities/Release/linux64_release.cmake b/Utilities/Release/linux64_release.cmake
index f2ca2d5..dc34120 100644
--- a/Utilities/Release/linux64_release.cmake
+++ b/Utilities/Release/linux64_release.cmake
@@ -3,8 +3,8 @@ set(BOOTSTRAP_ARGS "--docdir=doc/cmake")
set(HOST linux64)
set(MAKE_PROGRAM "make")
set(CPACK_BINARY_GENERATORS "STGZ TGZ")
-set(CC /opt/gcc-6.1.0/bin/gcc)
-set(CXX /opt/gcc-6.1.0/bin/g++)
+set(CC /opt/gcc-8.2.0/bin/gcc)
+set(CXX /opt/gcc-8.2.0/bin/g++)
set(CFLAGS "")
set(CXXFLAGS "")
set(qt_prefix "/home/kitware/qt-5.7.0")
@@ -41,6 +41,9 @@ CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:STRING=3
CMAKE_PREFIX_PATH:STRING=${qt_prefix}
CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES:STRING=${qt_xcb_libs}
")
+set(ENV [[
+export CMAKE_PREFIX_PATH=/opt/binutils-2.31
+]])
# Exclude Qt5 tests because our Qt5 is static.
set(EXTRA_CTEST_ARGS "-E Qt5")
diff --git a/Utilities/Scripts/update-libarchive.bash b/Utilities/Scripts/update-libarchive.bash
index 7534f94..3188658 100755
--- a/Utilities/Scripts/update-libarchive.bash
+++ b/Utilities/Scripts/update-libarchive.bash
@@ -8,7 +8,7 @@ readonly name="LibArchive"
readonly ownership="LibArchive Upstream <libarchive-discuss@googlegroups.com>"
readonly subtree="Utilities/cmlibarchive"
readonly repo="https://github.com/libarchive/libarchive.git"
-readonly tag="v3.3.2"
+readonly tag="v3.3.3"
readonly shortlog=false
readonly paths="
CMakeLists.txt
diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index 206f3c6..d7af6e2 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -71,6 +71,7 @@ include(CTest)
OPTION(ENABLE_NETTLE "Enable use of Nettle" ON)
OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
+OPTION(ENABLE_LZ4 "Enable the use of the system LZ4 library if found" ON)
OPTION(ENABLE_LZO "Enable the use of the system LZO library if found" OFF)
OPTION(ENABLE_LZMA "Enable the use of the system LZMA library if found" ON)
@@ -328,7 +329,7 @@ IF(ENABLE_LZO)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZO2 DEFAULT_MSG LZO2_LIBRARY LZO2_INCLUDE_DIR)
ELSE(ENABLE_LZO)
- SET(LIBZMA_FOUND FALSE) # Override cached value
+ SET(LZO2_FOUND FALSE) # Override cached value
ENDIF(ENABLE_LZO)
IF(LZO2_FOUND)
SET(HAVE_LIBLZO2 1)
@@ -347,15 +348,19 @@ IF(0) # CMake does not need LZ4 support in libarchive
#
# Find LZ4
#
-IF (LZ4_INCLUDE_DIR)
- # Already in cache, be silent
- SET(LZ4_FIND_QUIETLY TRUE)
-ENDIF (LZ4_INCLUDE_DIR)
+IF(ENABLE_LZ4)
+ IF (LZ4_INCLUDE_DIR)
+ # Already in cache, be silent
+ SET(LZ4_FIND_QUIETLY TRUE)
+ ENDIF (LZ4_INCLUDE_DIR)
-FIND_PATH(LZ4_INCLUDE_DIR lz4.h)
-FIND_LIBRARY(LZ4_LIBRARY NAMES lz4 liblz4)
-INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZ4 DEFAULT_MSG LZ4_LIBRARY LZ4_INCLUDE_DIR)
+ FIND_PATH(LZ4_INCLUDE_DIR lz4.h)
+ FIND_LIBRARY(LZ4_LIBRARY NAMES lz4 liblz4)
+ INCLUDE(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZ4 DEFAULT_MSG LZ4_LIBRARY LZ4_INCLUDE_DIR)
+ELSE(ENABLE_LZ4)
+ SET(LZ4_FOUND FALSE) # Override cached value
+ENDIF(ENABLE_LZ4)
IF(LZ4_FOUND)
SET(HAVE_LIBLZ4 1)
SET(HAVE_LZ4_H 1)
@@ -371,6 +376,31 @@ IF(LZ4_FOUND)
ENDIF(LZ4_FOUND)
MARK_AS_ADVANCED(CLEAR LZ4_INCLUDE_DIR)
MARK_AS_ADVANCED(CLEAR LZ4_LIBRARY)
+#
+# Find Zstd
+#
+IF (ZSTD_INCLUDE_DIR)
+ # Already in cache, be silent
+ SET(ZSTD_FIND_QUIETLY TRUE)
+ENDIF (ZSTD_INCLUDE_DIR)
+
+FIND_PATH(ZSTD_INCLUDE_DIR zstd.h)
+FIND_LIBRARY(ZSTD_LIBRARY NAMES zstd libzstd)
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(ZSTD DEFAULT_MSG ZSTD_LIBRARY ZSTD_INCLUDE_DIR)
+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)
+ #
+ # TODO: test for static library.
+ #
+ENDIF(ZSTD_FOUND)
+MARK_AS_ADVANCED(CLEAR ZSTD_INCLUDE_DIR)
+MARK_AS_ADVANCED(CLEAR ZSTD_LIBRARY)
ENDIF()
#
@@ -451,6 +481,7 @@ LA_CHECK_INCLUDE_FILE("sys/select.h" HAVE_SYS_SELECT_H)
LA_CHECK_INCLUDE_FILE("sys/stat.h" HAVE_SYS_STAT_H)
LA_CHECK_INCLUDE_FILE("sys/statfs.h" HAVE_SYS_STATFS_H)
LA_CHECK_INCLUDE_FILE("sys/statvfs.h" HAVE_SYS_STATVFS_H)
+LA_CHECK_INCLUDE_FILE("sys/sysmacros.h" HAVE_SYS_SYSMACROS_H)
LA_CHECK_INCLUDE_FILE("sys/time.h" HAVE_SYS_TIME_H)
LA_CHECK_INCLUDE_FILE("sys/utime.h" HAVE_SYS_UTIME_H)
LA_CHECK_INCLUDE_FILE("sys/utsname.h" HAVE_SYS_UTSNAME_H)
diff --git a/Utilities/cmlibarchive/build/cmake/config.h.in b/Utilities/cmlibarchive/build/cmake/config.h.in
index 368a451..1851d81 100644
--- a/Utilities/cmlibarchive/build/cmake/config.h.in
+++ b/Utilities/cmlibarchive/build/cmake/config.h.in
@@ -728,6 +728,9 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `z' library (-lz). */
#cmakedefine HAVE_LIBZ 1
+/* Define to 1 if you have the `zstd' library (-lzstd). */
+#cmakedefine HAVE_LIBZSTD 1
+
/* Define to 1 if you have the <limits.h> header file. */
#cmakedefine HAVE_LIMITS_H 1
@@ -1071,6 +1074,10 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/sysmacros.h> header file. */
+#cmakedefine HAVE_SYS_SYSMACROS_H 1
+
/* Define to 1 if you have the <sys/time.h> header file. */
#cmakedefine HAVE_SYS_TIME_H 1
@@ -1185,6 +1192,9 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <zlib.h> header file. */
#cmakedefine HAVE_ZLIB_H 1
+/* Define to 1 if you have the <zstd.h> header file. */
+#cmakedefine HAVE_ZSTD_H 1
+
/* Define to 1 if you have the `_ctime64_s' function. */
#cmakedefine HAVE__CTIME64_S 1
diff --git a/Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in b/Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in
index 95d7159..4b631e6 100644
--- a/Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in
+++ b/Utilities/cmlibarchive/build/pkgconfig/libarchive.pc.in
@@ -7,5 +7,6 @@ Name: libarchive
Description: library that can create and read several streaming archive formats
Version: @VERSION@
Cflags: -I${includedir}
+Cflags.private: -DLIBARCHIVE_STATIC
Libs: -L${libdir} -larchive
Libs.private: @LIBS@
diff --git a/Utilities/cmlibarchive/build/version b/Utilities/cmlibarchive/build/version
index 2dd0839..2427eab 100644
--- a/Utilities/cmlibarchive/build/version
+++ b/Utilities/cmlibarchive/build/version
@@ -1 +1 @@
-3003002
+3003003
diff --git a/Utilities/cmlibarchive/libarchive/CMakeLists.txt b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
index b02ae82..e38d664 100644
--- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
@@ -88,6 +88,7 @@ SET(libarchive_SOURCES
archive_read_support_filter_rpm.c
archive_read_support_filter_uu.c
archive_read_support_filter_xz.c
+ archive_read_support_filter_zstd.c
archive_read_support_format_7zip.c
archive_read_support_format_all.c
archive_read_support_format_ar.c
@@ -134,6 +135,7 @@ SET(libarchive_SOURCES
archive_write_add_filter_program.c
archive_write_add_filter_uuencode.c
archive_write_add_filter_xz.c
+ archive_write_add_filter_zstd.c
archive_write_set_format.c
archive_write_set_format_7zip.c
archive_write_set_format_ar.c
diff --git a/Utilities/cmlibarchive/libarchive/archive.h b/Utilities/cmlibarchive/libarchive/archive.h
index 0f94d2e..f3ebbfe 100644
--- a/Utilities/cmlibarchive/libarchive/archive.h
+++ b/Utilities/cmlibarchive/libarchive/archive.h
@@ -36,7 +36,7 @@
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
-#define ARCHIVE_VERSION_NUMBER 3003002
+#define ARCHIVE_VERSION_NUMBER 3003003
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
@@ -152,7 +152,7 @@ __LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
-#define ARCHIVE_VERSION_ONLY_STRING "3.3.2"
+#define ARCHIVE_VERSION_ONLY_STRING "3.3.3"
#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
@@ -174,6 +174,7 @@ __LA_DECL const char * archive_zlib_version(void);
__LA_DECL const char * archive_liblzma_version(void);
__LA_DECL const char * archive_bzlib_version(void);
__LA_DECL const char * archive_liblz4_version(void);
+__LA_DECL const char * archive_libzstd_version(void);
/* Declare our basic types. */
struct archive;
@@ -273,6 +274,7 @@ typedef const char *archive_passphrase_callback(struct archive *,
#define ARCHIVE_FILTER_LZOP 11
#define ARCHIVE_FILTER_GRZIP 12
#define ARCHIVE_FILTER_LZ4 13
+#define ARCHIVE_FILTER_ZSTD 14
#if ARCHIVE_VERSION_NUMBER < 4000000
#define ARCHIVE_COMPRESSION_NONE ARCHIVE_FILTER_NONE
@@ -430,6 +432,7 @@ __LA_DECL int archive_read_support_filter_program_signature
__LA_DECL int archive_read_support_filter_rpm(struct archive *);
__LA_DECL int archive_read_support_filter_uu(struct archive *);
__LA_DECL int archive_read_support_filter_xz(struct archive *);
+__LA_DECL int archive_read_support_filter_zstd(struct archive *);
__LA_DECL int archive_read_support_format_7zip(struct archive *);
__LA_DECL int archive_read_support_format_all(struct archive *);
@@ -775,6 +778,7 @@ __LA_DECL int archive_write_add_filter_program(struct archive *,
const char *cmd);
__LA_DECL int archive_write_add_filter_uuencode(struct archive *);
__LA_DECL int archive_write_add_filter_xz(struct archive *);
+__LA_DECL int archive_write_add_filter_zstd(struct archive *);
/* A convenience function to set the format based on the code or name. */
diff --git a/Utilities/cmlibarchive/libarchive/archive_acl.c b/Utilities/cmlibarchive/libarchive/archive_acl.c
index b8b6b63..4736531 100644
--- a/Utilities/cmlibarchive/libarchive/archive_acl.c
+++ b/Utilities/cmlibarchive/libarchive/archive_acl.c
@@ -1159,6 +1159,7 @@ archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
switch (want_type) {
case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ __LA_FALLTHROUGH;
case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
numfields = 5;
@@ -1626,6 +1627,7 @@ archive_acl_from_text_l(struct archive_acl *acl, const char *text,
switch (want_type) {
case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ __LA_FALLTHROUGH;
case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
numfields = 5;
diff --git a/Utilities/cmlibarchive/libarchive/archive_cmdline.c b/Utilities/cmlibarchive/libarchive/archive_cmdline.c
index 7d3bac5..5c519cd 100644
--- a/Utilities/cmlibarchive/libarchive/archive_cmdline.c
+++ b/Utilities/cmlibarchive/libarchive/archive_cmdline.c
@@ -100,10 +100,10 @@ get_argument(struct archive_string *as, const char *p)
/*
* Set up command line arguments.
- * Returns ARChIVE_OK if everything okey.
- * Returns ARChIVE_FAILED if there is a lack of the `"' terminator or an
+ * Returns ARCHIVE_OK if everything okey.
+ * Returns ARCHIVE_FAILED if there is a lack of the `"' terminator or an
* empty command line.
- * Returns ARChIVE_FATAL if no memory.
+ * Returns ARCHIVE_FATAL if no memory.
*/
int
__archive_cmdline_parse(struct archive_cmdline *data, const char *cmd)
diff --git a/Utilities/cmlibarchive/libarchive/archive_cryptor.c b/Utilities/cmlibarchive/libarchive/archive_cryptor.c
index ced52fd..71967c9 100644
--- a/Utilities/cmlibarchive/libarchive/archive_cryptor.c
+++ b/Utilities/cmlibarchive/libarchive/archive_cryptor.c
@@ -153,7 +153,7 @@ aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
CCCryptorStatus r;
r = CCCryptorReset(ref, NULL);
- if (r != kCCSuccess)
+ if (r != kCCSuccess && r != kCCUnimplemented)
return -1;
r = CCCryptorUpdate(ref, ctx->nonce, AES_BLOCK_SIZE, ctx->encr_buf,
AES_BLOCK_SIZE, NULL);
diff --git a/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h b/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
index 0ca544b..b975922 100644
--- a/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
@@ -64,7 +64,7 @@ typedef struct {
} archive_crypto_ctx;
#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
-#include <Bcrypt.h>
+#include <bcrypt.h>
/* Common in other bcrypt implementations, but missing from VS2008. */
#ifndef BCRYPT_SUCCESS
diff --git a/Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c b/Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c
index 07d08ff..aba41e5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c
+++ b/Utilities/cmlibarchive/libarchive/archive_disk_acl_freebsd.c
@@ -93,7 +93,9 @@ static const acl_perm_map_t acl_nfs4_flag_map[] = {
{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
+#ifdef ACL_ENTRY_INHERITED
{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
+#endif
};
static const int acl_nfs4_flag_map_size =
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.c b/Utilities/cmlibarchive/libarchive/archive_entry.c
index 30fb456..f722bbe 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.c
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.c
@@ -1491,7 +1491,7 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
* the style of the generated ACL.
*/
wchar_t *
-archive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len,
+archive_entry_acl_to_text_w(struct archive_entry *entry, la_ssize_t *len,
int flags)
{
return (archive_acl_to_text_w(&entry->acl, len, flags,
@@ -1499,7 +1499,7 @@ archive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len,
}
char *
-archive_entry_acl_to_text(struct archive_entry *entry, ssize_t *len,
+archive_entry_acl_to_text(struct archive_entry *entry, la_ssize_t *len,
int flags)
{
return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.h b/Utilities/cmlibarchive/libarchive/archive_entry.h
index 8c8e75a..a9134f6 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.h
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.h
@@ -30,7 +30,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
-#define ARCHIVE_VERSION_NUMBER 3003002
+#define ARCHIVE_VERSION_NUMBER 3003003
/*
* Note: archive_entry.h is for use outside of libarchive; the
@@ -42,6 +42,7 @@
#include <sys/types.h>
#include <stddef.h> /* for wchar_t */
+#include <stdint.h>
#include <time.h>
#if defined(_WIN32) && !defined(__CYGWIN__)
diff --git a/Utilities/cmlibarchive/libarchive/archive_match.c b/Utilities/cmlibarchive/libarchive/archive_match.c
index be72066..f150e82 100644
--- a/Utilities/cmlibarchive/libarchive/archive_match.c
+++ b/Utilities/cmlibarchive/libarchive/archive_match.c
@@ -1582,7 +1582,7 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
*/
int
-archive_match_include_uid(struct archive *_a, int64_t uid)
+archive_match_include_uid(struct archive *_a, la_int64_t uid)
{
struct archive_match *a;
@@ -1593,7 +1593,7 @@ archive_match_include_uid(struct archive *_a, int64_t uid)
}
int
-archive_match_include_gid(struct archive *_a, int64_t gid)
+archive_match_include_gid(struct archive *_a, la_int64_t gid)
{
struct archive_match *a;
diff --git a/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
index 59f95b8..921249b 100644
--- a/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
@@ -28,7 +28,8 @@
#include <openssl/hmac.h>
#include <openssl/opensslv.h>
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
#include <stdlib.h> /* malloc, free */
#include <string.h> /* memset */
static inline HMAC_CTX *HMAC_CTX_new(void)
diff --git a/Utilities/cmlibarchive/libarchive/archive_pack_dev.c b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c
index 098881b..53bddd7 100644
--- a/Utilities/cmlibarchive/libarchive/archive_pack_dev.c
+++ b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c
@@ -57,6 +57,9 @@ __RCSID("$NetBSD$");
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
+#ifdef HAVE_SYS_SYSMACROS_H
+#include <sys/sysmacros.h>
+#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_platform.h b/Utilities/cmlibarchive/libarchive/archive_platform.h
index f33208c..e161e64 100644
--- a/Utilities/cmlibarchive/libarchive/archive_platform.h
+++ b/Utilities/cmlibarchive/libarchive/archive_platform.h
@@ -196,4 +196,10 @@
#define ARCHIVE_ERRNO_MISC (-1)
#endif
+#if defined(__GNUC__) && (__GNUC__ >= 7)
+#define __LA_FALLTHROUGH __attribute__((fallthrough))
+#else
+#define __LA_FALLTHROUGH
+#endif
+
#endif /* !ARCHIVE_PLATFORM_H_INCLUDED */
diff --git a/Utilities/cmlibarchive/libarchive/archive_ppmd7.c b/Utilities/cmlibarchive/libarchive/archive_ppmd7.c
index 1aed922..d0bacc6 100644
--- a/Utilities/cmlibarchive/libarchive/archive_ppmd7.c
+++ b/Utilities/cmlibarchive/libarchive/archive_ppmd7.c
@@ -115,14 +115,14 @@ static void Ppmd7_Construct(CPpmd7 *p)
memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
}
-static void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc)
+static void Ppmd7_Free(CPpmd7 *p)
{
- alloc->Free(alloc, p->Base);
+ free(p->Base);
p->Size = 0;
p->Base = 0;
}
-static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
+static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size)
{
if (p->Base == 0 || p->Size != size)
{
@@ -131,14 +131,14 @@ static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
if (size < UNIT_SIZE) {
return False;
}
- Ppmd7_Free(p, alloc);
+ Ppmd7_Free(p);
p->AlignOffset =
#ifdef PPMD_32BIT
(4 - size) & 3;
#else
4 - (size & 3);
#endif
- if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size
+ if ((p->Base = (Byte *)malloc(p->AlignOffset + size
#ifndef PPMD_32BIT
+ UNIT_SIZE
#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h b/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h
index 06c99e8..577d6fb 100644
--- a/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h
@@ -95,8 +95,8 @@ typedef struct
{
/* Base Functions */
void (*Ppmd7_Construct)(CPpmd7 *p);
- Bool (*Ppmd7_Alloc)(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
- void (*Ppmd7_Free)(CPpmd7 *p, ISzAlloc *alloc);
+ Bool (*Ppmd7_Alloc)(CPpmd7 *p, UInt32 size);
+ void (*Ppmd7_Free)(CPpmd7 *p);
void (*Ppmd7_Init)(CPpmd7 *p, unsigned maxOrder);
#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
diff --git a/Utilities/cmlibarchive/libarchive/archive_ppmd_private.h b/Utilities/cmlibarchive/libarchive/archive_ppmd_private.h
index e78bde5..a83b851 100644
--- a/Utilities/cmlibarchive/libarchive/archive_ppmd_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_ppmd_private.h
@@ -69,13 +69,6 @@ typedef struct
void (*Write)(void *p, Byte b);
} IByteOut;
-
-typedef struct
-{
- void *(*Alloc)(void *p, size_t size);
- void (*Free)(void *p, void *address); /* address can be 0 */
-} ISzAlloc;
-
/*** End defined in Types.h ***/
/*** Begin defined in CpuArch.h ***/
diff --git a/Utilities/cmlibarchive/libarchive/archive_read.c b/Utilities/cmlibarchive/libarchive/archive_read.c
index a642a33..0e56e76 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read.c
@@ -120,7 +120,8 @@ archive_read_new(void)
* Record the do-not-extract-to file. This belongs in archive_read_extract.c.
*/
void
-archive_read_extract_set_skip_file(struct archive *_a, int64_t d, int64_t i)
+archive_read_extract_set_skip_file(struct archive *_a, la_int64_t d,
+ la_int64_t i)
{
struct archive_read *a = (struct archive_read *)_a;
@@ -747,7 +748,7 @@ choose_format(struct archive_read *a)
* Return the file offset (within the uncompressed data stream) where
* the last header started.
*/
-int64_t
+la_int64_t
archive_read_header_position(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
@@ -820,7 +821,7 @@ archive_read_format_capabilities(struct archive *_a)
* DO NOT intermingle calls to this function and archive_read_data_block
* to read a single entry body.
*/
-ssize_t
+la_ssize_t
archive_read_data(struct archive *_a, void *buff, size_t s)
{
struct archive *a = (struct archive *)_a;
@@ -943,7 +944,7 @@ archive_read_data_skip(struct archive *_a)
return (r);
}
-int64_t
+la_int64_t
archive_seek_data(struct archive *_a, int64_t offset, int whence)
{
struct archive_read *a = (struct archive_read *)_a;
@@ -1626,7 +1627,8 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
switch (whence) {
case SEEK_CUR:
/* Adjust the offset and use SEEK_SET instead */
- offset += filter->position;
+ offset += filter->position;
+ __LA_FALLTHROUGH;
case SEEK_SET:
cursor = 0;
while (1)
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
index 5e4d163..da7c55b 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
@@ -89,6 +89,10 @@ archive_read_append_filter(struct archive *_a, int code)
strcpy(str, "lz4");
r1 = archive_read_support_filter_lz4(_a);
break;
+ case ARCHIVE_FILTER_ZSTD:
+ strcpy(str, "zstd");
+ r1 = archive_read_support_filter_zstd(_a);
+ break;
case ARCHIVE_FILTER_LZIP:
strcpy(str, "lzip");
r1 = archive_read_support_filter_lzip(_a);
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c
index 548ba89..1786cff 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c
@@ -127,7 +127,7 @@ archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
/*
* Enter working directory and return working pathname of archive_entry.
* If a pointer to an integer is provided and its value is below zero
- * open a file descriptor on this pahtname.
+ * open a file descriptor on this pathname.
*/
const char *
archive_read_disk_entry_setup_path(struct archive_read_disk *a,
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
index 6961ae6..cdf7541 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
@@ -387,7 +387,7 @@ archive_read_disk_vtable(void)
}
const char *
-archive_read_disk_gname(struct archive *_a, int64_t gid)
+archive_read_disk_gname(struct archive *_a, la_int64_t gid)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
@@ -399,7 +399,7 @@ archive_read_disk_gname(struct archive *_a, int64_t gid)
}
const char *
-archive_read_disk_uname(struct archive *_a, int64_t uid)
+archive_read_disk_uname(struct archive *_a, la_int64_t uid)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
@@ -413,7 +413,7 @@ archive_read_disk_uname(struct archive *_a, int64_t uid)
int
archive_read_disk_set_gname_lookup(struct archive *_a,
void *private_data,
- const char * (*lookup_gname)(void *private, int64_t gid),
+ const char * (*lookup_gname)(void *private, la_int64_t gid),
void (*cleanup_gname)(void *private))
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
@@ -432,7 +432,7 @@ archive_read_disk_set_gname_lookup(struct archive *_a,
int
archive_read_disk_set_uname_lookup(struct archive *_a,
void *private_data,
- const char * (*lookup_uname)(void *private, int64_t uid),
+ const char * (*lookup_uname)(void *private, la_int64_t uid),
void (*cleanup_uname)(void *private))
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
index 3b90330..d82048d 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
@@ -117,7 +117,7 @@ struct filesystem {
*/
#define MAX_OVERLAPPED 8
-#define BUFFER_SIZE (1024 * 8)
+#define READ_BUFFER_SIZE (1024 * 64) /* Default to 64KB per https://technet.microsoft.com/en-us/library/cc938632.aspx */
#define DIRECT_IO 0/* Disabled */
#define ASYNC_IO 1/* Enabled */
@@ -320,7 +320,7 @@ archive_read_disk_vtable(void)
}
const char *
-archive_read_disk_gname(struct archive *_a, int64_t gid)
+archive_read_disk_gname(struct archive *_a, la_int64_t gid)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
@@ -332,7 +332,7 @@ archive_read_disk_gname(struct archive *_a, int64_t gid)
}
const char *
-archive_read_disk_uname(struct archive *_a, int64_t uid)
+archive_read_disk_uname(struct archive *_a, la_int64_t uid)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (ARCHIVE_OK != __archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
@@ -346,7 +346,7 @@ archive_read_disk_uname(struct archive *_a, int64_t uid)
int
archive_read_disk_set_gname_lookup(struct archive *_a,
void *private_data,
- const char * (*lookup_gname)(void *private, int64_t gid),
+ const char * (*lookup_gname)(void *private, la_int64_t gid),
void (*cleanup_gname)(void *private))
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
@@ -567,7 +567,7 @@ start_next_async_read(struct archive_read_disk *a, struct tree *t)
/* Allocate read buffer. */
if (olp->buff == NULL) {
void *p;
- size_t s = (size_t)align_num_per_sector(t, BUFFER_SIZE);
+ size_t s = (size_t)align_num_per_sector(t, READ_BUFFER_SIZE);
p = VirtualAlloc(NULL, s, MEM_COMMIT, PAGE_READWRITE);
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM,
@@ -683,7 +683,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
break;
} while (r == ARCHIVE_OK && t->ol_num_doing < MAX_OVERLAPPED);
} else {
- if (start_next_async_read(a, t) == ARCHIVE_FATAL)
+ if ((r = start_next_async_read(a, t)) == ARCHIVE_FATAL)
goto abort_read_data;
}
@@ -923,6 +923,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
t->entry_fh = CreateFileW(tree_current_access_path(t),
GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, flags, NULL);
if (t->entry_fh == INVALID_HANDLE_VALUE) {
+ la_dosmaperr(GetLastError());
archive_set_error(&a->archive, errno,
"Couldn't open %ls", tree_current_path(a->tree));
return (ARCHIVE_FAILED);
@@ -2275,10 +2276,10 @@ setup_sparse_from_disk(struct archive_read_disk *a,
if (range.Length.QuadPart > 0)
continue;
} else {
- /* The remaining data is hole. */
+ /* The entire file is a hole. Add one data block of size 0 at the end. */
archive_entry_sparse_add_entry(entry,
- range.FileOffset.QuadPart,
- range.Length.QuadPart);
+ entry_size,
+ 0);
}
break;
} else {
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_filter.3 b/Utilities/cmlibarchive/libarchive/archive_read_filter.3
index 7f020e3..ef0a701 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_filter.3
+++ b/Utilities/cmlibarchive/libarchive/archive_read_filter.3
@@ -38,6 +38,7 @@
.Nm archive_read_support_filter_rpm ,
.Nm archive_read_support_filter_uu ,
.Nm archive_read_support_filter_xz ,
+.Nm archive_read_support_filter_zstd ,
.Nm archive_read_support_filter_program ,
.Nm archive_read_support_filter_program_signature
.Nd functions for reading streaming archives
@@ -73,6 +74,8 @@ Streaming Archive Library (libarchive, -larchive)
.Ft int
.Fn archive_read_support_filter_xz "struct archive *"
.Ft int
+.Fn archive_read_support_filter_zstd "struct archive *"
+.Ft int
.Fo archive_read_support_filter_program
.Fa "struct archive *"
.Fa "const char *cmd"
@@ -99,7 +102,8 @@ Streaming Archive Library (libarchive, -larchive)
.Fn archive_read_support_filter_none ,
.Fn archive_read_support_filter_rpm ,
.Fn archive_read_support_filter_uu ,
-.Fn archive_read_support_filter_xz
+.Fn archive_read_support_filter_xz ,
+.Fn archive_read_support_filter_zstd ,
.Xc
Enables auto-detection code and decompression support for the
specified compression.
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c
index 68c53de..edb508c 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c
@@ -71,6 +71,8 @@ archive_read_support_filter_all(struct archive *a)
archive_read_support_filter_grzip(a);
/* Lz4 falls back to "lz4 -d" command-line program. */
archive_read_support_filter_lz4(a);
+ /* Zstd falls back to "zstd -d" command-line program. */
+ archive_read_support_filter_zstd(a);
/* Note: We always return ARCHIVE_OK here, even if some of the
* above return ARCHIVE_WARN. The intent here is to enable
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
new file mode 100644
index 0000000..c8bb36b
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_zstd.c
@@ -0,0 +1,292 @@
+/*-
+ * Copyright (c) 2009-2011 Sean Purcell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_ZSTD_H
+#include <zstd.h>
+#endif
+
+#include "archive.h"
+#include "archive_endian.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+
+struct private_data {
+ ZSTD_DStream *dstream;
+ unsigned char *out_block;
+ size_t out_block_size;
+ int64_t total_out;
+ char in_frame; /* True = in the middle of a zstd frame. */
+ char eof; /* True = found end of compressed data. */
+};
+
+/* Zstd Filter. */
+static ssize_t zstd_filter_read(struct archive_read_filter *, const void**);
+static int zstd_filter_close(struct archive_read_filter *);
+#endif
+
+/*
+ * Note that we can detect zstd compressed files even if we can't decompress
+ * them. (In fact, we like detecting them because we can give better error
+ * messages.) So the bid framework here gets compiled even if no zstd library
+ * is available.
+ */
+static int zstd_bidder_bid(struct archive_read_filter_bidder *,
+ struct archive_read_filter *);
+static int zstd_bidder_init(struct archive_read_filter *);
+
+int
+archive_read_support_filter_zstd(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *bidder;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_zstd");
+
+ if (__archive_read_get_bidder(a, &bidder) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ bidder->data = NULL;
+ bidder->name = "zstd";
+ bidder->bid = zstd_bidder_bid;
+ bidder->init = zstd_bidder_init;
+ bidder->options = NULL;
+ bidder->free = NULL;
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+ return (ARCHIVE_OK);
+#else
+ archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ "Using external zstd program for zstd decompression");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+/*
+ * Test whether we can handle this data.
+ */
+static int
+zstd_bidder_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+ const unsigned char *buffer;
+ ssize_t avail;
+ unsigned prefix;
+
+ /* Zstd frame magic values */
+ const unsigned zstd_magic = 0xFD2FB528U;
+
+ (void) self; /* UNUSED */
+
+ buffer = __archive_read_filter_ahead(filter, 4, &avail);
+ if (buffer == NULL)
+ return (0);
+
+ prefix = archive_le32dec(buffer);
+ if (prefix == zstd_magic)
+ return (32);
+
+ return (0);
+}
+
+#if !(HAVE_ZSTD_H && HAVE_LIBZSTD)
+
+/*
+ * If we don't have the library on this system, we can't do the
+ * decompression directly. We can, however, try to run "zstd -d"
+ * in case that's available.
+ */
+static int
+zstd_bidder_init(struct archive_read_filter *self)
+{
+ int r;
+
+ r = __archive_read_program(self, "zstd -d -qq");
+ /* Note: We set the format here even if __archive_read_program()
+ * above fails. We do, after all, know what the format is
+ * even if we weren't able to read it. */
+ self->code = ARCHIVE_FILTER_ZSTD;
+ self->name = "zstd";
+ return (r);
+}
+
+#else
+
+/*
+ * Initialize the filter object
+ */
+static int
+zstd_bidder_init(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ const size_t out_block_size = ZSTD_DStreamOutSize();
+ void *out_block;
+ ZSTD_DStream *dstream;
+
+ self->code = ARCHIVE_FILTER_ZSTD;
+ self->name = "zstd";
+
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ out_block = (unsigned char *)malloc(out_block_size);
+ dstream = ZSTD_createDStream();
+
+ if (state == NULL || out_block == NULL || dstream == NULL) {
+ free(out_block);
+ free(state);
+ ZSTD_freeDStream(dstream); /* supports free on NULL */
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for zstd decompression");
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = state;
+
+ state->out_block_size = out_block_size;
+ state->out_block = out_block;
+ state->dstream = dstream;
+ self->read = zstd_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = zstd_filter_close;
+
+ state->eof = 0;
+ state->in_frame = 0;
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+zstd_filter_read(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state;
+ size_t decompressed;
+ ssize_t avail_in;
+ ZSTD_outBuffer out;
+ ZSTD_inBuffer in;
+
+ state = (struct private_data *)self->data;
+
+ out = (ZSTD_outBuffer) { state->out_block, state->out_block_size, 0 };
+
+ /* Try to fill the output buffer. */
+ while (out.pos < out.size && !state->eof) {
+ if (!state->in_frame) {
+ const size_t ret = ZSTD_initDStream(state->dstream);
+ if (ZSTD_isError(ret)) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Error initializing zstd decompressor: %s",
+ ZSTD_getErrorName(ret));
+ return (ARCHIVE_FATAL);
+ }
+ }
+ in.src = __archive_read_filter_ahead(self->upstream, 1,
+ &avail_in);
+ if (avail_in < 0) {
+ return avail_in;
+ }
+ if (in.src == NULL && avail_in == 0) {
+ if (!state->in_frame) {
+ /* end of stream */
+ state->eof = 1;
+ break;
+ } else {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Truncated zstd input");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ in.size = avail_in;
+ in.pos = 0;
+
+ {
+ const size_t ret =
+ ZSTD_decompressStream(state->dstream, &out, &in);
+
+ if (ZSTD_isError(ret)) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Zstd decompression failed: %s",
+ ZSTD_getErrorName(ret));
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Decompressor made some progress */
+ __archive_read_filter_consume(self->upstream, in.pos);
+
+ /* ret guaranteed to be > 0 if frame isn't done yet */
+ state->in_frame = (ret != 0);
+ }
+ }
+
+ decompressed = out.pos;
+ state->total_out += decompressed;
+ if (decompressed == 0)
+ *p = NULL;
+ else
+ *p = state->out_block;
+ return (decompressed);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+zstd_filter_close(struct archive_read_filter *self)
+{
+ struct private_data *state;
+
+ state = (struct private_data *)self->data;
+
+ ZSTD_freeDStream(state->dstream);
+ free(state->out_block);
+ free(state);
+
+ return (ARCHIVE_OK);
+}
+
+#endif /* HAVE_ZLIB_H && HAVE_LIBZSTD */
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
index 96774f4..a885a4c 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
@@ -975,18 +975,6 @@ decode_codec_id(const unsigned char *codecId, size_t id_size)
return (id);
}
-static void *
-ppmd_alloc(void *p, size_t size)
-{
- (void)p;
- return malloc(size);
-}
-static void
-ppmd_free(void *p, void *address)
-{
- (void)p;
- free(address);
-}
static Byte
ppmd_read(void *p)
{
@@ -1006,8 +994,6 @@ ppmd_read(void *p)
return (b);
}
-static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
-
static int
init_decompression(struct archive_read *a, struct _7zip *zip,
const struct _7z_coder *coder1, const struct _7z_coder *coder2)
@@ -1237,7 +1223,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
if (zip->ppmd7_valid) {
__archive_ppmd7_functions.Ppmd7_Free(
- &zip->ppmd7_context, &g_szalloc);
+ &zip->ppmd7_context);
zip->ppmd7_valid = 0;
}
@@ -1256,7 +1242,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
}
__archive_ppmd7_functions.Ppmd7_Construct(&zip->ppmd7_context);
r = __archive_ppmd7_functions.Ppmd7_Alloc(
- &zip->ppmd7_context, msize, &g_szalloc);
+ &zip->ppmd7_context, msize);
if (r == 0) {
archive_set_error(&a->archive, ENOMEM,
"Coludn't allocate memory for PPMd");
@@ -1636,7 +1622,7 @@ free_decompression(struct archive_read *a, struct _7zip *zip)
#endif
if (zip->ppmd7_valid) {
__archive_ppmd7_functions.Ppmd7_Free(
- &zip->ppmd7_context, &g_szalloc);
+ &zip->ppmd7_context);
zip->ppmd7_valid = 0;
}
return (r);
@@ -2569,6 +2555,7 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
case kDummy:
if (ll == 0)
break;
+ __LA_FALLTHROUGH;
default:
if (header_bytes(a, ll) == NULL)
return (-1);
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c
index ad9f782..67d5b21 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c
@@ -633,6 +633,13 @@ header_newc(struct archive_read *a, struct cpio *cpio,
/* Pad name to 2 more than a multiple of 4. */
*name_pad = (2 - *namelength) & 3;
+ /* Make sure that the padded name length fits into size_t. */
+ if (*name_pad > SIZE_MAX - *namelength) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "cpio archive has invalid namelength");
+ return (ARCHIVE_FATAL);
+ }
+
/*
* Note: entry_bytes_remaining is at least 64 bits and
* therefore guaranteed to be big enough for a 33-bit file
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
index 4b436d1..93649f8 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
@@ -409,7 +409,8 @@ static int next_entry_seek(struct archive_read *, struct iso9660 *,
struct file_info **);
static struct file_info *
parse_file_info(struct archive_read *a,
- struct file_info *parent, const unsigned char *isodirrec);
+ struct file_info *parent, const unsigned char *isodirrec,
+ size_t reclen);
static int parse_rockridge(struct archive_read *a,
struct file_info *file, const unsigned char *start,
const unsigned char *end);
@@ -1022,7 +1023,7 @@ read_children(struct archive_read *a, struct file_info *parent)
if (*(p + DR_name_len_offset) == 1
&& *(p + DR_name_offset) == '\001')
continue;
- child = parse_file_info(a, parent, p);
+ child = parse_file_info(a, parent, p, b - p);
if (child == NULL) {
__archive_read_consume(a, skip_size);
return (ARCHIVE_FATAL);
@@ -1112,7 +1113,7 @@ choose_volume(struct archive_read *a, struct iso9660 *iso9660)
*/
seenJoliet = iso9660->seenJoliet;/* Save flag. */
iso9660->seenJoliet = 0;
- file = parse_file_info(a, NULL, block);
+ file = parse_file_info(a, NULL, block, vd->size);
if (file == NULL)
return (ARCHIVE_FATAL);
iso9660->seenJoliet = seenJoliet;
@@ -1144,7 +1145,7 @@ choose_volume(struct archive_read *a, struct iso9660 *iso9660)
return (ARCHIVE_FATAL);
}
iso9660->seenJoliet = 0;
- file = parse_file_info(a, NULL, block);
+ file = parse_file_info(a, NULL, block, vd->size);
if (file == NULL)
return (ARCHIVE_FATAL);
iso9660->seenJoliet = seenJoliet;
@@ -1749,7 +1750,7 @@ archive_read_format_iso9660_cleanup(struct archive_read *a)
*/
static struct file_info *
parse_file_info(struct archive_read *a, struct file_info *parent,
- const unsigned char *isodirrec)
+ const unsigned char *isodirrec, size_t reclen)
{
struct iso9660 *iso9660;
struct file_info *file, *filep;
@@ -1763,16 +1764,20 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
iso9660 = (struct iso9660 *)(a->format->data);
- dr_len = (size_t)isodirrec[DR_length_offset];
- name_len = (size_t)isodirrec[DR_name_len_offset];
- location = archive_le32dec(isodirrec + DR_extent_offset);
- fsize = toi(isodirrec + DR_size_offset, DR_size_size);
- /* Sanity check that dr_len needs at least 34. */
- if (dr_len < 34) {
+ if (reclen != 0)
+ dr_len = (size_t)isodirrec[DR_length_offset];
+ /*
+ * Sanity check that reclen is not zero and dr_len is greater than
+ * reclen but at least 34
+ */
+ if (reclen == 0 || reclen < dr_len || dr_len < 34) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid length of directory record");
+ "Invalid length of directory record");
return (NULL);
}
+ name_len = (size_t)isodirrec[DR_name_len_offset];
+ location = archive_le32dec(isodirrec + DR_extent_offset);
+ fsize = toi(isodirrec + DR_size_offset, DR_size_size);
/* Sanity check that name_len doesn't exceed dr_len. */
if (dr_len - 33 < name_len || name_len == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
index 1995e9c..98d02c6 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
@@ -701,6 +701,12 @@ archive_read_format_lha_read_header(struct archive_read *a,
* Prepare variables used to read a file content.
*/
lha->entry_bytes_remaining = lha->compsize;
+ if (lha->entry_bytes_remaining < 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid LHa entry size");
+ return (ARCHIVE_FATAL);
+ }
lha->entry_offset = 0;
lha->entry_crc_calculated = 0;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
index 44b6083..5b0eadc 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_rb.h"
#include "archive_read_private.h"
#include "archive_string.h"
#include "archive_pack_dev.h"
@@ -75,7 +76,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
#define MTREE_HAS_OPTIONAL 0x0800
#define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */
-#define MTREE_HASHTABLE_SIZE 1024
+#define MAX_LINE_LEN (1024 * 1024)
struct mtree_option {
struct mtree_option *next;
@@ -83,13 +84,13 @@ struct mtree_option {
};
struct mtree_entry {
+ struct archive_rb_node rbnode;
+ struct mtree_entry *next_dup;
struct mtree_entry *next;
struct mtree_option *options;
char *name;
char full;
char used;
- unsigned int name_hash;
- struct mtree_entry *hashtable_next;
};
struct mtree {
@@ -102,11 +103,12 @@ struct mtree {
const char *archive_format_name;
struct mtree_entry *entries;
struct mtree_entry *this_entry;
- struct mtree_entry *entry_hashtable[MTREE_HASHTABLE_SIZE];
+ struct archive_rb_tree entry_rbtree;
struct archive_string current_dir;
struct archive_string contents_name;
struct archive_entry_linkresolver *resolver;
+ struct archive_rb_tree rbtree;
int64_t cur_size;
char checkfs;
@@ -115,7 +117,6 @@ struct mtree {
static int bid_keycmp(const char *, const char *, ssize_t);
static int cleanup(struct archive_read *);
static int detect_form(struct archive_read *, int *);
-static unsigned int hash(const char *);
static int mtree_bid(struct archive_read *, int);
static int parse_file(struct archive_read *, struct archive_entry *,
struct mtree *, struct mtree_entry *, int *);
@@ -217,9 +218,30 @@ free_options(struct mtree_option *head)
}
}
+static int
+mtree_cmp_node(const struct archive_rb_node *n1,
+ const struct archive_rb_node *n2)
+{
+ const struct mtree_entry *e1 = (const struct mtree_entry *)n1;
+ const struct mtree_entry *e2 = (const struct mtree_entry *)n2;
+
+ return (strcmp(e1->name, e2->name));
+}
+
+static int
+mtree_cmp_key(const struct archive_rb_node *n, const void *key)
+{
+ const struct mtree_entry *e = (const struct mtree_entry *)n;
+
+ return (strcmp(e->name, key));
+}
+
int
archive_read_support_format_mtree(struct archive *_a)
{
+ static const struct archive_rb_tree_ops rb_ops = {
+ mtree_cmp_node, mtree_cmp_key,
+ };
struct archive_read *a = (struct archive_read *)_a;
struct mtree *mtree;
int r;
@@ -235,6 +257,8 @@ archive_read_support_format_mtree(struct archive *_a)
}
mtree->fd = -1;
+ __archive_rb_tree_init(&mtree->rbtree, &rb_ops);
+
r = __archive_read_register_format(a, mtree, "mtree",
mtree_bid, archive_read_format_mtree_options, read_header, read_data, skip, NULL, cleanup, NULL, NULL);
@@ -334,6 +358,14 @@ next_line(struct archive_read *a,
size_t nbytes_req = (*ravail+1023) & ~1023U;
ssize_t tested;
+ /*
+ * Place an arbitrary limit on the line length.
+ * mtree is almost free-form input and without line length limits,
+ * it can consume a lot of memory.
+ */
+ if (len >= MAX_LINE_LEN)
+ return (-1);
+
/* Increase reading bytes if it is not enough to at least
* new two lines. */
if (nbytes_req < (size_t)*ravail + 160)
@@ -865,12 +897,11 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
struct mtree_option **global, const char *line, ssize_t line_len,
struct mtree_entry **last_entry, int is_form_d)
{
- struct mtree_entry *entry, *ht_iter;
+ struct mtree_entry *entry;
struct mtree_option *iter;
const char *next, *eq, *name, *end;
size_t name_len, len;
int r, i;
- unsigned int ht_idx;
if ((entry = malloc(sizeof(*entry))) == NULL) {
archive_set_error(&a->archive, errno, "Can't allocate memory");
@@ -881,8 +912,6 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
entry->name = NULL;
entry->used = 0;
entry->full = 0;
- entry->name_hash = 0;
- entry->hashtable_next = NULL;
/* Add this entry to list. */
if (*last_entry == NULL)
@@ -935,15 +964,17 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
memcpy(entry->name, name, name_len);
entry->name[name_len] = '\0';
parse_escapes(entry->name, entry);
- entry->name_hash = hash(entry->name);
- ht_idx = entry->name_hash % MTREE_HASHTABLE_SIZE;
- if ((ht_iter = mtree->entry_hashtable[ht_idx]) != NULL) {
- while (ht_iter->hashtable_next)
- ht_iter = ht_iter->hashtable_next;
- ht_iter->hashtable_next = entry;
- } else {
- mtree->entry_hashtable[ht_idx] = entry;
+ entry->next_dup = NULL;
+ if (entry->full) {
+ if (!__archive_rb_tree_insert_node(&mtree->rbtree, &entry->rbnode)) {
+ struct mtree_entry *alt;
+ alt = (struct mtree_entry *)__archive_rb_tree_find_node(
+ &mtree->rbtree, entry->name);
+ while (alt->next_dup)
+ alt = alt->next_dup;
+ alt->next_dup = entry;
+ }
}
for (iter = *global; iter != NULL; iter = iter->next) {
@@ -1138,14 +1169,13 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
* with pathname canonicalization, which is a very
* tricky subject.)
*/
- for (mp = mentry->hashtable_next; mp != NULL; mp = mp->hashtable_next) {
- if (mp->full && !mp->used
- && mentry->name_hash == mp->name_hash
- && strcmp(mentry->name, mp->name) == 0) {
+ mp = (struct mtree_entry *)__archive_rb_tree_find_node(
+ &mtree->rbtree, mentry->name);
+ for (; mp; mp = mp->next_dup) {
+ if (mp->full && !mp->used) {
/* Later lines override earlier ones. */
mp->used = 1;
- r1 = parse_line(a, entry, mtree, mp,
- &parsed_kws);
+ r1 = parse_line(a, entry, mtree, mp, &parsed_kws);
if (r1 < r)
r = r1;
}
@@ -1489,6 +1519,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
}
if (strcmp(key, "cksum") == 0)
break;
+ __LA_FALLTHROUGH;
case 'd':
if (strcmp(key, "device") == 0) {
/* stat(2) st_rdev field, e.g. the major/minor IDs
@@ -1502,12 +1533,14 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
archive_entry_set_rdev(entry, dev);
return r;
}
+ __LA_FALLTHROUGH;
case 'f':
if (strcmp(key, "flags") == 0) {
*parsed_kws |= MTREE_HAS_FFLAGS;
archive_entry_copy_fflags_text(entry, val);
break;
}
+ __LA_FALLTHROUGH;
case 'g':
if (strcmp(key, "gid") == 0) {
*parsed_kws |= MTREE_HAS_GID;
@@ -1519,16 +1552,19 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
archive_entry_copy_gname(entry, val);
break;
}
+ __LA_FALLTHROUGH;
case 'i':
if (strcmp(key, "inode") == 0) {
archive_entry_set_ino(entry, mtree_atol(&val, 10));
break;
}
+ __LA_FALLTHROUGH;
case 'l':
if (strcmp(key, "link") == 0) {
archive_entry_copy_symlink(entry, val);
break;
}
+ __LA_FALLTHROUGH;
case 'm':
if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
break;
@@ -1545,6 +1581,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
}
break;
}
+ __LA_FALLTHROUGH;
case 'n':
if (strcmp(key, "nlink") == 0) {
*parsed_kws |= MTREE_HAS_NLINK;
@@ -1552,6 +1589,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
(unsigned int)mtree_atol(&val, 10));
break;
}
+ __LA_FALLTHROUGH;
case 'r':
if (strcmp(key, "resdevice") == 0) {
/* stat(2) st_dev field, e.g. the device ID where the
@@ -1567,6 +1605,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
if (strcmp(key, "rmd160") == 0 ||
strcmp(key, "rmd160digest") == 0)
break;
+ __LA_FALLTHROUGH;
case 's':
if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0)
break;
@@ -1583,6 +1622,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
archive_entry_set_size(entry, mtree_atol(&val, 10));
break;
}
+ __LA_FALLTHROUGH;
case 't':
if (strcmp(key, "tags") == 0) {
/*
@@ -1625,18 +1665,21 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
archive_entry_set_filetype(entry, AE_IFBLK);
break;
}
+ __LA_FALLTHROUGH;
case 'c':
if (strcmp(val, "char") == 0) {
archive_entry_set_filetype(entry,
AE_IFCHR);
break;
}
+ __LA_FALLTHROUGH;
case 'd':
if (strcmp(val, "dir") == 0) {
archive_entry_set_filetype(entry,
AE_IFDIR);
break;
}
+ __LA_FALLTHROUGH;
case 'f':
if (strcmp(val, "fifo") == 0) {
archive_entry_set_filetype(entry,
@@ -1648,12 +1691,14 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
AE_IFREG);
break;
}
+ __LA_FALLTHROUGH;
case 'l':
if (strcmp(val, "link") == 0) {
archive_entry_set_filetype(entry,
AE_IFLNK);
break;
}
+ __LA_FALLTHROUGH;
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
@@ -1665,6 +1710,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
*parsed_kws |= MTREE_HAS_TYPE;
break;
}
+ __LA_FALLTHROUGH;
case 'u':
if (strcmp(key, "uid") == 0) {
*parsed_kws |= MTREE_HAS_UID;
@@ -1676,6 +1722,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
archive_entry_copy_uname(entry, val);
break;
}
+ __LA_FALLTHROUGH;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized key %s=%s", key, val);
@@ -1962,19 +2009,3 @@ readline(struct archive_read *a, struct mtree *mtree, char **start,
find_off = u - mtree->line.s;
}
}
-
-static unsigned int
-hash(const char *p)
-{
- /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
- as used by ELF for hashing function names. */
- unsigned g, h = 0;
- while (*p != '\0') {
- h = (h << 4) + *p++;
- if ((g = h & 0xF0000000) != 0) {
- h ^= g >> 24;
- h &= 0x0FFFFFFF;
- }
- }
- return h;
-}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
index a0e641e..c68d77b 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
@@ -604,20 +604,6 @@ lzss_emit_match(struct rar *rar, int offset, int length)
rar->lzss.position += length;
}
-static void *
-ppmd_alloc(void *p, size_t size)
-{
- (void)p;
- return malloc(size);
-}
-static void
-ppmd_free(void *p, void *address)
-{
- (void)p;
- free(address);
-}
-static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
-
static Byte
ppmd_read(void *p)
{
@@ -1038,7 +1024,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
case COMPRESS_METHOD_BEST:
ret = read_data_compressed(a, buff, size, offset);
if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN)
- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
+ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
break;
default:
@@ -1253,7 +1239,7 @@ archive_read_format_rar_cleanup(struct archive_read *a)
free(rar->dbo);
free(rar->unp_buffer);
free(rar->lzss.window);
- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
+ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
free(rar);
(a->format->data) = NULL;
return (ARCHIVE_OK);
@@ -1496,7 +1482,11 @@ read_header(struct archive_read *a, struct archive_entry *entry,
return (ARCHIVE_FATAL);
}
filename[filename_size++] = '\0';
- filename[filename_size++] = '\0';
+ /*
+ * Do not increment filename_size here as the computations below
+ * add the space for the terminating NUL explicitly.
+ */
+ filename[filename_size] = '\0';
/* Decoded unicode form is UTF-16BE, so we have to update a string
* conversion object for it. */
@@ -1654,7 +1644,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
rar->unp_offset = 0;
rar->unp_buffer_size = UNP_BUFFER_SIZE;
memset(rar->lengthtable, 0, sizeof(rar->lengthtable));
- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
+ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
rar->ppmd_valid = rar->ppmd_eod = 0;
/* Don't set any archive entries for non-file header types */
@@ -2118,7 +2108,7 @@ parse_codes(struct archive_read *a)
/* Make sure ppmd7_contest is freed before Ppmd7_Construct
* because reading a broken file cause this abnormal sequence. */
- __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
+ __archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context);
rar->bytein.a = a;
rar->bytein.Read = &ppmd_read;
@@ -2133,7 +2123,7 @@ parse_codes(struct archive_read *a)
}
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
- rar->dictionary_size, &g_szalloc))
+ rar->dictionary_size))
{
archive_set_error(&a->archive, ENOMEM,
"Out of memory");
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
index 30d5bc8..60800bb 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
@@ -251,15 +251,15 @@ archive_read_support_format_tar(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_read_support_format_tar");
tar = (struct tar *)calloc(1, sizeof(*tar));
-#ifdef HAVE_COPYFILE_H
- /* Set this by default on Mac OS. */
- tar->process_mac_extensions = 1;
-#endif
if (tar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate tar data");
return (ARCHIVE_FATAL);
}
+#ifdef HAVE_COPYFILE_H
+ /* Set this by default on Mac OS. */
+ tar->process_mac_extensions = 1;
+#endif
r = __archive_read_register_format(a, tar, "tar",
archive_read_format_tar_bid,
@@ -2241,7 +2241,7 @@ gnu_add_sparse_entry(struct archive_read *a, struct tar *tar,
else
tar->sparse_list = p;
tar->sparse_last = p;
- if (remaining < 0 || offset < 0) {
+ if (remaining < 0 || offset < 0 || offset > INT64_MAX - remaining) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed sparse map data");
return (ARCHIVE_FATAL);
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
index eeac1c8..9292ed7 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
@@ -1040,6 +1040,9 @@ atol10(const char *p, size_t char_cnt)
uint64_t l;
int digit;
+ if (char_cnt == 0)
+ return (0);
+
l = 0;
digit = *p - '0';
while (digit >= 0 && digit < 10 && char_cnt-- > 0) {
@@ -1054,7 +1057,10 @@ atol8(const char *p, size_t char_cnt)
{
int64_t l;
int digit;
-
+
+ if (char_cnt == 0)
+ return (0);
+
l = 0;
while (char_cnt-- > 0) {
if (*p >= '0' && *p <= '7')
@@ -2623,6 +2629,14 @@ strappend_base64(struct xar *xar,
archive_strncat(as, (const char *)buff, len);
}
+static int
+is_string(const char *known, const char *data, size_t len)
+{
+ if (strlen(known) != len)
+ return -1;
+ return memcmp(data, known, len);
+}
+
static void
xml_data(void *userData, const char *s, int len)
{
@@ -2674,26 +2688,26 @@ xml_data(void *userData, const char *s, int len)
archive_strncpy(&(xar->file->symlink), s, len);
break;
case FILE_TYPE:
- if (strncmp("file", s, len) == 0 ||
- strncmp("hardlink", s, len) == 0)
+ if (is_string("file", s, len) == 0 ||
+ is_string("hardlink", s, len) == 0)
xar->file->mode =
(xar->file->mode & ~AE_IFMT) | AE_IFREG;
- if (strncmp("directory", s, len) == 0)
+ if (is_string("directory", s, len) == 0)
xar->file->mode =
(xar->file->mode & ~AE_IFMT) | AE_IFDIR;
- if (strncmp("symlink", s, len) == 0)
+ if (is_string("symlink", s, len) == 0)
xar->file->mode =
(xar->file->mode & ~AE_IFMT) | AE_IFLNK;
- if (strncmp("character special", s, len) == 0)
+ if (is_string("character special", s, len) == 0)
xar->file->mode =
(xar->file->mode & ~AE_IFMT) | AE_IFCHR;
- if (strncmp("block special", s, len) == 0)
+ if (is_string("block special", s, len) == 0)
xar->file->mode =
(xar->file->mode & ~AE_IFMT) | AE_IFBLK;
- if (strncmp("socket", s, len) == 0)
+ if (is_string("socket", s, len) == 0)
xar->file->mode =
(xar->file->mode & ~AE_IFMT) | AE_IFSOCK;
- if (strncmp("fifo", s, len) == 0)
+ if (is_string("fifo", s, len) == 0)
xar->file->mode =
(xar->file->mode & ~AE_IFMT) | AE_IFIFO;
xar->file->has |= HAS_TYPE;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
index ddd4458..7e99b12 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
@@ -511,7 +511,13 @@ process_extra(struct archive_read *a, const char *p, size_t extra_length, struct
case 0x5455:
{
/* Extended time field "UT". */
- int flags = p[offset];
+ int flags;
+ if (datasize == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Incomplete extended time field");
+ return ARCHIVE_FAILED;
+ }
+ flags = p[offset];
offset++;
datasize--;
/* Flag bits indicate which dates are present. */
@@ -723,6 +729,11 @@ process_extra(struct archive_read *a, const char *p, size_t extra_length, struct
}
case 0x9901:
/* WinZip AES extra data field. */
+ if (datasize < 6) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Incomplete AES field");
+ return ARCHIVE_FAILED;
+ }
if (p[offset + 2] == 'A' && p[offset + 3] == 'E') {
/* Vendor version. */
zip_entry->aes_extra.vendor =
@@ -881,6 +892,24 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
zip_entry->mode |= 0664;
}
+ /* Windows archivers sometimes use backslash as the directory separator.
+ Normalize to slash. */
+ if (zip_entry->system == 0 &&
+ (wp = archive_entry_pathname_w(entry)) != NULL) {
+ if (wcschr(wp, L'/') == NULL && wcschr(wp, L'\\') != NULL) {
+ size_t i;
+ struct archive_wstring s;
+ archive_string_init(&s);
+ archive_wstrcpy(&s, wp);
+ for (i = 0; i < archive_strlen(&s); i++) {
+ if (s.s[i] == '\\')
+ s.s[i] = '/';
+ }
+ archive_entry_copy_pathname_w(entry, s.s);
+ archive_wstring_free(&s);
+ }
+ }
+
/* Make sure that entries with a trailing '/' are marked as directories
* even if the External File Attributes contains bogus values. If this
* is not a directory and there is no type, assume regularfile. */
@@ -1056,6 +1085,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
zip->end_of_entry = 1;
/* Set up a more descriptive format name. */
+ archive_string_empty(&zip->format_name);
archive_string_sprintf(&zip->format_name, "ZIP %d.%d (%s)",
version / 10, version % 10,
compression_name(zip->entry->compression));
diff --git a/Utilities/cmlibarchive/libarchive/archive_string.c b/Utilities/cmlibarchive/libarchive/archive_string.c
index 5ae09b6..554533e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_string.c
+++ b/Utilities/cmlibarchive/libarchive/archive_string.c
@@ -214,7 +214,8 @@ archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)
{
if (archive_wstring_ensure(as, as->length + s + 1) == NULL)
return (NULL);
- wmemmove(as->s + as->length, p, s);
+ if (s)
+ wmemmove(as->s + as->length, p, s);
as->length += s;
as->s[as->length] = 0;
return (as);
diff --git a/Utilities/cmlibarchive/libarchive/archive_util.c b/Utilities/cmlibarchive/libarchive/archive_util.c
index 1e36ad7..e5c6e3b 100644
--- a/Utilities/cmlibarchive/libarchive/archive_util.c
+++ b/Utilities/cmlibarchive/libarchive/archive_util.c
@@ -140,7 +140,7 @@ archive_compression_name(struct archive *a)
/*
* Return a count of the number of compressed bytes processed.
*/
-int64_t
+la_int64_t
archive_position_compressed(struct archive *a)
{
return archive_filter_bytes(a, -1);
@@ -149,7 +149,7 @@ archive_position_compressed(struct archive *a)
/*
* Return a count of the number of uncompressed bytes processed.
*/
-int64_t
+la_int64_t
archive_position_uncompressed(struct archive *a)
{
return archive_filter_bytes(a, 0);
diff --git a/Utilities/cmlibarchive/libarchive/archive_version_details.c b/Utilities/cmlibarchive/libarchive/archive_version_details.c
index 9289bf1..e773e5e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_version_details.c
+++ b/Utilities/cmlibarchive/libarchive/archive_version_details.c
@@ -45,6 +45,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1
#ifdef HAVE_LZ4_H
#include <lz4.h>
#endif
+#ifdef HAVE_ZSTD_H
+#include <zstd.h>
+#endif
#include "archive.h"
#include "archive_private.h"
@@ -59,6 +62,7 @@ archive_version_details(void)
const char *liblzma = archive_liblzma_version();
const char *bzlib = archive_bzlib_version();
const char *liblz4 = archive_liblz4_version();
+ const char *libzstd = archive_libzstd_version();
if (!init) {
archive_string_init(&str);
@@ -84,6 +88,10 @@ archive_version_details(void)
archive_strcat(&str, " liblz4/");
archive_strcat(&str, liblz4);
}
+ if (libzstd) {
+ archive_strcat(&str, " libzstd/");
+ archive_strcat(&str, libzstd);
+ }
}
return str.s;
}
@@ -131,3 +139,13 @@ archive_liblz4_version(void)
return NULL;
#endif
}
+
+const char *
+archive_libzstd_version(void)
+{
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+ return ZSTD_VERSION_STRING;
+#else
+ return NULL;
+#endif
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_virtual.c b/Utilities/cmlibarchive/libarchive/archive_virtual.c
index de2595a..f509ee5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_virtual.c
+++ b/Utilities/cmlibarchive/libarchive/archive_virtual.c
@@ -48,7 +48,7 @@ archive_filter_name(struct archive *a, int n)
return ((a->vtable->archive_filter_name)(a, n));
}
-int64_t
+la_int64_t
archive_filter_bytes(struct archive *a, int n)
{
return ((a->vtable->archive_filter_bytes)(a, n));
@@ -124,14 +124,15 @@ archive_write_finish_entry(struct archive *a)
return ((a->vtable->archive_write_finish_entry)(a));
}
-ssize_t
+la_ssize_t
archive_write_data(struct archive *a, const void *buff, size_t s)
{
return ((a->vtable->archive_write_data)(a, buff, s));
}
-ssize_t
-archive_write_data_block(struct archive *a, const void *buff, size_t s, int64_t o)
+la_ssize_t
+archive_write_data_block(struct archive *a, const void *buff, size_t s,
+ la_int64_t o)
{
if (a->vtable->archive_write_data_block == NULL) {
archive_set_error(a, ARCHIVE_ERRNO_MISC,
@@ -156,7 +157,7 @@ archive_read_next_header2(struct archive *a, struct archive_entry *entry)
int
archive_read_data_block(struct archive *a,
- const void **buff, size_t *s, int64_t *o)
+ const void **buff, size_t *s, la_int64_t *o)
{
return ((a->vtable->archive_read_data_block)(a, buff, s, o));
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write.3 b/Utilities/cmlibarchive/libarchive/archive_write.3
index 376d71d..c1164f5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write.3
@@ -71,7 +71,7 @@ support.
.\"
.Ss Set options
See
-.Xr archive_read_set_options 3 .
+.Xr archive_write_set_options 3 .
.\"
.Ss Open archive
See
diff --git a/Utilities/cmlibarchive/libarchive/archive_write.c b/Utilities/cmlibarchive/libarchive/archive_write.c
index 0634a22..e8daf53 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write.c
@@ -190,7 +190,7 @@ archive_write_get_bytes_in_last_block(struct archive *_a)
* an archive to itself recursively.
*/
int
-archive_write_set_skip_file(struct archive *_a, int64_t d, int64_t i)
+archive_write_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)
{
struct archive_write *a = (struct archive_write *)_a;
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter.c
index 08f518a..203f414 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter.c
@@ -53,6 +53,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
{ ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzip },
{ ARCHIVE_FILTER_UU, archive_write_add_filter_uuencode },
{ ARCHIVE_FILTER_XZ, archive_write_add_filter_xz },
+ { ARCHIVE_FILTER_ZSTD, archive_write_add_filter_zstd },
{ -1, NULL }
};
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c
index 85a8d47..ffa633c 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c
@@ -57,6 +57,7 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
{ "lzop", archive_write_add_filter_lzop },
{ "uuencode", archive_write_add_filter_uuencode },
{ "xz", archive_write_add_filter_xz },
+ { "zstd", archive_write_add_filter_zstd },
{ NULL, NULL }
};
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
index bbcc178..986123a 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
@@ -226,7 +226,12 @@ archive_compressor_gzip_open(struct archive_write_filter *f)
data->compressed[7] = (uint8_t)(t>>24)&0xff;
} else
memset(&data->compressed[4], 0, 4);
- data->compressed[8] = 0; /* No deflate options */
+ if (data->compression_level == 9)
+ data->compressed[8] = 2;
+ else if(data->compression_level == 1)
+ data->compressed[8] = 4;
+ else
+ data->compressed[8] = 0;
data->compressed[9] = 3; /* OS=Unix */
data->stream.next_out += 10;
data->stream.avail_out -= 10;
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
new file mode 100644
index 0000000..671fc6a
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_zstd.c
@@ -0,0 +1,335 @@
+/*-
+ * Copyright (c) 2017 Sean Purcell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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 "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_ZSTD_H
+#include <zstd.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_string.h"
+#include "archive_write_private.h"
+
+/* Don't compile this if we don't have zstd.h */
+
+struct private_data {
+ int compression_level;
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+ ZSTD_CStream *cstream;
+ int64_t total_in;
+ ZSTD_outBuffer out;
+#else
+ struct archive_write_program_data *pdata;
+#endif
+};
+
+static int archive_compressor_zstd_options(struct archive_write_filter *,
+ const char *, const char *);
+static int archive_compressor_zstd_open(struct archive_write_filter *);
+static int archive_compressor_zstd_write(struct archive_write_filter *,
+ const void *, size_t);
+static int archive_compressor_zstd_close(struct archive_write_filter *);
+static int archive_compressor_zstd_free(struct archive_write_filter *);
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+static int drive_compressor(struct archive_write_filter *,
+ struct private_data *, int, const void *, size_t);
+#endif
+
+
+/*
+ * Add a zstd compression filter to this write handle.
+ */
+int
+archive_write_add_filter_zstd(struct archive *_a)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+ struct private_data *data;
+ archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_add_filter_zstd");
+
+ data = calloc(1, sizeof(*data));
+ if (data == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ f->data = data;
+ f->open = &archive_compressor_zstd_open;
+ f->options = &archive_compressor_zstd_options;
+ f->close = &archive_compressor_zstd_close;
+ f->free = &archive_compressor_zstd_free;
+ f->code = ARCHIVE_FILTER_ZSTD;
+ f->name = "zstd";
+ data->compression_level = 3; /* Default level used by the zstd CLI */
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+ data->cstream = ZSTD_createCStream();
+ if (data->cstream == NULL) {
+ free(data);
+ archive_set_error(&a->archive, ENOMEM,
+ "Failed to allocate zstd compressor object");
+ return (ARCHIVE_FATAL);
+ }
+
+ return (ARCHIVE_OK);
+#else
+ data->pdata = __archive_write_program_allocate("zstd");
+ if (data->pdata == NULL) {
+ free(data);
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Using external zstd program");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+static int
+archive_compressor_zstd_free(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+ ZSTD_freeCStream(data->cstream);
+ free(data->out.dst);
+#else
+ __archive_write_program_free(data->pdata);
+#endif
+ free(data);
+ f->data = NULL;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
+ const char *value)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ if (strcmp(key, "compression-level") == 0) {
+ int level = atoi(value);
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+ if (level < 1 || level > ZSTD_maxCLevel()) {
+#else
+ /* If we don't have the library, hard-code the max level */
+ if (level < 1 || level > 22) {
+#endif
+ return (ARCHIVE_WARN);
+ }
+ data->compression_level = level;
+ return (ARCHIVE_OK);
+ }
+
+ /* Note: The "warn" return is just to inform the options
+ * supervisor that we didn't handle it. It will generate
+ * a suitable error if no one used this option. */
+ return (ARCHIVE_WARN);
+}
+
+#if HAVE_ZSTD_H && HAVE_LIBZSTD
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_zstd_open(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+
+ if (data->out.dst == NULL) {
+ size_t bs = ZSTD_CStreamOutSize(), bpb;
+ if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+ /* Buffer size should be a multiple number of
+ * the of bytes per block for performance. */
+ bpb = archive_write_get_bytes_per_block(f->archive);
+ if (bpb > bs)
+ bs = bpb;
+ else if (bpb != 0)
+ bs -= bs % bpb;
+ }
+ data->out.size = bs;
+ data->out.pos = 0;
+ data->out.dst
+ = (unsigned char *)malloc(data->out.size);
+ if (data->out.dst == NULL) {
+ archive_set_error(f->archive, ENOMEM,
+ "Can't allocate data for compression buffer");
+ return (ARCHIVE_FATAL);
+ }
+ }
+
+ f->write = archive_compressor_zstd_write;
+
+ if (ZSTD_isError(ZSTD_initCStream(data->cstream,
+ data->compression_level))) {
+ archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing zstd compressor object");
+ return (ARCHIVE_FATAL);
+ }
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,
+ size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+
+ /* Update statistics */
+ data->total_in += length;
+
+ if ((ret = drive_compressor(f, data, 0, buff, length)) != ARCHIVE_OK)
+ return (ret);
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_zstd_close(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int r1, r2;
+
+ /* Finish zstd frame */
+ r1 = drive_compressor(f, data, 1, NULL, 0);
+
+ r2 = __archive_write_close_filter(f->next_filter);
+
+ return r1 < r2 ? r1 : r2;
+}
+
+/*
+ * Utility function to push input data through compressor,
+ * writing full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write_filter *f,
+ struct private_data *data, int finishing, const void *src, size_t length)
+{
+ ZSTD_inBuffer in = (ZSTD_inBuffer) { src, length, 0 };
+
+ for (;;) {
+ if (data->out.pos == data->out.size) {
+ const int ret = __archive_write_filter(f->next_filter,
+ data->out.dst, data->out.size);
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ data->out.pos = 0;
+ }
+
+ /* If there's nothing to do, we're done. */
+ if (!finishing && in.pos == in.size)
+ return (ARCHIVE_OK);
+
+ {
+ const size_t zstdret = !finishing ?
+ ZSTD_compressStream(data->cstream, &data->out, &in)
+ : ZSTD_endStream(data->cstream, &data->out);
+
+ if (ZSTD_isError(zstdret)) {
+ archive_set_error(f->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Zstd compression failed: %s",
+ ZSTD_getErrorName(zstdret));
+ return (ARCHIVE_FATAL);
+ }
+
+ /* If we're finishing, 0 means nothing left to flush */
+ if (finishing && zstdret == 0) {
+ const int ret = __archive_write_filter(f->next_filter,
+ data->out.dst, data->out.pos);
+ return (ret);
+ }
+ }
+ }
+}
+
+#else /* HAVE_ZSTD_H && HAVE_LIBZSTD */
+
+static int
+archive_compressor_zstd_open(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ struct archive_string as;
+ int r;
+
+ archive_string_init(&as);
+ archive_string_sprintf(&as, "zstd -%d", data->compression_level);
+
+ f->write = archive_compressor_zstd_write;
+ r = __archive_write_program_open(f, data->pdata, as.s);
+ archive_string_free(&as);
+ return (r);
+}
+
+static int
+archive_compressor_zstd_write(struct archive_write_filter *f, const void *buff,
+ size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_compressor_zstd_close(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ return __archive_write_program_close(f, data->pdata);
+}
+
+#endif /* HAVE_ZSTD_H && HAVE_LIBZSTD */
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
index 4a42a3b..affa503 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
@@ -835,7 +835,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
}
int
-archive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i)
+archive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -1786,7 +1786,7 @@ finish_metadata:
int
archive_write_disk_set_group_lookup(struct archive *_a,
void *private_data,
- int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid),
+ la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid),
void (*cleanup_gid)(void *private))
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
@@ -1822,7 +1822,7 @@ archive_write_disk_set_user_lookup(struct archive *_a,
}
int64_t
-archive_write_disk_gid(struct archive *_a, const char *name, int64_t id)
+archive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -1833,7 +1833,7 @@ archive_write_disk_gid(struct archive *_a, const char *name, int64_t id)
}
int64_t
-archive_write_disk_uid(struct archive *_a, const char *name, int64_t id)
+archive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -1981,6 +1981,10 @@ restore_entry(struct archive_write_disk *a)
if ((en == EISDIR || en == EEXIST)
&& (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
/* If we're not overwriting, we're done. */
+ if (S_ISDIR(a->mode)) {
+ /* Don't overwrite any settings on existing directories. */
+ a->todo = 0;
+ }
archive_entry_unset_size(a->entry);
return (ARCHIVE_OK);
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
index 94b016e..78eda4a 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
@@ -906,7 +906,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
}
int
-archive_write_disk_set_skip_file(struct archive *_a, int64_t d, int64_t i)
+archive_write_disk_set_skip_file(struct archive *_a, la_int64_t d, la_int64_t i)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -1156,7 +1156,7 @@ _archive_write_disk_finish_entry(struct archive *_a)
int
archive_write_disk_set_group_lookup(struct archive *_a,
void *private_data,
- int64_t (*lookup_gid)(void *private, const char *gname, int64_t gid),
+ la_int64_t (*lookup_gid)(void *private, const char *gname, la_int64_t gid),
void (*cleanup_gid)(void *private))
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
@@ -1192,7 +1192,7 @@ archive_write_disk_set_user_lookup(struct archive *_a,
}
int64_t
-archive_write_disk_gid(struct archive *_a, const char *name, int64_t id)
+archive_write_disk_gid(struct archive *_a, const char *name, la_int64_t id)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -1203,7 +1203,7 @@ archive_write_disk_gid(struct archive *_a, const char *name, int64_t id)
}
int64_t
-archive_write_disk_uid(struct archive *_a, const char *name, int64_t id)
+archive_write_disk_uid(struct archive *_a, const char *name, la_int64_t id)
{
struct archive_write_disk *a = (struct archive_write_disk *)_a;
archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
@@ -1322,9 +1322,20 @@ restore_entry(struct archive_write_disk *a)
}
}
+ if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {
+ archive_set_error(&a->archive, en,
+ "Hard-link target '%s' does not exist.",
+ archive_entry_hardlink(a->entry));
+ return (ARCHIVE_FAILED);
+ }
+
if ((en == EISDIR || en == EEXIST)
&& (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
/* If we're not overwriting, we're done. */
+ if (S_ISDIR(a->mode)) {
+ /* Don't overwrite any settings on existing directories. */
+ a->todo = 0;
+ }
archive_entry_unset_size(a->entry);
return (ARCHIVE_OK);
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_filter.3 b/Utilities/cmlibarchive/libarchive/archive_write_filter.3
index e1d1891..d6fa071 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_filter.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_filter.3
@@ -42,7 +42,8 @@
.Nm archive_write_add_filter_none ,
.Nm archive_write_add_filter_program ,
.Nm archive_write_add_filter_uuencode ,
-.Nm archive_write_add_filter_xz
+.Nm archive_write_add_filter_xz ,
+.Nm archive_write_add_filter_zstd ,
.Nd functions enabling output filters
.Sh LIBRARY
Streaming Archive Library (libarchive, -larchive)
@@ -76,6 +77,8 @@ Streaming Archive Library (libarchive, -larchive)
.Fn archive_write_add_filter_uuencode "struct archive *"
.Ft int
.Fn archive_write_add_filter_xz "struct archive *"
+.Ft int
+.Fn archive_write_add_filter_zstd "struct archive *"
.Sh DESCRIPTION
.Bl -tag -width indent
.It Xo
@@ -89,6 +92,7 @@ Streaming Archive Library (libarchive, -larchive)
.Fn archive_write_add_filter_lzma ,
.Fn archive_write_add_filter_lzop ,
.Fn archive_write_add_filter_xz ,
+.Fn archive_write_add_filter_zstd ,
.Xc
The resulting archive will be compressed as specified.
Note that the compressed output is always properly blocked.
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
index 3fc5a07..2bd4ec4 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
@@ -2095,19 +2095,6 @@ compression_init_encoder_lzma2(struct archive *a,
/*
* _7_PPMD compressor.
*/
-static void *
-ppmd_alloc(void *p, size_t size)
-{
- (void)p;
- return malloc(size);
-}
-static void
-ppmd_free(void *p, void *address)
-{
- (void)p;
- free(address);
-}
-static ISzAlloc g_szalloc = { ppmd_alloc, ppmd_free };
static void
ppmd_write(void *p, Byte b)
{
@@ -2167,7 +2154,7 @@ compression_init_encoder_ppmd(struct archive *a,
archive_le32enc(props+1, msize);
__archive_ppmd7_functions.Ppmd7_Construct(&strm->ppmd7_context);
r = __archive_ppmd7_functions.Ppmd7_Alloc(
- &strm->ppmd7_context, msize, &g_szalloc);
+ &strm->ppmd7_context, msize);
if (r == 0) {
free(strm->buff);
free(strm);
@@ -2243,7 +2230,7 @@ compression_end_ppmd(struct archive *a, struct la_zstream *lastrm)
(void)a; /* UNUSED */
strm = (struct ppmd_stream *)lastrm->real_stream;
- __archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context, &g_szalloc);
+ __archive_ppmd7_functions.Ppmd7_Free(&strm->ppmd7_context);
free(strm->buff);
free(strm);
lastrm->real_stream = NULL;
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c
index c9771d8..50305cc 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c
@@ -180,7 +180,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
}
memset(buff, ' ', 60);
- strncpy(&buff[AR_fmag_offset], "`\n", 2);
+ memcpy(&buff[AR_fmag_offset], "`\n", 2);
if (strcmp(pathname, "/") == 0 ) {
/* Entry is archive symbol table in GNU format */
@@ -189,7 +189,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
}
if (strcmp(pathname, "__.SYMDEF") == 0) {
/* Entry is archive symbol table in BSD format */
- strncpy(buff + AR_name_offset, "__.SYMDEF", 9);
+ memcpy(buff + AR_name_offset, "__.SYMDEF", 9);
goto stat;
}
if (strcmp(pathname, "//") == 0) {
@@ -225,7 +225,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
* actually 15 bytes.
*/
if (strlen(filename) <= 15) {
- strncpy(&buff[AR_name_offset],
+ memcpy(&buff[AR_name_offset],
filename, strlen(filename));
buff[AR_name_offset + strlen(filename)] = '/';
} else {
@@ -248,7 +248,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
return (ARCHIVE_FATAL);
}
- strncpy(se, filename, strlen(filename));
+ memcpy(se, filename, strlen(filename));
strcpy(se + strlen(filename), "/\n");
ss = strstr(ar->strtab, se);
@@ -285,11 +285,11 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
* archive header.
*/
if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {
- strncpy(&buff[AR_name_offset], filename, strlen(filename));
+ memcpy(&buff[AR_name_offset], filename, strlen(filename));
buff[AR_name_offset + strlen(filename)] = ' ';
}
else {
- strncpy(buff + AR_name_offset, "#1/", 3);
+ memcpy(buff + AR_name_offset, "#1/", 3);
if (format_decimal(strlen(filename),
buff + AR_name_offset + 3,
AR_name_size - 3)) {
@@ -374,13 +374,14 @@ archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
return (ARCHIVE_WARN);
}
- ar->strtab = (char *)malloc(s);
+ ar->strtab = (char *)malloc(s + 1);
if (ar->strtab == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate strtab buffer");
return (ARCHIVE_FATAL);
}
- strncpy(ar->strtab, buff, s);
+ memcpy(ar->strtab, buff, s);
+ ar->strtab[s] = '\0';
ar->has_strtab = 1;
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
index 0eaf733..3cebeae 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
@@ -1654,7 +1654,7 @@ build_pax_attribute_name(char *dest, const char *src)
* GNU PAX Format 1.0 requires the special name, which pattern is:
* <dir>/GNUSparseFile.<pid>/<original file name>
*
- * Since reproducable archives are more important, use 0 as pid.
+ * Since reproducible archives are more important, use 0 as pid.
*
* This function is used for only Sparse file, a file type of which
* is regular file.