diff options
274 files changed, 5384 insertions, 2192 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/add_custom_command.rst b/Help/command/add_custom_command.rst index 5f74c54..71fe494 100644 --- a/Help/command/add_custom_command.rst +++ b/Help/command/add_custom_command.rst @@ -182,6 +182,9 @@ The options are: If it is a relative path it will be interpreted relative to the build tree directory corresponding to the current source directory. + Arguments to ``WORKING_DIRECTORY`` may use + :manual:`generator expressions <cmake-generator-expressions(7)>`. + ``DEPFILE`` Specify a ``.d`` depfile for the :generator:`Ninja` generator. A ``.d`` file holds dependencies usually emitted by the custom diff --git a/Help/command/add_custom_target.rst b/Help/command/add_custom_target.rst index bd61c8b..a6b2f77 100644 --- a/Help/command/add_custom_target.rst +++ b/Help/command/add_custom_target.rst @@ -121,3 +121,6 @@ The options are: Execute the command with the given current working directory. If it is a relative path it will be interpreted relative to the build tree directory corresponding to the current source directory. + + Arguments to ``WORKING_DIRECTORY`` may use + :manual:`generator expressions <cmake-generator-expressions(7)>`. diff --git a/Help/command/if.rst b/Help/command/if.rst index f04f233..5294ce8 100644 --- a/Help/command/if.rst +++ b/Help/command/if.rst @@ -148,23 +148,33 @@ Possible expressions are: ``if(<variable|string> VERSION_LESS <variable|string>)`` Component-wise integer version number comparison (version format is - ``major[.minor[.patch[.tweak]]]``). + ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). + Any non-integer version component or non-integer trailing part of a version + component effectively truncates the string at that point. ``if(<variable|string> VERSION_GREATER <variable|string>)`` Component-wise integer version number comparison (version format is - ``major[.minor[.patch[.tweak]]]``). + ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). + Any non-integer version component or non-integer trailing part of a version + component effectively truncates the string at that point. ``if(<variable|string> VERSION_EQUAL <variable|string>)`` Component-wise integer version number comparison (version format is - ``major[.minor[.patch[.tweak]]]``). + ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). + Any non-integer version component or non-integer trailing part of a version + component effectively truncates the string at that point. ``if(<variable|string> VERSION_LESS_EQUAL <variable|string>)`` Component-wise integer version number comparison (version format is - ``major[.minor[.patch[.tweak]]]``). + ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). + Any non-integer version component or non-integer trailing part of a version + component effectively truncates the string at that point. ``if(<variable|string> VERSION_GREATER_EQUAL <variable|string>)`` Component-wise integer version number comparison (version format is - ``major[.minor[.patch[.tweak]]]``). + ``major[.minor[.patch[.tweak]]]``, omitted components are treated as zero). + Any non-integer version component or non-integer trailing part of a version + component effectively truncates the string at that point. ``if(<variable|string> IN_LIST <variable>)`` True if the given element is contained in the named list variable. 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/envvar/CUDAHOSTCXX.rst b/Help/envvar/CUDAHOSTCXX.rst index f0f94f6..bb786ca 100644 --- a/Help/envvar/CUDAHOSTCXX.rst +++ b/Help/envvar/CUDAHOSTCXX.rst @@ -7,3 +7,7 @@ determine ``CUDA`` host compiler, after which the value for ``CUDAHOSTCXX`` is stored in the cache as :variable:`CMAKE_CUDA_HOST_COMPILER`. For any configuration run (including the first), the environment variable will be ignored if the :variable:`CMAKE_CUDA_HOST_COMPILER` variable is defined. + +This environment variable is primarily meant for use with projects that +enable ``CUDA`` as a first-class language. The :module:`FindCUDA` +module will also use it to initialize its ``CUDA_HOST_COMPILER`` setting. 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/OPTIONS_BUILD.txt b/Help/manual/OPTIONS_BUILD.txt index 33d27af..baa73d5 100644 --- a/Help/manual/OPTIONS_BUILD.txt +++ b/Help/manual/OPTIONS_BUILD.txt @@ -1,3 +1,11 @@ +``-S <path-to-source>`` + Path to root directory of the CMake project to build. + +``-B <path-to-build>`` + Path to directory which CMake will use as the root of build directory. + + If the directory doesn't already exist CMake will make it. + ``-C <initial-cache>`` Pre-load a script to populate the cache. 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-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index c3428d1..76fd3d9 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -68,10 +68,13 @@ Available logical expressions are: target. ``$<PLATFORM_ID:comp>`` ``1`` if the CMake-id of the platform matches ``comp``, otherwise ``0``. + See also the :variable:`CMAKE_SYSTEM_NAME` variable. ``$<C_COMPILER_ID:comp>`` ``1`` if the CMake-id of the C compiler matches ``comp``, otherwise ``0``. + See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. ``$<CXX_COMPILER_ID:comp>`` ``1`` if the CMake-id of the CXX compiler matches ``comp``, otherwise ``0``. + See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. ``$<VERSION_LESS:v1,v2>`` ``1`` if ``v1`` is a version less than ``v2``, else ``0``. ``$<VERSION_GREATER:v1,v2>`` @@ -84,8 +87,10 @@ Available logical expressions are: ``1`` if ``v1`` is a version greater than or equal to ``v2``, else ``0``. ``$<C_COMPILER_VERSION:ver>`` ``1`` if the version of the C compiler matches ``ver``, otherwise ``0``. + See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. ``$<CXX_COMPILER_VERSION:ver>`` ``1`` if the version of the CXX compiler matches ``ver``, otherwise ``0``. + See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. ``$<TARGET_POLICY:pol>`` ``1`` if the policy ``pol`` was NEW when the 'head' target was created, else ``0``. If the policy was not set, the warning message for the policy diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst index 8ecca4d..2cc52fe 100644 --- a/Help/manual/cmake-policies.7.rst +++ b/Help/manual/cmake-policies.7.rst @@ -57,6 +57,8 @@ 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> CMP0077: option() honors normal variables. </policy/CMP0077> 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 d8a5def..9dd36ed 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -78,6 +78,7 @@ Variables that Provide Information /variable/CMAKE_PROJECT_VERSION_TWEAK /variable/CMAKE_RANLIB /variable/CMAKE_ROOT + /variable/CMAKE_RULE_MESSAGES /variable/CMAKE_SCRIPT_MODE_FILE /variable/CMAKE_SHARED_LIBRARY_PREFIX /variable/CMAKE_SHARED_LIBRARY_SUFFIX @@ -178,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 @@ -393,6 +395,7 @@ Variables that Control the Build /variable/CMAKE_TRY_COMPILE_TARGET_TYPE /variable/CMAKE_USE_RELATIVE_PATHS /variable/CMAKE_VISIBILITY_INLINES_HIDDEN + /variable/CMAKE_VS_GLOBALS /variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD /variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD /variable/CMAKE_VS_SDK_EXCLUDE_DIRECTORIES diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 177acd4..b11526c 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -9,6 +9,7 @@ Synopsis .. parsed-literal:: cmake [<options>] {<path-to-source> | <path-to-existing-build>} + cmake [<options>] -S <path-to-source> -B <path-to-build> cmake [{-D <var>=<value>}...] -P <cmake-script-file> cmake --build <dir> [<options>...] [-- <build-tool-options>...] cmake --open <dir> @@ -353,11 +354,6 @@ Available commands are: Touch a file if it exists but do not create it. If a file does not exist it will be silently ignored. -UNIX-specific Command-Line Tools --------------------------------- - -The following ``cmake -E`` commands are available only on UNIX: - ``create_symlink <old> <new>`` Create a symbolic link ``<new>`` naming ``<old>``. diff --git a/Help/policy/CMP0080.rst b/Help/policy/CMP0080.rst new file mode 100644 index 0000000..5ce9591 --- /dev/null +++ b/Help/policy/CMP0080.rst @@ -0,0 +1,25 @@ +CMP0080 +------- + +:module:`BundleUtilities` cannot be included at configure time. + +The macros provided by :module:`BundleUtilities` are intended to be invoked +at install time rather than at configure time, because they depend on the +listed targets already existing at the time they are invoked. If they are +invoked at configure time, the targets haven't been built yet, and the +commands will fail. + +This policy restricts the inclusion of :module:`BundleUtilities` to +``cmake -P`` style scripts and install rules. Specifically, it looks for the +presence of :variable:`CMAKE_GENERATOR` and throws a fatal error if it exists. + +The ``OLD`` behavior of this policy is to allow :module:`BundleUtilities` to +be included at configure time. The ``NEW`` behavior of this policy is to +disallow such inclusion. + +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/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_dir/TESTS.rst b/Help/prop_dir/TESTS.rst index c6e1d88..91acd3e 100644 --- a/Help/prop_dir/TESTS.rst +++ b/Help/prop_dir/TESTS.rst @@ -4,4 +4,4 @@ TESTS List of tests. This read-only property holds a :ref:`;-list <CMake Language Lists>` of tests -defined so far by the :command:`add_test` command. +defined so far, in the current directory, by the :command:`add_test` command. diff --git a/Help/prop_gbl/RULE_MESSAGES.rst b/Help/prop_gbl/RULE_MESSAGES.rst index 87a5ca6..a9734a7 100644 --- a/Help/prop_gbl/RULE_MESSAGES.rst +++ b/Help/prop_gbl/RULE_MESSAGES.rst @@ -8,6 +8,6 @@ progress message describing what each build rule does. If the property is not set the default is ON. Set the property to OFF to disable granular messages and report only as each target completes. This is intended to allow scripted builds to avoid the build time cost -of detailed reports. If a ``CMAKE_RULE_MESSAGES`` cache entry exists +of detailed reports. If a :variable:`CMAKE_RULE_MESSAGES` cache entry exists its value initializes the value of this property. Non-Makefile generators currently ignore this property. 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/FindPython-lookup-strategy.rst b/Help/release/dev/FindPython-lookup-strategy.rst new file mode 100644 index 0000000..f6d6db5 --- /dev/null +++ b/Help/release/dev/FindPython-lookup-strategy.rst @@ -0,0 +1,6 @@ +FindPython-lookup-strategy +-------------------------- + +* Modules :module:`FindPython3`, :module:`FindPython2` and :module:`FindPython` + gain capability to control order of resource lookup on macOS (Framework) and + Windows (Registry). 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/bundleutilities-policy.rst b/Help/release/dev/bundleutilities-policy.rst new file mode 100644 index 0000000..e293f92 --- /dev/null +++ b/Help/release/dev/bundleutilities-policy.rst @@ -0,0 +1,5 @@ +bundleutilities-policy +---------------------- + +* The :module:`BundleUtilities` module may no longer be included at configure + time. This was always a bug anyway. See policy :policy:`CMP0080`. diff --git a/Help/release/dev/cmake-explicit-dirs.rst b/Help/release/dev/cmake-explicit-dirs.rst new file mode 100644 index 0000000..35f2d3a --- /dev/null +++ b/Help/release/dev/cmake-explicit-dirs.rst @@ -0,0 +1,10 @@ +cmake-explicit-dirs +------------------- + +* The :manual:`cmake <cmake(1)>` command gained the ``-S <source_dir>`` + command line option to specify the location of the source directory. + This option can be used independently of ``-B``. + +* The :manual:`cmake <cmake(1)>` command gained the ``-B <build_dir>`` + command line option to specify the location of the build directory. + This option can be used independently of ``-S``. 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/create_symlink-windows.rst b/Help/release/dev/create_symlink-windows.rst new file mode 100644 index 0000000..e3ea491 --- /dev/null +++ b/Help/release/dev/create_symlink-windows.rst @@ -0,0 +1,5 @@ +create_symlink-windows +------------------------- + +* The :manual:`cmake(1)` ``-E create_symlink`` command can now be used + on Windows. diff --git a/Help/release/dev/custom_command-working_directory-genex.rst b/Help/release/dev/custom_command-working_directory-genex.rst new file mode 100644 index 0000000..ae06202 --- /dev/null +++ b/Help/release/dev/custom_command-working_directory-genex.rst @@ -0,0 +1,5 @@ +custom_command-working_directory-genex +-------------------------------------- + +* The :command:`add_custom_command` and :command:`add_custom_target` commands + learned to support generator expressions in ``WORKING_DIRECTORY`` options. diff --git a/Help/release/dev/deprecate-policy-old.rst b/Help/release/dev/deprecate-policy-old.rst new file mode 100644 index 0000000..7e9862f --- /dev/null +++ b/Help/release/dev/deprecate-policy-old.rst @@ -0,0 +1,8 @@ +deprecate-policy-old +-------------------- + +* An explicit deprecation diagnostic was added for policies ``CMP0055`` + through ``CMP0063`` (``CMP0054`` and below were already deprecated). + The :manual:`cmake-policies(7)` manual explains that the OLD behaviors + of all policies are deprecated and that projects should port to the + NEW behaviors. 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/release/dev/vs-global-props-for-all-targets.rst b/Help/release/dev/vs-global-props-for-all-targets.rst new file mode 100644 index 0000000..647949e --- /dev/null +++ b/Help/release/dev/vs-global-props-for-all-targets.rst @@ -0,0 +1,6 @@ +vs-global-props-for-all-targets +------------------------------- + +* A :variable:`CMAKE_VS_GLOBALS` variable was added to initialize + :prop_tgt:`VS_GLOBAL_<variable>` target properties on targets as + they are created. diff --git a/Help/release/dev/vs-ipo.rst b/Help/release/dev/vs-ipo.rst new file mode 100644 index 0000000..a31601f --- /dev/null +++ b/Help/release/dev/vs-ipo.rst @@ -0,0 +1,6 @@ +vs-ipo +------ + +* The :ref:`Visual Studio Generators` for VS 2010 and above learned to + support the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` target property + and supporting :module:`CheckIPOSupported` module. 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/Help/variable/CMAKE_RULE_MESSAGES.rst b/Help/variable/CMAKE_RULE_MESSAGES.rst new file mode 100644 index 0000000..7460a81 --- /dev/null +++ b/Help/variable/CMAKE_RULE_MESSAGES.rst @@ -0,0 +1,8 @@ +CMAKE_RULE_MESSAGES +------------------- + +Specify whether to report a message for each make rule. + +If set in the cache it is used to initialize the value of the :prop_gbl:`RULE_MESSAGES` property. +Users may disable the option in their local build tree to disable granular messages +and report only as each target completes in Makefile builds. diff --git a/Help/variable/CMAKE_VS_GLOBALS.rst b/Help/variable/CMAKE_VS_GLOBALS.rst new file mode 100644 index 0000000..83777b6 --- /dev/null +++ b/Help/variable/CMAKE_VS_GLOBALS.rst @@ -0,0 +1,21 @@ +CMAKE_VS_GLOBALS +---------------- + +List of ``Key=Value`` records to be set per target as target properties +:prop_tgt:`VS_GLOBAL_<variable>` with ``variable=Key`` and value ``Value``. + +For example: + +.. code-block:: cmake + + set(CMAKE_VS_GLOBALS + "DefaultLanguage=en-US" + "MinimumVisualStudioVersion=14.0" + ) + +will set properties ``VS_GLOBAL_DefaultLanguage`` to ``en-US`` and +``VS_GLOBAL_MinimumVisualStudioVersion`` to ``14.0`` for all targets +(except for ``INTERFACE`` libraries). + +This variable is meant to be set by a +:variable:`toolchain file <CMAKE_TOOLCHAIN_FILE>`. diff --git a/Modules/BundleUtilities.cmake b/Modules/BundleUtilities.cmake index 4727f03..31db25a 100644 --- a/Modules/BundleUtilities.cmake +++ b/Modules/BundleUtilities.cmake @@ -1,223 +1,242 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. -#.rst: -# BundleUtilities -# --------------- -# -# Functions to help assemble a standalone bundle application. -# -# A collection of CMake utility functions useful for dealing with .app -# bundles on the Mac and bundle-like directories on any OS. -# -# The following functions are provided by this module: -# -# :: -# -# fixup_bundle -# copy_and_fixup_bundle -# verify_app -# get_bundle_main_executable -# get_dotapp_dir -# get_bundle_and_executable -# get_bundle_all_executables -# get_item_key -# get_item_rpaths -# clear_bundle_keys -# set_bundle_key_values -# get_bundle_keys -# copy_resolved_item_into_bundle -# copy_resolved_framework_into_bundle -# fixup_bundle_item -# verify_bundle_prerequisites -# verify_bundle_symlinks -# -# Requires CMake 2.6 or greater because it uses function, break and -# PARENT_SCOPE. Also depends on GetPrerequisites.cmake. -# -# :: -# -# FIXUP_BUNDLE(<app> <libs> <dirs>) -# -# Fix up a bundle in-place and make it standalone, such that it can be -# drag-n-drop copied to another machine and run on that machine as long -# as all of the system libraries are compatible. -# -# If you pass plugins to fixup_bundle as the libs parameter, you should -# install them or copy them into the bundle before calling fixup_bundle. -# The "libs" parameter is a list of libraries that must be fixed up, but -# that cannot be determined by otool output analysis. (i.e., plugins) -# -# Gather all the keys for all the executables and libraries in a bundle, -# and then, for each key, copy each prerequisite into the bundle. Then -# fix each one up according to its own list of prerequisites. -# -# Then clear all the keys and call verify_app on the final bundle to -# ensure that it is truly standalone. -# -# As an optional parameter (IGNORE_ITEM) a list of file names can be passed, -# which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") -# -# :: -# -# COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>) -# -# Makes a copy of the bundle <src> at location <dst> and then fixes up -# the new copied bundle in-place at <dst>... -# -# :: -# -# VERIFY_APP(<app>) -# -# Verifies that an application <app> appears valid based on running -# analysis tools on it. Calls "message(FATAL_ERROR" if the application -# is not verified. -# -# As an optional parameter (IGNORE_ITEM) a list of file names can be passed, -# which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") -# -# :: -# -# GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>) -# -# The result will be the full path name of the bundle's main executable -# file or an "error:" prefixed string if it could not be determined. -# -# :: -# -# GET_DOTAPP_DIR(<exe> <dotapp_dir_var>) -# -# Returns the nearest parent dir whose name ends with ".app" given the -# full path to an executable. If there is no such parent dir, then -# simply return the dir containing the executable. -# -# The returned directory may or may not exist. -# -# :: -# -# GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>) -# -# Takes either a ".app" directory name or the name of an executable -# nested inside a ".app" directory and returns the path to the ".app" -# directory in <bundle_var> and the path to its main executable in -# <executable_var> -# -# :: -# -# GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>) -# -# Scans the given bundle recursively for all executable files and -# accumulates them into a variable. -# -# :: -# -# GET_ITEM_KEY(<item> <key_var>) -# -# Given a file (item) name, generate a key that should be unique -# considering the set of libraries that need copying or fixing up to -# make a bundle standalone. This is essentially the file name including -# extension with "." replaced by "_" -# -# This key is used as a prefix for CMake variables so that we can -# associate a set of variables with a given item based on its key. -# -# :: -# -# CLEAR_BUNDLE_KEYS(<keys_var>) -# -# Loop over the list of keys, clearing all the variables associated with -# each key. After the loop, clear the list of keys itself. -# -# Caller of get_bundle_keys should call clear_bundle_keys when done with -# list of keys. -# -# :: -# -# SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs> -# <copyflag> [<rpaths>]) -# -# Add a key to the list (if necessary) for the given item. If added, -# also set all the variables associated with that key. -# -# :: -# -# GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>) -# -# Loop over all the executable and library files within the bundle (and -# given as extra <libs>) and accumulate a list of keys representing -# them. Set values associated with each key such that we can loop over -# all of them and copy prerequisite libs into the bundle and then do -# appropriate install_name_tool fixups. -# -# As an optional parameter (IGNORE_ITEM) a list of file names can be passed, -# which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") -# -# :: -# -# COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>) -# -# Copy a resolved item into the bundle if necessary. Copy is not -# necessary if the resolved_item is "the same as" the -# resolved_embedded_item. -# -# :: -# -# COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>) -# -# Copy a resolved framework into the bundle if necessary. Copy is not -# necessary if the resolved_item is "the same as" the -# resolved_embedded_item. -# -# By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want -# full frameworks embedded in your bundles, set -# BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By -# default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework -# dylib itself plus the framework Resources directory. -# -# :: -# -# FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>) -# -# Get the direct/non-system prerequisites of the resolved embedded item. -# For each prerequisite, change the way it is referenced to the value of -# the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely -# changing to an "@executable_path" style reference.) -# -# This function requires that the resolved_embedded_item be "inside" the -# bundle already. In other words, if you pass plugins to fixup_bundle -# as the libs parameter, you should install them or copy them into the -# bundle before calling fixup_bundle. The "libs" parameter is a list of -# libraries that must be fixed up, but that cannot be determined by -# otool output analysis. (i.e., plugins) -# -# Also, change the id of the item being fixed up to its own -# _EMBEDDED_ITEM value. -# -# Accumulate changes in a local variable and make *one* call to -# install_name_tool at the end of the function with all the changes at -# once. -# -# If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be -# marked writable before install_name_tool tries to change them. -# -# :: -# -# VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>) -# -# Verifies that the sum of all prerequisites of all files inside the -# bundle are contained within the bundle or are "system" libraries, -# presumed to exist everywhere. -# -# As an optional parameter (IGNORE_ITEM) a list of file names can be passed, -# which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") -# -# :: -# -# VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>) -# -# Verifies that any symlinks found in the bundle point to other files -# that are already also in the bundle... Anything that points to an -# external file causes this function to fail the verification. +#[=======================================================================[.rst: +BundleUtilities +--------------- + +Functions to help assemble a standalone bundle application. + +A collection of CMake utility functions useful for dealing with .app +bundles on the Mac and bundle-like directories on any OS. + +The following functions are provided by this module: + +:: + + fixup_bundle + copy_and_fixup_bundle + verify_app + get_bundle_main_executable + get_dotapp_dir + get_bundle_and_executable + get_bundle_all_executables + get_item_key + get_item_rpaths + clear_bundle_keys + set_bundle_key_values + get_bundle_keys + copy_resolved_item_into_bundle + copy_resolved_framework_into_bundle + fixup_bundle_item + verify_bundle_prerequisites + verify_bundle_symlinks + +Requires CMake 2.6 or greater because it uses function, break and +PARENT_SCOPE. Also depends on GetPrerequisites.cmake. + +DO NOT USE THESE FUNCTIONS AT CONFIGURE TIME (from ``CMakeLists.txt``)! +Instead, invoke them from an :command:`install(CODE)` or +:command:`install(SCRIPT)` rule. + +:: + + FIXUP_BUNDLE(<app> <libs> <dirs>) + +Fix up a bundle in-place and make it standalone, such that it can be +drag-n-drop copied to another machine and run on that machine as long +as all of the system libraries are compatible. + +If you pass plugins to fixup_bundle as the libs parameter, you should +install them or copy them into the bundle before calling fixup_bundle. +The "libs" parameter is a list of libraries that must be fixed up, but +that cannot be determined by otool output analysis. (i.e., plugins) + +Gather all the keys for all the executables and libraries in a bundle, +and then, for each key, copy each prerequisite into the bundle. Then +fix each one up according to its own list of prerequisites. + +Then clear all the keys and call verify_app on the final bundle to +ensure that it is truly standalone. + +As an optional parameter (IGNORE_ITEM) a list of file names can be passed, +which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") + +:: + + COPY_AND_FIXUP_BUNDLE(<src> <dst> <libs> <dirs>) + +Makes a copy of the bundle <src> at location <dst> and then fixes up +the new copied bundle in-place at <dst>... + +:: + + VERIFY_APP(<app>) + +Verifies that an application <app> appears valid based on running +analysis tools on it. Calls "message(FATAL_ERROR" if the application +is not verified. + +As an optional parameter (IGNORE_ITEM) a list of file names can be passed, +which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") + +:: + + GET_BUNDLE_MAIN_EXECUTABLE(<bundle> <result_var>) + +The result will be the full path name of the bundle's main executable +file or an "error:" prefixed string if it could not be determined. + +:: + + GET_DOTAPP_DIR(<exe> <dotapp_dir_var>) + +Returns the nearest parent dir whose name ends with ".app" given the +full path to an executable. If there is no such parent dir, then +simply return the dir containing the executable. + +The returned directory may or may not exist. + +:: + + GET_BUNDLE_AND_EXECUTABLE(<app> <bundle_var> <executable_var> <valid_var>) + +Takes either a ".app" directory name or the name of an executable +nested inside a ".app" directory and returns the path to the ".app" +directory in <bundle_var> and the path to its main executable in +<executable_var> + +:: + + GET_BUNDLE_ALL_EXECUTABLES(<bundle> <exes_var>) + +Scans the given bundle recursively for all executable files and +accumulates them into a variable. + +:: + + GET_ITEM_KEY(<item> <key_var>) + +Given a file (item) name, generate a key that should be unique +considering the set of libraries that need copying or fixing up to +make a bundle standalone. This is essentially the file name including +extension with "." replaced by "_" + +This key is used as a prefix for CMake variables so that we can +associate a set of variables with a given item based on its key. + +:: + + CLEAR_BUNDLE_KEYS(<keys_var>) + +Loop over the list of keys, clearing all the variables associated with +each key. After the loop, clear the list of keys itself. + +Caller of get_bundle_keys should call clear_bundle_keys when done with +list of keys. + +:: + + SET_BUNDLE_KEY_VALUES(<keys_var> <context> <item> <exepath> <dirs> + <copyflag> [<rpaths>]) + +Add a key to the list (if necessary) for the given item. If added, +also set all the variables associated with that key. + +:: + + GET_BUNDLE_KEYS(<app> <libs> <dirs> <keys_var>) + +Loop over all the executable and library files within the bundle (and +given as extra <libs>) and accumulate a list of keys representing +them. Set values associated with each key such that we can loop over +all of them and copy prerequisite libs into the bundle and then do +appropriate install_name_tool fixups. + +As an optional parameter (IGNORE_ITEM) a list of file names can be passed, +which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") + +:: + + COPY_RESOLVED_ITEM_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>) + +Copy a resolved item into the bundle if necessary. Copy is not +necessary if the resolved_item is "the same as" the +resolved_embedded_item. + +:: + + COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE(<resolved_item> <resolved_embedded_item>) + +Copy a resolved framework into the bundle if necessary. Copy is not +necessary if the resolved_item is "the same as" the +resolved_embedded_item. + +By default, BU_COPY_FULL_FRAMEWORK_CONTENTS is not set. If you want +full frameworks embedded in your bundles, set +BU_COPY_FULL_FRAMEWORK_CONTENTS to ON before calling fixup_bundle. By +default, COPY_RESOLVED_FRAMEWORK_INTO_BUNDLE copies the framework +dylib itself plus the framework Resources directory. + +:: + + FIXUP_BUNDLE_ITEM(<resolved_embedded_item> <exepath> <dirs>) + +Get the direct/non-system prerequisites of the resolved embedded item. +For each prerequisite, change the way it is referenced to the value of +the _EMBEDDED_ITEM keyed variable for that prerequisite. (Most likely +changing to an "@executable_path" style reference.) + +This function requires that the resolved_embedded_item be "inside" the +bundle already. In other words, if you pass plugins to fixup_bundle +as the libs parameter, you should install them or copy them into the +bundle before calling fixup_bundle. The "libs" parameter is a list of +libraries that must be fixed up, but that cannot be determined by +otool output analysis. (i.e., plugins) + +Also, change the id of the item being fixed up to its own +_EMBEDDED_ITEM value. + +Accumulate changes in a local variable and make *one* call to +install_name_tool at the end of the function with all the changes at +once. + +If the BU_CHMOD_BUNDLE_ITEMS variable is set then bundle items will be +marked writable before install_name_tool tries to change them. + +:: + + VERIFY_BUNDLE_PREREQUISITES(<bundle> <result_var> <info_var>) + +Verifies that the sum of all prerequisites of all files inside the +bundle are contained within the bundle or are "system" libraries, +presumed to exist everywhere. + +As an optional parameter (IGNORE_ITEM) a list of file names can be passed, +which are then ignored (e.g. IGNORE_ITEM "vcredist_x86.exe;vcredist_x64.exe") + +:: + + VERIFY_BUNDLE_SYMLINKS(<bundle> <result_var> <info_var>) + +Verifies that any symlinks found in the bundle point to other files +that are already also in the bundle... Anything that points to an +external file causes this function to fail the verification. +#]=======================================================================] + +# Do not include this module at configure time! +if(DEFINED CMAKE_GENERATOR) + cmake_policy(GET CMP0080 _BundleUtilities_CMP0080) + if(_BundleUtilities_CMP0080 STREQUAL "NEW") + message(FATAL_ERROR "BundleUtilities cannot be included at configure time!") + elseif(NOT _BundleUtilities_CMP0080 STREQUAL "OLD") + message(AUTHOR_WARNING + "Policy CMP0080 is not set: BundleUtilities prefers not to be included at configure time. " + "Run \"cmake --help-policy CMP0080\" for policy details. " + "Use the cmake_policy command to set the policy and suppress this warning." + ) + endif() +endif() # The functions defined in this file depend on the get_prerequisites function # (and possibly others) found in: 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/CheckIPOSupported.cmake b/Modules/CheckIPOSupported.cmake index 3344834..ad8852c 100644 --- a/Modules/CheckIPOSupported.cmake +++ b/Modules/CheckIPOSupported.cmake @@ -226,7 +226,7 @@ function(check_ipo_supported) endif() endforeach() - if(CMAKE_GENERATOR MATCHES "^Visual Studio ") + if(CMAKE_GENERATOR MATCHES "^Visual Studio 9 ") _ipo_not_supported("CMake doesn't support IPO for current generator") return() endif() diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index 1650e55..3527979 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -43,7 +43,7 @@ # matches what is needed by the CUDA runtime version. # # The following variables affect the behavior of the macros in the -# script (in alphebetical order). Note that any of these flags can be +# script (in alphabetical order). Note that any of these flags can be # changed multiple times in the same directory before calling # ``CUDA_ADD_EXECUTABLE``, ``CUDA_ADD_LIBRARY``, ``CUDA_COMPILE``, # ``CUDA_COMPILE_PTX``, ``CUDA_COMPILE_FATBIN``, ``CUDA_COMPILE_CUBIN`` @@ -105,6 +105,8 @@ # the host compiler is constructed with one or more visual studio macros # such as $(VCInstallDir), that expands out to the path when # the command is run from within VS. +# If the CUDAHOSTCXX environment variable is set it will +# be used as the default. # # CUDA_NVCC_FLAGS # CUDA_NVCC_FLAGS_<CONFIG> @@ -147,7 +149,7 @@ # VERBOSE=1 to see output), although setting CUDA_VERBOSE_BUILD to ON will # always print the output. # -# The script creates the following macros (in alphebetical order):: +# The script creates the following macros (in alphabetical order):: # # CUDA_ADD_CUFFT_TO_TARGET( cuda_target ) # -- Adds the cufft library to the target (can be any target). Handles whether @@ -527,7 +529,9 @@ option(CUDA_HOST_COMPILATION_CPP "Generated file extension" ON) # Extra user settable flags cmake_initialize_per_config_variable(CUDA_NVCC_FLAGS "Semi-colon delimit multiple arguments.") -if(CMAKE_GENERATOR MATCHES "Visual Studio") +if(DEFINED ENV{CUDAHOSTCXX}) + set(CUDA_HOST_COMPILER "$ENV{CUDAHOSTCXX}" CACHE FILEPATH "Host side compiler used by NVCC") +elseif(CMAKE_GENERATOR MATCHES "Visual Studio") set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)Tools/MSVC/$(VCToolsVersion)/bin/Host$(Platform)/$(PlatformTarget)") if(MSVC_VERSION LESS 1910) set(_CUDA_MSVC_HOST_COMPILER "$(VCInstallDir)bin") diff --git a/Modules/FindCUDA/select_compute_arch.cmake b/Modules/FindCUDA/select_compute_arch.cmake index cf4fc39..1baf051 100644 --- a/Modules/FindCUDA/select_compute_arch.cmake +++ b/Modules/FindCUDA/select_compute_arch.cmake @@ -109,6 +109,9 @@ function(CUDA_DETECT_INSTALLED_GPUS OUT_VARIABLE) RUN_OUTPUT_VARIABLE compute_capabilities) endif() + # Filter unrelated content out of the output. + string(REGEX MATCHALL "[0-9]+\\.[0-9]+" compute_capabilities "${compute_capabilities}") + if(run_result EQUAL 0) string(REPLACE "2.1" "2.1(2.0)" compute_capabilities "${compute_capabilities}") set(CUDA_GPU_DETECT_OUTPUT ${compute_capabilities} 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/FindPython.cmake b/Modules/FindPython.cmake index 8139e53..0bf0b4f 100644 --- a/Modules/FindPython.cmake +++ b/Modules/FindPython.cmake @@ -116,6 +116,25 @@ Hints * If set to TRUE, search **only** for static libraries. * If set to FALSE, search **only** for shared libraries. +``Python_FIND_REGISTRY`` + On Windows the ``Python_FIND_REGISTRY`` variable determine the order + of preference between registry and environment variables. + the ``Python_FIND_REGISTRY`` variable can be set to empty or one of the + following: + + * ``FIRST``: Try to use registry before environment variables. + This is the default. + * ``LAST``: Try to use registry after environment variables. + * ``NEVER``: Never try to use registry. + +``CMAKE_FIND_FRAMEWORK`` + On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of + preference between Apple-style and unix-style package components. + + .. note:: + + Value ``ONLY`` is not supported so ``FIRST`` will be used instead. + Commands ^^^^^^^^ diff --git a/Modules/FindPython/Support.cmake b/Modules/FindPython/Support.cmake index fe3df91..1834591 100644 --- a/Modules/FindPython/Support.cmake +++ b/Modules/FindPython/Support.cmake @@ -44,9 +44,28 @@ macro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG) endmacro() +macro (_PYTHON_FIND_FRAMEWORKS) + set (${_PYTHON_PREFIX}_FRAMEWORKS) + if (APPLE) + set (_pff_frameworks ${CMAKE_FRAMEWORK_PATH} + $ENV{CMAKE_FRAMEWORK_PATH} + ~/Library/Frameworks + /usr/local/Frameworks + ${CMAKE_SYSTEM_FRAMEWORK_PATH}) + list (REMOVE_DUPLICATES _pff_frameworks) + foreach (_pff_framework IN LISTS _pff_frameworks) + if (EXISTS ${_pff_framework}/Python.framework) + list (APPEND ${_PYTHON_PREFIX}_FRAMEWORKS ${_pff_framework}/Python.framework) + endif() + endforeach() + unset (_pff_frameworks) + unset (_pff_framework) + endif() +endmacro() + function (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS _PYTHON_VERSION) set (_PYTHON_FRAMEWORK_PATHS) - foreach (_PYTHON_FRAMEWORK IN LISTS Python_FRAMEWORKS) + foreach (_PYTHON_FRAMEWORK IN LISTS ${_PYTHON_PREFIX}_FRAMEWORKS) list (APPEND _PYTHON_FRAMEWORK_PATHS "${_PYTHON_FRAMEWORK}/Versions/${_PYTHON_VERSION}") endforeach() @@ -59,20 +78,43 @@ function (_PYTHON_VALIDATE_INTERPRETER) return() endif() - if (${_PYTHON_PREFIX}_EXECUTABLE MATCHES "python${CMAKE_EXECUTABLE_SUFFIX}$") - # executable found do not have version in name - # ensure major version is OK + if (ARGC EQUAL 1) + set (expected_version ${ARGV0}) + else() + unset (expected_version) + endif() + + get_filename_component (python_name "${${_PYTHON_PREFIX}_EXECUTABLE}" NAME) + + if (expected_version AND NOT python_name STREQUAL "python${expected_version}${CMAKE_EXECUTABLE_SUFFIX}") + # executable found must have a specific version execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c - "import sys; sys.stdout.write(str(sys.version_info[0]))" + "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))" RESULT_VARIABLE result OUTPUT_VARIABLE version ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + if (result OR NOT version EQUAL expected_version) # interpreter not usable or has wrong major version set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE) return() endif() + else() + if (NOT python_name STREQUAL "python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}${CMAKE_EXECUTABLE_SUFFIX}") + # executable found do not have version in name + # ensure major version is OK + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; sys.stdout.write(str(sys.version_info[0]))" + RESULT_VARIABLE result + OUTPUT_VARIABLE version + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + # interpreter not usable or has wrong major version + set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE) + return() + endif() + endif() endif() if (CMAKE_SIZEOF_VOID_P AND "Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS @@ -93,6 +135,33 @@ function (_PYTHON_VALIDATE_INTERPRETER) endfunction() +function (_PYTHON_VALIDATE_COMPILER expected_version) + if (NOT ${_PYTHON_PREFIX}_COMPILER) + return() + endif() + + # retrieve python environment version from compiler + set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir") + file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))\n") + execute_process (COMMAND "${${_PYTHON_PREFIX}_COMPILER}" /target:exe /embed "${working_dir}/version.py" + WORKING_DIRECTORY "${working_dir}" + OUTPUT_QUIET + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process (COMMAND "${working_dir}/version" + WORKING_DIRECTORY "${working_dir}" + RESULT_VARIABLE result + OUTPUT_VARIABLE version + ERROR_QUIET) + file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}") + + if (result OR NOT version EQUAL expected_version) + # Compiler not usable or has wrong major version + set (${_PYTHON_PREFIX}_COMPILER ${_PYTHON_PREFIX}_COMPILER-NOTFOUND CACHE INTERNAL "" FORCE) + endif() +endfunction() + + function (_PYTHON_FIND_RUNTIME_LIBRARY _PYTHON_LIB) string (REPLACE "_RUNTIME" "" _PYTHON_LIB "${_PYTHON_LIB}") # look at runtime part on systems supporting it @@ -181,19 +250,47 @@ else() # architecture unknown, search for natural interpreter set (_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES ipy) endif() +set (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40) # Apple frameworks handling -include (${CMAKE_CURRENT_LIST_DIR}/../CMakeFindFrameworks.cmake) -cmake_find_frameworks (Python) +_python_find_frameworks () + +# Save CMAKE_FIND_APPBUNDLE +if (DEFINED CMAKE_FIND_APPBUNDLE) + set (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE}) +else() + unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) +endif() +# To avoid app bundle lookup +set (CMAKE_FIND_APPBUNDLE "NEVER") # Save CMAKE_FIND_FRAMEWORK if (DEFINED CMAKE_FIND_FRAMEWORK) set (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) + if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY") + message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.") + set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST") + else() + set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) + endif() else() unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) + set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST") +endif() +# To avoid framework lookup +set (CMAKE_FIND_FRAMEWORK "NEVER") + +# Windows Registry handling +if (DEFINED ${_PYTHON_PREFIX}_FIND_REGISTRY) + if (NOT ${_PYTHON_PREFIX}_FIND_REGISTRY MATCHES "^(FIRST|LAST|NEVER)$") + message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected.") + set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST") + else() + set (_${_PYTHON_PREFIX}_FIND_REGISTRY ${${_PYTHON_PREFIX}_FIND_REGISTRY}) + endif() +else() + set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST") endif() -# To avoid picking up the system elements pre-maturely. -set (CMAKE_FIND_FRAMEWORK LAST) unset (_${_PYTHON_PREFIX}_REQUIRED_VARS) @@ -215,22 +312,83 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION}) + # Apple frameworks handling + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + NAMES_PER_DIR + PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + PATH_SUFFIXES bin + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + # Windows registry + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + # try using HINTS find_program (${_PYTHON_PREFIX}_EXECUTABLE NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} PATH_SUFFIXES bin NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) - # try using registry - if (WIN32) + # try using standard paths. + # NAMES_PER_DIR is not defined on purpose to have a chance to find + # expected version. + # For example, typical systems have 'python' for version 2.* and 'python3' + # for version 3.*. So looking for names per dir will find, potentially, + # systematically 'python' (i.e. version 2) even if version 3 is searched. + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}) + + # Apple frameworks handling + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") find_program (${_PYTHON_PREFIX}_EXECUTABLE - NAMES python${_${_PYTHON_PREFIX}_VERSION} python + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + NAMES_PER_DIR + PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + PATH_SUFFIXES bin + NO_DEFAULT_PATH) + endif() + + # Windows registry + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] @@ -238,27 +396,37 @@ if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - PATH_SUFFIXES bin - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) + PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_DEFAULT_PATH) endif() - # try in standard paths - find_program (${_PYTHON_PREFIX}_EXECUTABLE - NAMES python${_${_PYTHON_PREFIX}_VERSION}) - _python_validate_interpreter () + _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION}) if (${_PYTHON_PREFIX}_EXECUTABLE) break() endif() endforeach() - # try more generic names if (NOT ${_PYTHON_PREFIX}_EXECUTABLE) + # No specific version found. Retry with generic names + # try using HINTS find_program (${_PYTHON_PREFIX}_EXECUTABLE - NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} python + NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATH_SUFFIXES bin) + PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + # try using standard paths. + # NAMES_PER_DIR is not defined on purpose to have a chance to find + # expected version. + # For example, typical systems have 'python' for version 2.* and 'python3' + # for version 3.*. So looking for names per dir will find, potentially, + # systematically 'python' (i.e. version 2) even if version 3 is searched. + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}) _python_validate_interpreter () endif() @@ -359,19 +527,42 @@ if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) # try using root dir and registry foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) + if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_program (${_PYTHON_PREFIX}_COMPILER + NAMES ipyc + HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} + PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + find_program (${_PYTHON_PREFIX}_COMPILER NAMES ipyc HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} - PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) + + if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") + find_program (${_PYTHON_PREFIX}_COMPILER + NAMES ipyc + PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_DEFAULT_PATH) + endif() + + _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION}) if (${_PYTHON_PREFIX}_COMPILER) break() endif() endforeach() - # try in standard paths + + # no specific version found, re-try in standard paths find_program (${_PYTHON_PREFIX}_COMPILER - NAMES ipyc) + NAMES ipyc + HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}) if (${_PYTHON_PREFIX}_COMPILER) # retrieve python environment version from compiler @@ -483,6 +674,7 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "python${_${_PYTHON_PREFIX}_VERSION}-config") find_program (_${_PYTHON_PREFIX}_CONFIG NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} + NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} PATH_SUFFIXES bin) unset (_${_PYTHON_PREFIX}_CONFIG_NAMES) @@ -571,7 +763,54 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION}) - # search first in known locations + set (_${_PYTHON_PREFIX}_REGISTRY_PATHS + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath]) + + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") + find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} + python${_${_PYTHON_PREFIX}_VERSION}mu + python${_${_PYTHON_PREFIX}_VERSION}m + python${_${_PYTHON_PREFIX}_VERSION}u + python${_${_PYTHON_PREFIX}_VERSION} + NAMES_PER_DIR + PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION} + lib/python${_${_PYTHON_PREFIX}_VERSION}/config + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} + python${_${_PYTHON_PREFIX}_VERSION}mu + python${_${_PYTHON_PREFIX}_VERSION}m + python${_${_PYTHON_PREFIX}_VERSION}u + python${_${_PYTHON_PREFIX}_VERSION} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION} + lib/python${_${_PYTHON_PREFIX}_VERSION}/config + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + # search in HINTS locations find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} python${_${_PYTHON_PREFIX}_VERSION}mu @@ -580,11 +819,6 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS python${_${_PYTHON_PREFIX}_VERSION} NAMES_PER_DIR HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m @@ -593,6 +827,19 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS lib/python${_${_PYTHON_PREFIX}_VERSION}/config NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH) + + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") + set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}) + else() + unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS) + endif() + + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") + set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}) + else() + unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS) + endif() + # search in all default paths find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} @@ -601,6 +848,8 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS python${_${_PYTHON_PREFIX}_VERSION}u python${_${_PYTHON_PREFIX}_VERSION} NAMES_PER_DIR + PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m @@ -618,11 +867,6 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS python${_${_PYTHON_PREFIX}_VERSION} NAMES_PER_DIR HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] PATH_SUFFIXES bin) endif() @@ -632,27 +876,28 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS # use library location as a hint get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG - NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d - NAMES_PER_DIR - HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} - NO_DEFAULT_PATH) - else() - # search first in known locations - find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d NAMES_PER_DIR - HINTS ${_${_PYTHON_PREFIX}_HINTS} - PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - PATH_SUFFIXES lib libs - NO_SYSTEM_ENVIRONMENT_PATH - NO_CMAKE_SYSTEM_PATH) + HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} + NO_DEFAULT_PATH) + else() + # search first in known locations + if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES lib libs + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() # search in all default paths find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES lib libs) endif() if (${_PYTHON_PREFIX}_LIBRARY_DEBUG) @@ -661,10 +906,6 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d NAMES_PER_DIR HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} - PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] PATH_SUFFIXES bin) endif() endif() @@ -672,6 +913,21 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS # Don't search for include dir until library location is known if (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS) + + if (${_PYTHON_PREFIX}_EXECUTABLE) + # pick up include directory from configuration + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; import sysconfig; sys.stdout.write(sysconfig.get_path('include'))" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PATH + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT _${_PYTHON_PREFIX}_RESULT) + file (TO_CMAKE_PATH "${_${_PYTHON_PREFIX}_PATH}" _${_PYTHON_PREFIX}_PATH) + list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PATH}") + endif() + endif() + foreach (_${_PYTHON_PREFIX}_LIB IN ITEMS ${_PYTHON_PREFIX}_LIBRARY_RELEASE ${_PYTHON_PREFIX}_LIBRARY_DEBUG) if (${_${_PYTHON_PREFIX}_LIB}) # Use the library's install prefix as a hint @@ -691,14 +947,41 @@ if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS endforeach() list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_INCLUDE_HINTS) + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") + find_path (${_PYTHON_PREFIX}_INCLUDE_DIR + NAMES Python.h + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu + include/python${_${_PYTHON_PREFIX}_VERSION}m + include/python${_${_PYTHON_PREFIX}_VERSION}u + include/python${_${_PYTHON_PREFIX}_VERSION} + include + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_path (${_PYTHON_PREFIX}_INCLUDE_DIR + NAMES Python.h + HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu + include/python${_${_PYTHON_PREFIX}_VERSION}m + include/python${_${_PYTHON_PREFIX}_VERSION}u + include/python${_${_PYTHON_PREFIX}_VERSION} + include + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + find_path (${_PYTHON_PREFIX}_INCLUDE_DIR NAMES Python.h HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} - PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] - [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu include/python${_${_PYTHON_PREFIX}_VERSION}m include/python${_${_PYTHON_PREFIX}_VERSION}u @@ -914,6 +1197,13 @@ endif() # final clean-up +# Restore CMAKE_FIND_APPBUNDLE +if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) + set (CMAKE_FIND_APPBUNDLE ${_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE}) + unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) +else() + unset (CMAKE_FIND_APPBUNDLE) +endif() # Restore CMAKE_FIND_FRAMEWORK if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) set (CMAKE_FIND_FRAMEWORK ${_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK}) diff --git a/Modules/FindPython2.cmake b/Modules/FindPython2.cmake index 22e9a8f..2735a25 100644 --- a/Modules/FindPython2.cmake +++ b/Modules/FindPython2.cmake @@ -117,6 +117,25 @@ Hints * If set to TRUE, search **only** for static libraries. * If set to FALSE, search **only** for shared libraries. +``Python2_FIND_REGISTRY`` + On Windows the ``Python2_FIND_REGISTRY`` variable determine the order + of preference between registry and environment variables. + the ``Python2_FIND_REGISTRY`` variable can be set to empty or one of the + following: + + * ``FIRST``: Try to use registry before environment variables. + This is the default. + * ``LAST``: Try to use registry after environment variables. + * ``NEVER``: Never try to use registry. + +``CMAKE_FIND_FRAMEWORK`` + On macOS the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of + preference between Apple-style and unix-style package components. + + .. note:: + + Value ``ONLY`` is not supported so ``FIRST`` will be used instead. + Commands ^^^^^^^^ diff --git a/Modules/FindPython3.cmake b/Modules/FindPython3.cmake index 99c159b..ed7e1a3 100644 --- a/Modules/FindPython3.cmake +++ b/Modules/FindPython3.cmake @@ -117,6 +117,25 @@ Hints * If set to TRUE, search **only** for static libraries. * If set to FALSE, search **only** for shared libraries. +``Python3_FIND_REGISTRY`` + On Windows the ``Python3_FIND_REGISTRY`` variable determine the order + of preference between registry and environment variables. + the ``Python3_FIND_REGISTRY`` variable can be set to empty or one of the + following: + + * ``FIRST``: Try to use registry before environment variables. + This is the default. + * ``LAST``: Try to use registry after environment variables. + * ``NEVER``: Never try to use registry. + +``CMAKE_FIND_FRAMEWORK`` + On OS X the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of + preference between Apple-style and unix-style package components. + + .. note:: + + Value ``ONLY`` is not supported so ``FIRST`` will be used instead. + Commands ^^^^^^^^ 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 ee31122..408cc7d 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 20180916) +set(CMake_VERSION_PATCH 20181001) #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/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 8863dc8..667a8ba 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -151,9 +151,9 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, cmSystemTools::CollapseFullPath(this->Values[ct_BUILD]).c_str(), this->Quiet); } else { - const char* bdir = + std::string const& bdir = this->Makefile->GetSafeDefinition("CTEST_BINARY_DIRECTORY"); - if (bdir) { + if (!bdir.empty()) { this->CTest->SetCTestConfiguration( "BuildDirectory", cmSystemTools::CollapseFullPath(bdir).c_str(), this->Quiet); diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index cbed40e..c7f3f39 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -425,6 +425,29 @@ bool cmCTestSubmitHandler::SubmitUsingHTTP(const std::string& localprefix, ((url.find('?') == std::string::npos) ? '?' : '&') + "FileName=" + ofile; + cmCTestCurl ctest_curl(this->CTest); + upload_as += "&build="; + upload_as += + ctest_curl.Escape(this->CTest->GetCTestConfiguration("BuildName")); + upload_as += "&site="; + upload_as += + ctest_curl.Escape(this->CTest->GetCTestConfiguration("Site")); + upload_as += "&stamp="; + upload_as += ctest_curl.Escape(this->CTest->GetCurrentTag()); + upload_as += "-"; + upload_as += ctest_curl.Escape(this->CTest->GetTestModelString()); + cmCTestScriptHandler* ch = + static_cast<cmCTestScriptHandler*>(this->CTest->GetHandler("script")); + cmake* cm = ch->GetCMake(); + if (cm) { + const char* subproject = + cm->GetState()->GetGlobalProperty("SubProject"); + if (subproject) { + upload_as += "&subproject="; + upload_as += ctest_curl.Escape(subproject); + } + } + upload_as += "&MD5="; if (cmSystemTools::IsOn(this->GetOption("InternalTest"))) { diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index 2646c9a..7b980a0 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -150,7 +150,7 @@ int main(int argc, char** argv) typedef cmsys::CommandLineArguments argT; arg.AddArgument("-B", argT::CONCAT_ARGUMENT, &binaryDirectory, "Binary Directory"); - arg.AddArgument("-H", argT::CONCAT_ARGUMENT, &sourceDirectory, + arg.AddArgument("-S", argT::CONCAT_ARGUMENT, &sourceDirectory, "Source Directory"); // do not complain about unknown options arg.StoreUnusedArguments(true); 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 2107d32..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( @@ -1725,7 +1724,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, } const char* stagePath = this->Makefile->GetDefinition("CMAKE_STAGING_PREFIX"); - const char* installPrefix = + std::string const& installPrefix = this->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); cmSystemTools::ConvertToUnixSlashes(rootPath); std::vector<std::string> const& rdirs = this->GetRuntimeSearchPath(); diff --git a/Source/cmCustomCommandGenerator.cxx b/Source/cmCustomCommandGenerator.cxx index 6c9f9d6..5bbae17 100644 --- a/Source/cmCustomCommandGenerator.cxx +++ b/Source/cmCustomCommandGenerator.cxx @@ -64,6 +64,13 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(cmCustomCommand const& cc, } this->Depends.insert(this->Depends.end(), result.begin(), result.end()); } + + const std::string& workingdirectory = this->CC.GetWorkingDirectory(); + if (!workingdirectory.empty()) { + std::unique_ptr<cmCompiledGeneratorExpression> cge = + this->GE->Parse(workingdirectory); + this->WorkingDirectory = cge->Evaluate(this->LG, this->Config); + } } cmCustomCommandGenerator::~cmCustomCommandGenerator() @@ -186,7 +193,7 @@ const char* cmCustomCommandGenerator::GetComment() const std::string cmCustomCommandGenerator::GetWorkingDirectory() const { - return this->CC.GetWorkingDirectory(); + return this->WorkingDirectory; } std::vector<std::string> const& cmCustomCommandGenerator::GetOutputs() const diff --git a/Source/cmCustomCommandGenerator.h b/Source/cmCustomCommandGenerator.h index 34fd653..b7e2a39 100644 --- a/Source/cmCustomCommandGenerator.h +++ b/Source/cmCustomCommandGenerator.h @@ -23,6 +23,7 @@ class cmCustomCommandGenerator cmGeneratorExpression* GE; cmCustomCommandLines CommandLines; std::vector<std::string> Depends; + std::string WorkingDirectory; const char* GetCrossCompilingEmulator(unsigned int c) const; const char* GetArgv0Location(unsigned int c) const; diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index 4716e14..6f1afd7 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -36,7 +36,7 @@ bool cmDepends::Write(std::ostream& makeDepends, std::ostream& internalDepends) std::string srcLang = "CMAKE_DEPENDS_CHECK_"; srcLang += this->Language; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - const char* srcStr = mf->GetSafeDefinition(srcLang); + std::string const& srcStr = mf->GetSafeDefinition(srcLang); std::vector<std::string> pairs; cmSystemTools::ExpandListArgument(srcStr, pairs); 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 67df6fd..4cf9dd7 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -195,7 +195,7 @@ static bool checkInterfaceDirs(const std::string& prepro, cmGeneratorTarget* target, const std::string& prop) { - const char* installDir = + std::string const& installDir = target->Makefile->GetSafeDefinition("CMAKE_INSTALL_PREFIX"); std::string const& topSourceDir = target->GetLocalGenerator()->GetSourceDirectory(); @@ -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/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index fbf6560..07a60de 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -666,7 +666,7 @@ std::string cmExtraCodeBlocksGenerator::GetCBCompilerId(const cmMakefile* mf) pureFortran = true; } - std::string compilerId = mf->GetSafeDefinition(compilerIdVar); + std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar); std::string compiler = "gcc"; // default to gcc if (compilerId == "MSVC") { if (mf->IsDefinitionSet("MSVC10")) { diff --git a/Source/cmExtraCodeLiteGenerator.cxx b/Source/cmExtraCodeLiteGenerator.cxx index fe5c7bb..28106d1 100644 --- a/Source/cmExtraCodeLiteGenerator.cxx +++ b/Source/cmExtraCodeLiteGenerator.cxx @@ -599,7 +599,7 @@ std::string cmExtraCodeLiteGenerator::GetCodeLiteCompilerName( compilerIdVar = "CMAKE_C_COMPILER_ID"; } - std::string compilerId = mf->GetSafeDefinition(compilerIdVar); + std::string const& compilerId = mf->GetSafeDefinition(compilerIdVar); std::string compiler = "gnu g++"; // default to g++ // Since we need the compiler for parsing purposes only 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/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 16ac88c..f901215 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -580,10 +580,11 @@ struct CompilerIdNode : public cmGeneratorExpressionNode cmGeneratorExpressionDAGChecker* /*unused*/, const std::string& lang) const { - const char* compilerId = context->LG->GetMakefile()->GetSafeDefinition( - "CMAKE_" + lang + "_COMPILER_ID"); + std::string const& compilerId = + context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang + + "_COMPILER_ID"); if (parameters.empty()) { - return compilerId ? compilerId : ""; + return compilerId; } static cmsys::RegularExpression compilerIdValidator("^[A-Za-z0-9_]*$"); if (!compilerIdValidator.find(*parameters.begin())) { @@ -591,15 +592,16 @@ struct CompilerIdNode : public cmGeneratorExpressionNode "Expression syntax not recognized."); return std::string(); } - if (!compilerId) { + if (compilerId.empty()) { return parameters.front().empty() ? "1" : "0"; } - if (strcmp(parameters.begin()->c_str(), compilerId) == 0) { + if (strcmp(parameters.begin()->c_str(), compilerId.c_str()) == 0) { return "1"; } - if (cmsysString_strcasecmp(parameters.begin()->c_str(), compilerId) == 0) { + if (cmsysString_strcasecmp(parameters.begin()->c_str(), + compilerId.c_str()) == 0) { switch (context->LG->GetPolicyStatus(cmPolicies::CMP0044)) { case cmPolicies::WARN: { std::ostringstream e; @@ -676,11 +678,11 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode cmGeneratorExpressionDAGChecker* /*unused*/, const std::string& lang) const { - const char* compilerVersion = + std::string const& compilerVersion = context->LG->GetMakefile()->GetSafeDefinition("CMAKE_" + lang + "_COMPILER_VERSION"); if (parameters.empty()) { - return compilerVersion ? compilerVersion : ""; + return compilerVersion; } static cmsys::RegularExpression compilerIdValidator("^[0-9\\.]*$"); @@ -689,13 +691,13 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode "Expression syntax not recognized."); return std::string(); } - if (!compilerVersion) { + if (compilerVersion.empty()) { return parameters.front().empty() ? "1" : "0"; } return cmSystemTools::VersionCompare(cmSystemTools::OP_EQUAL, parameters.begin()->c_str(), - compilerVersion) + compilerVersion.c_str()) ? "1" : "0"; } @@ -757,17 +759,17 @@ struct PlatformIdNode : public cmGeneratorExpressionNode const GeneratorExpressionContent* /*content*/, cmGeneratorExpressionDAGChecker* /*dagChecker*/) const override { - const char* platformId = + std::string const& platformId = context->LG->GetMakefile()->GetSafeDefinition("CMAKE_SYSTEM_NAME"); if (parameters.empty()) { - return platformId ? platformId : ""; + return platformId; } - if (!platformId) { + if (platformId.empty()) { return parameters.front().empty() ? "1" : "0"; } - if (strcmp(parameters.begin()->c_str(), platformId) == 0) { + if (*parameters.begin() == platformId) { return "1"; } return "0"; diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index efcfaf7..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,13 +134,16 @@ 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); this->DLLPlatform = - strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), - "") != 0; + !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); this->PolicyMap = t->PolicyMap; } @@ -151,6 +155,7 @@ cmGeneratorTarget::~cmGeneratorTarget() cmDeleteAll(this->CompileFeaturesEntries); cmDeleteAll(this->CompileDefinitionsEntries); cmDeleteAll(this->LinkOptionsEntries); + cmDeleteAll(this->LinkDirectoriesEntries); cmDeleteAll(this->SourceEntries); cmDeleteAll(this->LinkInformation); } @@ -1705,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(); @@ -3069,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, @@ -3496,11 +3616,11 @@ void cmGeneratorTarget::GetFullNameInternal( // if there is no prefix on the target use the cmake definition if (!targetPrefix && prefixVar) { - targetPrefix = this->Makefile->GetSafeDefinition(prefixVar); + targetPrefix = this->Makefile->GetSafeDefinition(prefixVar).c_str(); } // if there is no suffix on the target use the cmake definition if (!targetSuffix && suffixVar) { - targetSuffix = this->Makefile->GetSafeDefinition(suffixVar); + targetSuffix = this->Makefile->GetSafeDefinition(suffixVar).c_str(); } // frameworks have directory prefix but no suffix 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/cmGetDirectoryPropertyCommand.cxx b/Source/cmGetDirectoryPropertyCommand.cxx index bf464d9..0d4d653 100644 --- a/Source/cmGetDirectoryPropertyCommand.cxx +++ b/Source/cmGetDirectoryPropertyCommand.cxx @@ -65,7 +65,7 @@ bool cmGetDirectoryPropertyCommand::InitialPass( "providing the name of the variable to get."); return false; } - std::string output = dir->GetSafeDefinition(*i); + std::string const& output = dir->GetSafeDefinition(*i); this->Makefile->AddDefinition(variable, output.c_str()); return true; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 24dc593..71e844e 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -828,10 +828,8 @@ void cmGlobalGenerator::EnableLanguage( std::string sharedLibFlagsVar = "CMAKE_SHARED_LIBRARY_"; sharedLibFlagsVar += lang; sharedLibFlagsVar += "_FLAGS"; - const char* sharedLibFlags = mf->GetSafeDefinition(sharedLibFlagsVar); - if (sharedLibFlags) { - this->LanguageToOriginalSharedLibFlags[lang] = sharedLibFlags; - } + this->LanguageToOriginalSharedLibFlags[lang] = + mf->GetSafeDefinition(sharedLibFlagsVar); // Translate compiler ids for compatibility. this->CheckCompilerIdCompatibility(mf, lang); @@ -1092,7 +1090,7 @@ void cmGlobalGenerator::FillExtensionToLanguageMap(const std::string& l, { std::string extensionsVar = std::string("CMAKE_") + std::string(l) + std::string("_SOURCE_FILE_EXTENSIONS"); - std::string exts = mf->GetSafeDefinition(extensionsVar); + const std::string& exts = mf->GetSafeDefinition(extensionsVar); std::vector<std::string> extensionList; cmSystemTools::ExpandListArgument(exts, extensionList); for (std::string const& i : extensionList) { @@ -1112,7 +1110,7 @@ bool cmGlobalGenerator::GlobalSettingIsOn(std::string const& name) const return this->Makefiles[0]->IsOn(name); } -const char* cmGlobalGenerator::GetSafeGlobalSetting( +std::string cmGlobalGenerator::GetSafeGlobalSetting( std::string const& name) const { assert(!this->Makefiles.empty()); @@ -1596,7 +1594,7 @@ void cmGlobalGenerator::FinalizeTargetCompileInfo() for (std::string const& li : langs) { std::string const standardIncludesVar = "CMAKE_" + li + "_STANDARD_INCLUDE_DIRECTORIES"; - std::string const standardIncludesStr = + std::string const& standardIncludesStr = mf->GetSafeDefinition(standardIncludesVar); std::vector<std::string> standardIncludesVec; cmSystemTools::ExpandListArgument(standardIncludesStr, @@ -2456,7 +2454,7 @@ void cmGlobalGenerator::AddGlobalTarget_EditCache( std::string edit_cmd = this->GetEditCacheCommand(); if (!edit_cmd.empty()) { singleLine.push_back(std::move(edit_cmd)); - singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); + singleLine.push_back("-S$(CMAKE_SOURCE_DIR)"); singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); gti.Message = "Running CMake cache editor..."; gti.UsesTerminal = true; @@ -2486,7 +2484,7 @@ void cmGlobalGenerator::AddGlobalTarget_RebuildCache( gti.UsesTerminal = true; cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCMakeCommand()); - singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); + singleLine.push_back("-S$(CMAKE_SOURCE_DIR)"); singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); gti.CommandLines.push_back(std::move(singleLine)); targets.push_back(std::move(gti)); diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index f240f1d..1ea2d24 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -233,7 +233,7 @@ public: const char* GetGlobalSetting(std::string const& name) const; bool GlobalSettingIsOn(std::string const& name) const; - const char* GetSafeGlobalSetting(std::string const& name) const; + std::string GetSafeGlobalSetting(std::string const& name) const; /** Add a file to the manifest of generated targets for a configuration. */ void AddToManifest(std::string const& f); diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 0c80910..f513403 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -651,13 +651,13 @@ void cmGlobalNinjaGenerator::EnableLanguage( this->ResolveLanguageCompiler(l, mf, optional); } #ifdef _WIN32 - if (strcmp(mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID"), "MSVC") != 0 && - strcmp(mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID"), "MSVC") != 0 && + if ((mf->GetSafeDefinition("CMAKE_C_SIMULATE_ID") != "MSVC") && + (mf->GetSafeDefinition("CMAKE_CXX_SIMULATE_ID") != "MSVC") && (mf->IsOn("CMAKE_COMPILER_IS_MINGW") || - strcmp(mf->GetSafeDefinition("CMAKE_C_COMPILER_ID"), "GNU") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"), "GNU") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_C_COMPILER_ID"), "Clang") == 0 || - strcmp(mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID"), "Clang") == 0)) { + (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "GNU") || + (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "GNU") || + (mf->GetSafeDefinition("CMAKE_C_COMPILER_ID") == "Clang") || + (mf->GetSafeDefinition("CMAKE_CXX_COMPILER_ID") == "Clang"))) { this->UsingGCCOnWindows = true; } #endif @@ -1340,7 +1340,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) std::ostringstream cmd; cmd << lg->ConvertToOutputFormat(cmSystemTools::GetCMakeCommand(), cmOutputConverter::SHELL) - << " -H" + << " -S" << lg->ConvertToOutputFormat(lg->GetSourceDirectory(), cmOutputConverter::SHELL) << " -B" 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/cmGlobalVisualStudio10Generator.h b/Source/cmGlobalVisualStudio10Generator.h index 6eb597c..63e6903 100644 --- a/Source/cmGlobalVisualStudio10Generator.h +++ b/Source/cmGlobalVisualStudio10Generator.h @@ -111,6 +111,8 @@ public: bool FindMakeProgram(cmMakefile* mf) override; + bool IsIPOSupported() const override { return true; } + static std::string GetInstalledNsightTegraVersion(); cmIDEFlagTable const* GetClFlagTable() const; diff --git a/Source/cmGlobalVisualStudio14Generator.cxx b/Source/cmGlobalVisualStudio14Generator.cxx index b0db146..c3ddb3e 100644 --- a/Source/cmGlobalVisualStudio14Generator.cxx +++ b/Source/cmGlobalVisualStudio14Generator.cxx @@ -212,6 +212,12 @@ bool cmGlobalVisualStudio14Generator::IsWindowsStoreToolsetInstalled() const cmSystemTools::KeyWOW64_32); } +std::string cmGlobalVisualStudio14Generator::GetWindows10SDKMaxVersion() const +{ + // The last Windows 10 SDK version that VS 2015 can target is 10.0.14393.0. + return "10.0.14393.0"; +} + #if defined(_WIN32) && !defined(__CYGWIN__) struct NoWindowsH { @@ -220,6 +226,20 @@ struct NoWindowsH return !cmSystemTools::FileExists(p + "/um/windows.h", true); } }; +class WindowsSDKTooRecent +{ + std::string const& MaxVersion; + +public: + WindowsSDKTooRecent(std::string const& maxVersion) + : MaxVersion(maxVersion) + { + } + bool operator()(std::string const& v) + { + return cmSystemTools::VersionCompareGreater(v, MaxVersion); + } +}; #endif std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion() @@ -276,6 +296,12 @@ std::string cmGlobalVisualStudio14Generator::GetWindows10SDKVersion() // Sort the results to make sure we select the most recent one. std::sort(sdks.begin(), sdks.end(), cmSystemTools::VersionCompareGreater); + // Skip SDKs that cannot be used with our toolset. + std::string maxVersion = this->GetWindows10SDKMaxVersion(); + if (!maxVersion.empty()) { + cmEraseIf(sdks, WindowsSDKTooRecent(maxVersion)); + } + // Look for a SDK exactly matching the requested target version. for (std::string const& i : sdks) { if (cmSystemTools::VersionCompareEqual(i, this->SystemVersion)) { diff --git a/Source/cmGlobalVisualStudio14Generator.h b/Source/cmGlobalVisualStudio14Generator.h index 4868df0..9f5bb4e 100644 --- a/Source/cmGlobalVisualStudio14Generator.h +++ b/Source/cmGlobalVisualStudio14Generator.h @@ -37,6 +37,10 @@ protected: // of the toolset is installed bool IsWindowsStoreToolsetInstalled() const; + // Used to make sure that the Windows 10 SDK selected can work with the + // version of the toolset. + virtual std::string GetWindows10SDKMaxVersion() const; + const char* GetIDEVersion() override { return "14.0"; } virtual bool SelectWindows10SDK(cmMakefile* mf, bool required); diff --git a/Source/cmGlobalVisualStudio15Generator.cxx b/Source/cmGlobalVisualStudio15Generator.cxx index 9983a43..23fd2d5 100644 --- a/Source/cmGlobalVisualStudio15Generator.cxx +++ b/Source/cmGlobalVisualStudio15Generator.cxx @@ -258,6 +258,11 @@ bool cmGlobalVisualStudio15Generator::IsWin81SDKInstalled() const return false; } +std::string cmGlobalVisualStudio15Generator::GetWindows10SDKMaxVersion() const +{ + return std::string(); +} + std::string cmGlobalVisualStudio15Generator::FindMSBuildCommand() { std::string msbuild; diff --git a/Source/cmGlobalVisualStudio15Generator.h b/Source/cmGlobalVisualStudio15Generator.h index cdc97ad..8ab63f1 100644 --- a/Source/cmGlobalVisualStudio15Generator.h +++ b/Source/cmGlobalVisualStudio15Generator.h @@ -52,6 +52,8 @@ protected: // Check for a Win 8 SDK known to the registry or VS installer tool. bool IsWin81SDKInstalled() const; + std::string GetWindows10SDKMaxVersion() const override; + std::string FindMSBuildCommand() override; std::string FindDevEnvCommand() override; diff --git a/Source/cmGlobalVisualStudio8Generator.cxx b/Source/cmGlobalVisualStudio8Generator.cxx index 117d051..ba138c2 100644 --- a/Source/cmGlobalVisualStudio8Generator.cxx +++ b/Source/cmGlobalVisualStudio8Generator.cxx @@ -177,9 +177,9 @@ bool cmGlobalVisualStudio8Generator::AddCheckTarget() // Create a rule to re-run CMake. cmCustomCommandLine commandLine; commandLine.push_back(cmSystemTools::GetCMakeCommand()); - std::string argH = "-H"; - argH += lg->GetSourceDirectory(); - commandLine.push_back(argH); + std::string argS = "-S"; + argS += lg->GetSourceDirectory(); + commandLine.push_back(argS); std::string argB = "-B"; argB += lg->GetBinaryDirectory(); commandLine.push_back(argB); 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/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index d7fe777..6e33cf7 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -5,7 +5,6 @@ #include "cmsys/Glob.hxx" #include <sstream> #include <stddef.h> -#include <string.h> #include <utility> #include "cmAlgorithms.h" @@ -350,8 +349,7 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) // Check whether this is a DLL platform. bool dll_platform = - strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), - "") != 0; + !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); for (std::string const& tgt : targetList.GetVector()) { 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/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 4f8f2e7..7030725 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -683,7 +683,7 @@ std::string cmLocalGenerator::GetIncludeFlags( std::string flagVar = "CMAKE_INCLUDE_FLAG_"; flagVar += lang; - const char* includeFlag = this->Makefile->GetSafeDefinition(flagVar); + std::string const& includeFlag = this->Makefile->GetSafeDefinition(flagVar); flagVar = "CMAKE_INCLUDE_FLAG_SEP_"; flagVar += lang; const char* sep = this->Makefile->GetDefinition(flagVar); @@ -1824,9 +1824,9 @@ bool cmLocalGenerator::GetShouldUseOldFlags(bool shared, std::string flagsVar = "CMAKE_SHARED_LIBRARY_"; flagsVar += lang; flagsVar += "_FLAGS"; - const char* flags = this->Makefile->GetSafeDefinition(flagsVar); + std::string const& flags = this->Makefile->GetSafeDefinition(flagsVar); - if (flags && flags != originalFlags) { + if (flags != originalFlags) { switch (this->GetPolicyStatus(cmPolicies::CMP0018)) { case cmPolicies::WARN: { std::ostringstream e; @@ -1859,7 +1859,7 @@ void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags, std::string const& lang, int targetType) { - const char* picFlags = nullptr; + std::string picFlags; if (targetType == cmStateEnums::EXECUTABLE) { std::string flagsVar = "CMAKE_"; @@ -1867,13 +1867,13 @@ void cmLocalGenerator::AddPositionIndependentFlags(std::string& flags, flagsVar += "_COMPILE_OPTIONS_PIE"; picFlags = this->Makefile->GetSafeDefinition(flagsVar); } - if (!picFlags) { + if (picFlags.empty()) { std::string flagsVar = "CMAKE_"; flagsVar += lang; flagsVar += "_COMPILE_OPTIONS_PIC"; picFlags = this->Makefile->GetSafeDefinition(flagsVar); } - if (picFlags) { + if (!picFlags.empty()) { std::vector<std::string> options; cmSystemTools::ExpandListArgument(picFlags, options); for (std::string const& o : options) { diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 690b827..4d19b3a 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -773,7 +773,7 @@ void cmLocalUnixMakefileGenerator3::WriteSpecialTargetsBottom( std::string cmakefileName = cmake::GetCMakeFilesDirectoryPostSlash(); cmakefileName += "Makefile.cmake"; std::string runRule = - "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; + "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; runRule += this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); @@ -1422,7 +1422,8 @@ bool cmLocalUnixMakefileGenerator3::ScanDependencies( this->WriteDisclaimer(internalRuleFileStream); // for each language we need to scan, scan it - const char* langStr = mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"); + std::string const& langStr = + mf->GetSafeDefinition("CMAKE_DEPENDS_LANGUAGES"); std::vector<std::string> langs; cmSystemTools::ExpandListArgument(langStr, langs); for (std::string const& lang : langs) { @@ -1682,7 +1683,7 @@ void cmLocalUnixMakefileGenerator3::WriteLocalAllRules( cmakefileName += "Makefile.cmake"; { std::string runRule = - "$(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; + "$(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)"; runRule += " --check-build-system "; runRule += this->ConvertToOutputFormat(cmakefileName, cmOutputConverter::SHELL); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index c05b085..8428672 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -260,7 +260,7 @@ cmSourceFile* cmLocalVisualStudio7Generator::CreateVCProjBuildRule() std::string comment = "Building Custom Rule "; comment += makefileIn; std::string args; - args = "-H"; + args = "-S"; args += this->GetSourceDirectory(); commandLine.push_back(args); args = "-B"; @@ -1082,7 +1082,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( // Use the NOINHERIT macro to avoid getting VS project default // libraries which may be set by the user to something bad. fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) " - << this->Makefile->GetSafeDefinition(standardLibsVar.c_str()); + << this->Makefile->GetSafeDefinition(standardLibsVar); if (this->FortranProject) { this->Internal->OutputObjects(fout, target, configName, " "); } @@ -1167,7 +1167,7 @@ void cmLocalVisualStudio7Generator::OutputBuildTool( // Use the NOINHERIT macro to avoid getting VS project default // libraries which may be set by the user to something bad. fout << "\t\t\t\tAdditionalDependencies=\"$(NOINHERIT) " - << this->Makefile->GetSafeDefinition(standardLibsVar.c_str()); + << this->Makefile->GetSafeDefinition(standardLibsVar); if (this->FortranProject) { this->Internal->OutputObjects(fout, target, configName, " "); } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index fdcf0a8..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; @@ -2401,7 +2409,7 @@ bool cmMakefile::IsDefinitionSet(const std::string& name) const return def != nullptr; } -const char* cmMakefile::GetDefinition(const std::string& name) const +const std::string* cmMakefile::GetDef(const std::string& name) const { const std::string* def = this->StateSnapshot.GetDefinition(name); if (!def) { @@ -2427,16 +2435,26 @@ const char* cmMakefile::GetDefinition(const std::string& name) const } } #endif - return (def ? def->c_str() : nullptr); + return def; } -const char* cmMakefile::GetSafeDefinition(const std::string& def) const +const char* cmMakefile::GetDefinition(const std::string& name) const { - const char* ret = this->GetDefinition(def); - if (!ret) { - return ""; + const std::string* def = GetDef(name); + if (!def) { + return nullptr; } - return ret; + return def->c_str(); +} + +const std::string& cmMakefile::GetSafeDefinition(const std::string& name) const +{ + static std::string const empty; + const std::string* def = GetDef(name); + if (!def) { + return empty; + } + return *def; } std::vector<std::string> cmMakefile::GetDefinitions() const @@ -4184,7 +4202,7 @@ bool cmMakefile::SetPolicy(cmPolicies::PolicyID id, // Deprecate old policies, especially those that require a lot // of code to maintain the old behavior. - if (status == cmPolicies::OLD && id <= cmPolicies::CMP0054) { + if (status == cmPolicies::OLD && id <= cmPolicies::CMP0063) { this->IssueMessage(cmake::DEPRECATION_WARNING, cmPolicies::GetPolicyDeprecatedWarning(id)); } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 54730b5..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, @@ -432,7 +433,8 @@ public: * cache is then queried. */ const char* GetDefinition(const std::string&) const; - const char* GetSafeDefinition(const std::string&) const; + const std::string* GetDef(const std::string&) const; + const std::string& GetSafeDefinition(const std::string&) const; std::string GetRequiredDefinition(const std::string& name) const; bool IsDefinitionSet(const std::string&) const; /** @@ -801,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/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index ebcc501..7ac8d1b 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -10,7 +10,6 @@ #include <map> #include <memory> // IWYU pragma: keep #include <sstream> -#include <string.h> #include "cmAlgorithms.h" #include "cmComputeLinkInformation.h" @@ -174,9 +173,8 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags, bool cmNinjaTargetGenerator::NeedDepTypeMSVC(const std::string& lang) const { - return strcmp(this->GetMakefile()->GetSafeDefinition("CMAKE_NINJA_DEPTYPE_" + - lang), - "msvc") == 0; + return (this->GetMakefile()->GetSafeDefinition("CMAKE_NINJA_DEPTYPE_" + + lang) == "msvc"); } // TODO: Refactor with diff --git a/Source/cmPolicies.cxx b/Source/cmPolicies.cxx index ba50fb8..5caea7d 100644 --- a/Source/cmPolicies.cxx +++ b/Source/cmPolicies.cxx @@ -135,7 +135,7 @@ static bool GetPolicyDefault(cmMakefile* mf, std::string const& policy, cmPolicies::PolicyStatus* defaultSetting) { std::string defaultVar = "CMAKE_POLICY_DEFAULT_" + policy; - std::string defaultValue = mf->GetSafeDefinition(defaultVar); + std::string const& defaultValue = mf->GetSafeDefinition(defaultVar); if (defaultValue == "NEW") { *defaultSetting = cmPolicies::NEW; } else if (defaultValue == "OLD") { diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index 4ffe803..a367e47 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -234,7 +234,13 @@ class cmMakefile; SELECT( \ POLICY, CMP0079, \ "target_link_libraries allows use with targets in other directories.", 3, \ - 13, 0, cmPolicies::WARN) + 13, 0, cmPolicies::WARN) \ + SELECT(POLICY, CMP0080, \ + "BundleUtilities cannot be included at configure time", 3, 13, 0, \ + 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) \ @@ -260,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/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 8bd985a..8a202a2 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1126,7 +1126,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() } }; auto MfDef = [makefile](const char* key) { - return std::string(makefile->GetSafeDefinition(key)); + return makefile->GetSafeDefinition(key); }; // Write diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index c364700..2e6f90f 100644 --- a/Source/cmQtAutoGeneratorMocUic.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -1204,7 +1204,7 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) valueConf = makefile->GetDefinition(keyConf); } if (valueConf == nullptr) { - valueConf = makefile->GetSafeDefinition(key); + return makefile->GetSafeDefinition(key); } return std::string(valueConf); }; @@ -1226,7 +1226,7 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) Base_.MultiConfig = InfoGetBool("AM_MULTI_CONFIG"); { unsigned long num = Base_.NumThreads; - if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL"), &num)) { + if (cmSystemTools::StringToULong(InfoGet("AM_PARALLEL").c_str(), &num)) { num = std::max<unsigned long>(num, 1); num = std::min<unsigned long>(num, ParallelMax); Base_.NumThreads = static_cast<unsigned int>(num); @@ -1264,7 +1264,8 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) // - Qt environment { unsigned long qtv = Base_.QtVersionMajor; - if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR"), &qtv)) { + if (cmSystemTools::StringToULong(InfoGet("AM_QT_VERSION_MAJOR").c_str(), + &qtv)) { Base_.QtVersionMajor = static_cast<unsigned int>(qtv); } } diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx index 6caa0d8..65c6741 100644 --- a/Source/cmQtAutoGeneratorRcc.cxx +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -52,7 +52,7 @@ bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) valueConf = makefile->GetDefinition(keyConf); } if (valueConf == nullptr) { - valueConf = makefile->GetSafeDefinition(key); + return makefile->GetSafeDefinition(key); } return std::string(valueConf); }; 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 c8b8653..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(); @@ -659,6 +661,8 @@ cmStateSnapshot cmState::CreateBaseSnapshot() pos->IncludeDirectoryPosition = 0; 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(); @@ -810,6 +814,10 @@ cmStateSnapshot cmState::Pop(cmStateSnapshot const& originSnapshot) prevPos->BuildSystemDirectory->CompileDefinitions.size(); prevPos->CompileOptionsPosition = 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/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 79e5ccf..8339aac 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -6,6 +6,7 @@ #include "cmDuration.h" #include "cmProcessOutput.h" #include "cm_sys_stat.h" +#include "cm_uv.h" #if defined(CMAKE_BUILD_WITH_CMAKE) # include "cmArchiveWrite.h" @@ -55,8 +56,6 @@ # include <wincrypt.h> # include <fcntl.h> /* _O_TEXT */ - -# include "cm_uv.h" #else # include <sys/time.h> # include <unistd.h> @@ -2988,3 +2987,25 @@ bool cmSystemTools::StringToULong(const char* str, unsigned long* value) *value = strtoul(str, &endp, 10); return (*endp == '\0') && (endp != str) && (errno == 0); } + +bool cmSystemTools::CreateSymlink(const std::string& origName, + const std::string& newName) +{ + uv_fs_t req; + int flags = 0; +#if defined(_WIN32) + if (cmsys::SystemTools::FileIsDirectory(origName)) { + flags |= UV_FS_SYMLINK_DIR; + } +#endif + int err = uv_fs_symlink(nullptr, &req, origName.c_str(), newName.c_str(), + flags, nullptr); + if (err) { + std::string e = + "failed to create symbolic link '" + newName + "': " + uv_strerror(err); + cmSystemTools::Error(e.c_str()); + return false; + } + + return true; +} diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 5c383ee..98300eb 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -513,6 +513,11 @@ public: /** Perform one-time initialization of libuv. */ static void InitializeLibUV(); + /** Create a symbolic link if the platform supports it. Returns whether + creation succeeded. */ + static bool CreateSymlink(const std::string& origName, + const std::string& newName); + private: static bool s_ForceUnixPaths; static bool s_RunCommandHideConsole; diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index cd40223..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; }; @@ -190,13 +192,11 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, // Check whether this is a DLL platform. this->DLLPlatform = - strcmp(this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX"), - "") != 0; + !this->Makefile->GetSafeDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX").empty(); // Check whether we are targeting an Android platform. this->IsAndroid = - strcmp(this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME"), - "Android") == 0; + (this->Makefile->GetSafeDefinition("CMAKE_SYSTEM_NAME") == "Android"); // Setup default property values. if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && @@ -393,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 && @@ -442,6 +454,31 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, if (this->TargetTypeValue <= cmStateEnums::UTILITY) { this->SetPropertyDefault("DOTNET_TARGET_FRAMEWORK_VERSION", nullptr); } + + if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY && + this->GetType() != cmStateEnums::UTILITY) { + + // check for "CMAKE_VS_GLOBALS" variable and set up target properties + // if any + const char* globals = mf->GetDefinition("CMAKE_VS_GLOBALS"); + if (globals) { + const std::string genName = mf->GetGlobalGenerator()->GetName(); + if (cmHasLiteralPrefix(genName, "Visual Studio")) { + std::vector<std::string> props; + cmSystemTools::ExpandListArgument(globals, props); + const std::string vsGlobal = "VS_GLOBAL_"; + for (const std::string& i : props) { + // split NAME=VALUE + const std::string::size_type assignment = i.find('='); + if (assignment != std::string::npos) { + const std::string propName = vsGlobal + i.substr(0, assignment); + const std::string propValue = i.substr(assignment + 1); + this->SetPropertyDefault(propName, propValue.c_str()); + } + } + } + } + } } cmGlobalGenerator* cmTarget::GetGlobalGenerator() const @@ -516,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()) { @@ -658,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(); @@ -878,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); @@ -904,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); @@ -990,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(); @@ -1101,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(); @@ -1198,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, @@ -1318,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); @@ -1334,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); @@ -1401,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/cmTargetLinkOptionsCommand.cxx b/Source/cmTargetLinkOptionsCommand.cxx index f0f13fd..d6ed5ae 100644 --- a/Source/cmTargetLinkOptionsCommand.cxx +++ b/Source/cmTargetLinkOptionsCommand.cxx @@ -33,9 +33,9 @@ std::string cmTargetLinkOptionsCommand::Join( } bool cmTargetLinkOptionsCommand::HandleDirectContent( - cmTarget* tgt, const std::vector<std::string>& content, bool, bool) + cmTarget* tgt, const std::vector<std::string>& content, bool prepend, bool) { cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); - tgt->InsertLinkOption(this->Join(content), lfbt); + tgt->InsertLinkOption(this->Join(content), lfbt, prepend); return true; // Successfully handled. } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 53a2a59..c79b071 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -1122,6 +1122,9 @@ void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValues( this->GeneratorTarget->GetPropertyAsBool("VS_WINRT_EXTENSIONS")) { e1.Element("WindowsAppContainer", "true"); } + if (this->IPOEnabledConfigurations.count(config) > 0) { + e1.Element("WholeProgramOptimization", "true"); + } } void cmVisualStudio10TargetGenerator::WriteMSToolConfigurationValuesManaged( @@ -2370,9 +2373,11 @@ void cmVisualStudio10TargetGenerator::OutputLinkIncremental( Options& linkOptions = *(this->LinkOptions[configName]); const std::string cond = this->CalcCondition(configName); - const char* incremental = linkOptions.GetFlag("LinkIncremental"); - e1.WritePlatformConfigTag("LinkIncremental", cond, - (incremental ? incremental : "true")); + if (this->IPOEnabledConfigurations.count(configName) == 0) { + const char* incremental = linkOptions.GetFlag("LinkIncremental"); + e1.WritePlatformConfigTag("LinkIncremental", cond, + (incremental ? incremental : "true")); + } linkOptions.RemoveFlag("LinkIncremental"); const char* manifest = linkOptions.GetFlag("GenerateManifest"); @@ -2484,8 +2489,10 @@ bool cmVisualStudio10TargetGenerator::ComputeClOptions( clOptions.AddFlag("CompileAs", "CompileAsCpp"); } - // Check IPO related warning/error. - this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName); + // Put the IPO enabled configurations into a set. + if (this->GeneratorTarget->IsIPOEnabled(linkLanguage, configName)) { + this->IPOEnabledConfigurations.insert(configName); + } // Get preprocessor definitions for this directory. std::string defineFlags = this->Makefile->GetDefineFlags(); @@ -2699,11 +2706,9 @@ bool cmVisualStudio10TargetGenerator::ComputeRcOptions( Options& rcOptions = *pOptions; std::string CONFIG = cmSystemTools::UpperCase(configName); - std::string rcConfigFlagsVar = std::string("CMAKE_RC_FLAGS_") + CONFIG; - std::string flags = - std::string(this->Makefile->GetSafeDefinition("CMAKE_RC_FLAGS")) + - std::string(" ") + - std::string(this->Makefile->GetSafeDefinition(rcConfigFlagsVar)); + std::string rcConfigFlagsVar = "CMAKE_RC_FLAGS_" + CONFIG; + std::string flags = this->Makefile->GetSafeDefinition("CMAKE_RC_FLAGS") + + " " + this->Makefile->GetSafeDefinition(rcConfigFlagsVar); rcOptions.Parse(flags); @@ -2757,10 +2762,8 @@ bool cmVisualStudio10TargetGenerator::ComputeCudaOptions( // Get compile flags for CUDA in this directory. std::string CONFIG = cmSystemTools::UpperCase(configName); std::string configFlagsVar = std::string("CMAKE_CUDA_FLAGS_") + CONFIG; - std::string flags = - std::string(this->Makefile->GetSafeDefinition("CMAKE_CUDA_FLAGS")) + - std::string(" ") + - std::string(this->Makefile->GetSafeDefinition(configFlagsVar)); + std::string flags = this->Makefile->GetSafeDefinition("CMAKE_CUDA_FLAGS") + + " " + this->Makefile->GetSafeDefinition(configFlagsVar); this->LocalGenerator->AddCompileOptions(flags, this->GeneratorTarget, "CUDA", configName); @@ -2971,9 +2974,8 @@ bool cmVisualStudio10TargetGenerator::ComputeMasmOptions( std::string CONFIG = cmSystemTools::UpperCase(configName); std::string configFlagsVar = std::string("CMAKE_ASM_MASM_FLAGS_") + CONFIG; std::string flags = - std::string(this->Makefile->GetSafeDefinition("CMAKE_ASM_MASM_FLAGS")) + - std::string(" ") + - std::string(this->Makefile->GetSafeDefinition(configFlagsVar)); + this->Makefile->GetSafeDefinition("CMAKE_ASM_MASM_FLAGS") + " " + + this->Makefile->GetSafeDefinition(configFlagsVar); masmOptions.Parse(flags); @@ -3024,14 +3026,11 @@ bool cmVisualStudio10TargetGenerator::ComputeNasmOptions( Options& nasmOptions = *pOptions; std::string CONFIG = cmSystemTools::UpperCase(configName); - std::string configFlagsVar = std::string("CMAKE_ASM_NASM_FLAGS_") + CONFIG; + std::string configFlagsVar = "CMAKE_ASM_NASM_FLAGS_" + CONFIG; std::string flags = - std::string(this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_FLAGS")) + - std::string(" -f") + - std::string( - this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT")) + - std::string(" ") + - std::string(this->Makefile->GetSafeDefinition(configFlagsVar)); + this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_FLAGS") + " -f" + + this->Makefile->GetSafeDefinition("CMAKE_ASM_NASM_OBJECT_FORMAT") + " " + + this->Makefile->GetSafeDefinition(configFlagsVar); nasmOptions.Parse(flags); // Get includes for this target diff --git a/Source/cmVisualStudio10TargetGenerator.h b/Source/cmVisualStudio10TargetGenerator.h index 15e47b4..829d2bf 100644 --- a/Source/cmVisualStudio10TargetGenerator.h +++ b/Source/cmVisualStudio10TargetGenerator.h @@ -204,6 +204,7 @@ private: bool NsightTegra; unsigned int NsightTegraVersion[4]; bool TargetCompileAsWinRT; + std::set<std::string> IPOEnabledConfigurations; cmGlobalVisualStudio10Generator* const GlobalGenerator; cmLocalVisualStudio10Generator* const LocalGenerator; std::set<std::string> CSharpCustomCommandNames; diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 783dbf2..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; @@ -612,19 +617,43 @@ void cmake::SetArgs(const std::vector<std::string>& args, bool havePlatform = false; for (unsigned int i = 1; i < args.size(); ++i) { std::string const& arg = args[i]; - if (arg.find("-H", 0) == 0) { + if (arg.find("-H", 0) == 0 || arg.find("-S", 0) == 0) { directoriesSet = true; std::string path = arg.substr(2); + if (path.empty()) { + ++i; + if (i >= args.size()) { + cmSystemTools::Error("No source directory specified for -S"); + return; + } + path = args[i]; + if (path[0] == '-') { + cmSystemTools::Error("No source directory specified for -S"); + return; + } + } + path = cmSystemTools::CollapseFullPath(path); cmSystemTools::ConvertToUnixSlashes(path); this->SetHomeDirectory(path); - } else if (arg.find("-S", 0) == 0) { - // There is no local generate anymore. Ignore -S option. } else if (arg.find("-O", 0) == 0) { // There is no local generate anymore. Ignore -O option. } else if (arg.find("-B", 0) == 0) { directoriesSet = true; std::string path = arg.substr(2); + if (path.empty()) { + ++i; + if (i >= args.size()) { + cmSystemTools::Error("No build directory specified for -B"); + return; + } + path = args[i]; + if (path[0] == '-') { + cmSystemTools::Error("No build directory specified for -B"); + return; + } + } + path = cmSystemTools::CollapseFullPath(path); cmSystemTools::ConvertToUnixSlashes(path); this->SetHomeOutputDirectory(path); @@ -836,20 +865,27 @@ void cmake::SetDirectoriesFromFile(const char* arg) this->SetHomeOutputDirectory(listPath); } else { // Source directory given on command line. Use current working - // directory as build tree. - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - this->SetHomeOutputDirectory(cwd); + // directory as build tree if -B hasn't been given already + if (this->GetHomeOutputDirectory().empty()) { + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + this->SetHomeOutputDirectory(cwd); + } } return; } - // We didn't find a CMakeLists.txt or CMakeCache.txt file from the - // argument. Assume it is the path to the source tree, and use the - // current working directory as the build tree. - std::string full = cmSystemTools::CollapseFullPath(arg); - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - this->SetHomeDirectory(full); - this->SetHomeOutputDirectory(cwd); + if (this->GetHomeDirectory().empty()) { + // We didn't find a CMakeLists.txt and it wasn't specified + // with -S. Assume it is the path to the source tree + std::string full = cmSystemTools::CollapseFullPath(arg); + this->SetHomeDirectory(full); + } + if (this->GetHomeOutputDirectory().empty()) { + // We didn't find a CMakeCache.txt and it wasn't specified + // with -B. Assume the current working directory as the build tree. + std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); + this->SetHomeOutputDirectory(cwd); + } } // at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the @@ -2431,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 4b4c67c..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; @@ -556,7 +557,9 @@ private: }; #define CMAKE_STANDARD_OPTIONS_TABLE \ - { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \ + { "-S <path-to-source>", "Explicitly specify a source directory." }, \ + { "-B <path-to-build>", "Explicitly specify a build directory." }, \ + { "-C <initial-cache>", "Pre-load a script to populate the cache." }, \ { "-D <var>[:<type>]=<value>", "Create or update a cmake cache entry." }, \ { "-U <globbing_expr>", "Remove matching entries from CMake cache." }, \ { "-G <generator-name>", "Specify a build system generator." }, \ diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index e3d94f6..75dabde 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -38,7 +38,8 @@ static const char* cmDocumentationName[][2] = { static const char* cmDocumentationUsage[][2] = { { nullptr, " cmake [options] <path-to-source>\n" - " cmake [options] <path-to-existing-build>" }, + " cmake [options] <path-to-existing-build>\n" + " cmake [options] -S <path-to-source> -B <path-to-build>" }, { nullptr, "Specify a source directory to (re-)generate a build system for " "it in the current working directory. Specify an existing build " diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 87da108..1d2f741 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -108,6 +108,7 @@ void CMakeCommandUsage(const char* program) << " time command [args...] - run command and display elapsed time\n" << " touch file - touch a file.\n" << " touch_nocreate file - touch a file but do not create it.\n" + << " create_symlink old new - create a symbolic link new -> old\n" #if defined(_WIN32) && !defined(__CYGWIN__) << "Available on Windows only:\n" << " delete_regv key - delete registry value\n" @@ -116,9 +117,6 @@ void CMakeCommandUsage(const char* program) << " env_vs9_wince sdkname - displays a batch file which sets the " "environment for the provided Windows CE SDK installed in VS2008\n" << " write_regv key value - write registry value\n" -#else - << "Available on UNIX only:\n" - << " create_symlink old new - create a symbolic link new -> old\n" #endif ; /* clang-format on */ @@ -868,9 +866,6 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) return 1; } if (!cmSystemTools::CreateSymlink(args[2], args[3])) { - std::string emsg = cmSystemTools::GetLastSystemError(); - std::cerr << "failed to create symbolic link '" << destinationFileName - << "': " << emsg << "\n"; return 1; } return 0; diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index 9fa0cb1..2a2e737 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -973,8 +973,8 @@ void kwsysProcess_Execute(kwsysProcess* cp) wchar_t* wstdin = kwsysEncoding_DupToWide(cp->PipeFileSTDIN); DWORD error; cp->PipeChildStd[0] = - CreateFileW(wstdin, GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + CreateFileW(wstdin, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, + OPEN_EXISTING, 0, 0); error = GetLastError(); /* Check now in case free changes this. */ free(wstdin); if (cp->PipeChildStd[0] == INVALID_HANDLE_VALUE) { diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 476fe08..0a4ad7a 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -3640,11 +3640,11 @@ bool SystemTools::Split(const std::string& str, while (lpos < data.length()) { std::string::size_type rpos = data.find_first_of(separator, lpos); if (rpos == std::string::npos) { - // Line ends at end of string without a newline. + // String ends at end of string without a separator. lines.push_back(data.substr(lpos)); return false; } else { - // Line ends in a "\n", remove the character. + // String ends in a separator, remove the character. lines.push_back(data.substr(lpos, rpos - lpos)); } lpos = rpos + 1; @@ -3658,7 +3658,7 @@ bool SystemTools::Split(const std::string& str, std::string data(str); std::string::size_type lpos = 0; while (lpos < data.length()) { - std::string::size_type rpos = data.find_first_of("\n", lpos); + std::string::size_type rpos = data.find_first_of('\n', lpos); if (rpos == std::string::npos) { // Line ends at end of string without a newline. lines.push_back(data.substr(lpos)); 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/CMakeCommands/target_link_options/CMakeLists.txt b/Tests/CMakeCommands/target_link_options/CMakeLists.txt index 3bb6ff3..e84d041 100644 --- a/Tests/CMakeCommands/target_link_options/CMakeLists.txt +++ b/Tests/CMakeCommands/target_link_options/CMakeLists.txt @@ -24,3 +24,11 @@ get_target_property(result target_link_options_3 INTERFACE_LINK_OPTIONS) if (NOT result MATCHES "-INTERFACE_FLAG") message(SEND_ERROR "target_link_options not populated the INTERFACE_LINK_OPTIONS target property of static library") endif() + +add_library(target_link_options_4 SHARED EXCLUDE_FROM_ALL LinkOptionsLib.c) +target_link_options(target_link_options_4 PRIVATE -PRIVATE_FLAG) +target_link_options(target_link_options_4 BEFORE PRIVATE -BEFORE_PRIVATE_FLAG) +get_target_property(result target_link_options_4 LINK_OPTIONS) +if (NOT result MATCHES "-BEFORE_PRIVATE_FLAG.*-PRIVATE_FLAG") + message(SEND_ERROR "target_link_options not managing correctly 'BEFORE' keyword") +endif() diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index a22521b..0de6c41 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -368,6 +368,7 @@ if(BUILD_TESTING) ADD_TEST_MACRO(CxxSubdirC CxxSubdirC) ADD_TEST_MACRO(IPO COnly/COnly) ADD_TEST_MACRO(OutDir runtime/OutDir) + ADD_TEST_MACRO(OutName exe.OutName.exe) ADD_TEST_MACRO(ObjectLibrary UseCshared) ADD_TEST_MACRO(NewlineArgs NewlineArgs) ADD_TEST_MACRO(SetLang SetLang) @@ -2106,7 +2107,7 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release set(reg_vs10 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]") set(reg_vs11 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]") set(reg_vs12 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]") - set(reg_vs14 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]") + set(reg_vs14 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]") set(reg_ws80 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v8.0;InstallationFolder]") set(reg_ws81 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\v8.1;InstallationFolder]") set(reg_ws10_0 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0\\Setup\\Build Tools for Windows 10;srcPath]") @@ -2127,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} @@ -2142,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 @@ -2162,18 +2164,24 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release -DCMAKE_SYSTEM_VERSION=8.1 ) endif() + if(CMake_TEST_VSWinStorePhone_VS_2017 AND ws10_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() @@ -2824,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/CustomCommandWorkingDirectory/CMakeLists.txt b/Tests/CustomCommandWorkingDirectory/CMakeLists.txt index 4975feb..5495a9b 100644 --- a/Tests/CustomCommandWorkingDirectory/CMakeLists.txt +++ b/Tests/CustomCommandWorkingDirectory/CMakeLists.txt @@ -42,3 +42,23 @@ add_custom_target( ) add_dependencies(working2 Custom2) + +file(MAKE_DIRECTORY ${TestWorkingDir_BINARY_DIR}/genex) +add_custom_command( + OUTPUT "${TestWorkingDir_BINARY_DIR}/genex/working.c" + COMMAND "${CMAKE_COMMAND}" -E copy "${TestWorkingDir_SOURCE_DIR}/working.c.in" "${TestWorkingDir_BINARY_DIR}/genex/working.c" + WORKING_DIRECTORY "${TestWorkingDir_BINARY_DIR}/$<1:genex>/" + COMMENT "custom command" +) + +add_executable(workinggenex "${TestWorkingDir_BINARY_DIR}/genex/working.c" + "${TestWorkingDir_BINARY_DIR}/genex/customTarget.c") + +add_custom_target( + CustomGenex ALL + COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${TestWorkingDir_SOURCE_DIR}/customTarget.c" "${TestWorkingDir_BINARY_DIR}/genex/customTarget.c" + BYPRODUCTS "${TestWorkingDir_BINARY_DIR}/genex/customTarget.c" + WORKING_DIRECTORY "${TestWorkingDir_BINARY_DIR}/$<1:genex>/" +) + +add_dependencies(workinggenex CustomGenex) 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/OutName/CMakeLists.txt b/Tests/OutName/CMakeLists.txt new file mode 100644 index 0000000..f024def --- /dev/null +++ b/Tests/OutName/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.12) +project(OutName C) + +add_executable(OutName main.c) +set_property(TARGET OutName PROPERTY PREFIX exe.) +set_property(TARGET OutName PROPERTY SUFFIX .exe) diff --git a/Tests/OutName/main.c b/Tests/OutName/main.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/OutName/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake b/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake new file mode 100644 index 0000000..063a7f3 --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/CMP0080-COMMAND.cmake @@ -0,0 +1,5 @@ +if(DEFINED CMP0080_VALUE) + cmake_policy(SET CMP0080 ${CMP0080_VALUE}) +endif() + +include(BundleUtilities) diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-NEW-result.txt b/Tests/RunCMake/BundleUtilities/CMP0080-NEW-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/CMP0080-NEW-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-NEW-stderr.txt b/Tests/RunCMake/BundleUtilities/CMP0080-NEW-stderr.txt new file mode 100644 index 0000000..1454b0c --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/CMP0080-NEW-stderr.txt @@ -0,0 +1,2 @@ +CMake Error at .*/Modules/BundleUtilities\.cmake:[0-9]+ \(message\): + BundleUtilities cannot be included at configure time! diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-NEW.cmake b/Tests/RunCMake/BundleUtilities/CMP0080-NEW.cmake new file mode 100644 index 0000000..558c16d --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/CMP0080-NEW.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0080 NEW) +include(BundleUtilities) diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-OLD.cmake b/Tests/RunCMake/BundleUtilities/CMP0080-OLD.cmake new file mode 100644 index 0000000..a65d92f --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/CMP0080-OLD.cmake @@ -0,0 +1,2 @@ +cmake_policy(SET CMP0080 OLD) +include(BundleUtilities) diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-WARN-stderr.txt b/Tests/RunCMake/BundleUtilities/CMP0080-WARN-stderr.txt new file mode 100644 index 0000000..a1a0e8f --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/CMP0080-WARN-stderr.txt @@ -0,0 +1,4 @@ +CMake Warning \(dev\) at .*/Modules/BundleUtilities\.cmake:[0-9]+ \(message\): + Policy CMP0080 is not set: BundleUtilities prefers not to be included at + configure time\. Run "cmake --help-policy CMP0080" for policy details\. Use + the cmake_policy command to set the policy and suppress this warning\. diff --git a/Tests/RunCMake/BundleUtilities/CMP0080-WARN.cmake b/Tests/RunCMake/BundleUtilities/CMP0080-WARN.cmake new file mode 100644 index 0000000..45f6f92 --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/CMP0080-WARN.cmake @@ -0,0 +1 @@ +include(BundleUtilities) diff --git a/Tests/RunCMake/BundleUtilities/CMakeLists.txt b/Tests/RunCMake/BundleUtilities/CMakeLists.txt new file mode 100644 index 0000000..6dd8cdf --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.4) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/BundleUtilities/RunCMakeTest.cmake b/Tests/RunCMake/BundleUtilities/RunCMakeTest.cmake new file mode 100644 index 0000000..14aaff1 --- /dev/null +++ b/Tests/RunCMake/BundleUtilities/RunCMakeTest.cmake @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.4) +include(RunCMake) + +# TODO Migrate Tests/BundleUtilities here + +run_cmake(CMP0080-OLD) +run_cmake(CMP0080-NEW) +run_cmake(CMP0080-WARN) +run_cmake_command(CMP0080-COMMAND-OLD ${CMAKE_COMMAND} -DCMP0080_VALUE:STRING=OLD -P ${RunCMake_SOURCE_DIR}/CMP0080-COMMAND.cmake) +run_cmake_command(CMP0080-COMMAND-NEW ${CMAKE_COMMAND} -DCMP0080_VALUE:STRING=NEW -P ${RunCMake_SOURCE_DIR}/CMP0080-COMMAND.cmake) +run_cmake_command(CMP0080-COMMAND-WARN ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/CMP0080-COMMAND.cmake) diff --git a/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-stderr.txt b/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-stderr.txt new file mode 100644 index 0000000..d0a156c --- /dev/null +++ b/Tests/RunCMake/CMP0055/CMP0055-OLD-Out-of-Scope-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0055-OLD-Out-of-Scope.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0055 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-stderr.txt b/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-stderr.txt new file mode 100644 index 0000000..937b352 --- /dev/null +++ b/Tests/RunCMake/CMP0055/CMP0055-OLD-Reject-Arguments-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0055-OLD-Reject-Arguments.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0055 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/CMP0060/CMP0060-OLD-stderr.txt b/Tests/RunCMake/CMP0060/CMP0060-OLD-stderr.txt new file mode 100644 index 0000000..4658747 --- /dev/null +++ b/Tests/RunCMake/CMP0060/CMP0060-OLD-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0060-OLD.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0060 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/CMP0069/RunCMakeTest.cmake b/Tests/RunCMake/CMP0069/RunCMakeTest.cmake index f44f840..456e6a6 100644 --- a/Tests/RunCMake/CMP0069/RunCMakeTest.cmake +++ b/Tests/RunCMake/CMP0069/RunCMakeTest.cmake @@ -5,6 +5,6 @@ run_cmake(CMP0069-NEW-cmake) run_cmake(CMP0069-NEW-compiler) run_cmake(CMP0069-WARN) -if(RunCMake_GENERATOR MATCHES "^Visual Studio ") +if(RunCMake_GENERATOR MATCHES "^Visual Studio 9 ") run_cmake(CMP0069-NEW-generator) endif() 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 c6c90d0..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 @@ -251,6 +252,7 @@ add_RunCMake_test(separate_arguments) add_RunCMake_test(set_property) add_RunCMake_test(string) add_RunCMake_test(test_include_dirs) +add_RunCMake_test(BundleUtilities) function(add_RunCMake_test_try_compile) if(CMAKE_VERSION VERSION_LESS 3.9.20170907 AND "x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC") 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/CheckIPOSupported/RunCMakeTest.cmake b/Tests/RunCMake/CheckIPOSupported/RunCMakeTest.cmake index e145569..b7d524c 100644 --- a/Tests/RunCMake/CheckIPOSupported/RunCMakeTest.cmake +++ b/Tests/RunCMake/CheckIPOSupported/RunCMakeTest.cmake @@ -8,6 +8,6 @@ run_cmake(not-supported-by-compiler) run_cmake(save-to-result) run_cmake(cmp0069-is-old) -if(RunCMake_GENERATOR MATCHES "^Visual Studio ") +if(RunCMake_GENERATOR MATCHES "^Visual Studio 9 ") run_cmake(not-supported-by-generator) endif() diff --git a/Tests/RunCMake/CommandLine/B-no-arg-result.txt b/Tests/RunCMake/CommandLine/B-no-arg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/B-no-arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/B-no-arg-stderr.txt b/Tests/RunCMake/CommandLine/B-no-arg-stderr.txt new file mode 100644 index 0000000..2309c5e --- /dev/null +++ b/Tests/RunCMake/CommandLine/B-no-arg-stderr.txt @@ -0,0 +1 @@ +CMake Error: No build directory specified for -B diff --git a/Tests/RunCMake/CommandLine/B-no-arg2-result.txt b/Tests/RunCMake/CommandLine/B-no-arg2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/B-no-arg2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/B-no-arg2-stderr.txt b/Tests/RunCMake/CommandLine/B-no-arg2-stderr.txt new file mode 100644 index 0000000..2309c5e --- /dev/null +++ b/Tests/RunCMake/CommandLine/B-no-arg2-stderr.txt @@ -0,0 +1 @@ +CMake Error: No build directory specified for -B diff --git a/Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake b/Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake index d7e652d..5df5f2f 100644 --- a/Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake +++ b/Tests/RunCMake/CommandLine/E_create_symlink-broken-create-check.cmake @@ -1,6 +1,10 @@ -if(NOT IS_SYMLINK ${RunCMake_TEST_BINARY_DIR}/L) - set(RunCMake_TEST_FAILED "Symlink 'L' incorrectly not created!") -endif() -if(EXISTS ${RunCMake_TEST_BINARY_DIR}/L) - set(RunCMake_TEST_FAILED "Symlink 'L' not broken!") +if(${actual_stderr_var} MATCHES "operation not permitted") + unset(msg) +else() + if(NOT IS_SYMLINK ${RunCMake_TEST_BINARY_DIR}/L) + set(RunCMake_TEST_FAILED "Symlink 'L' incorrectly not created!") + endif() + if(EXISTS ${RunCMake_TEST_BINARY_DIR}/L) + set(RunCMake_TEST_FAILED "Symlink 'L' not broken!") + endif() endif() diff --git a/Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake b/Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake index c078ae8..d37df01 100644 --- a/Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake +++ b/Tests/RunCMake/CommandLine/E_create_symlink-broken-replace-check.cmake @@ -1,3 +1,7 @@ -if(NOT IS_DIRECTORY ${RunCMake_TEST_BINARY_DIR}/L) - set(RunCMake_TEST_FAILED "Symlink 'L' not replaced correctly!") +if(${actual_stderr_var} MATCHES "operation not permitted") + unset(msg) +else() + if(NOT IS_DIRECTORY ${RunCMake_TEST_BINARY_DIR}/L) + set(RunCMake_TEST_FAILED "Symlink 'L' not replaced correctly!") + endif() endif() diff --git a/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt b/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt new file mode 100644 index 0000000..0ca5a0a --- /dev/null +++ b/Tests/RunCMake/CommandLine/ExplicitDirs/CMakeLists.txt @@ -0,0 +1,8 @@ +cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) +add_custom_command( + OUTPUT output.txt + COMMAND ${CMAKE_COMMAND} -E echo CustomCommand > output.txt + ) +add_custom_target(CustomTarget ALL DEPENDS output.txt) +add_custom_target(CustomTarget2 ALL DEPENDS output.txt) +add_custom_target(CustomTarget3 ALL DEPENDS output.txt) diff --git a/Tests/RunCMake/CommandLine/NoArgs-stdout.txt b/Tests/RunCMake/CommandLine/NoArgs-stdout.txt index 1cd3469..f1dafc8 100644 --- a/Tests/RunCMake/CommandLine/NoArgs-stdout.txt +++ b/Tests/RunCMake/CommandLine/NoArgs-stdout.txt @@ -2,6 +2,7 @@ cmake \[options\] <path-to-source> cmake \[options\] <path-to-existing-build> + cmake \[options\] -S <path-to-source> -B <path-to-build> Specify a source directory to \(re-\)generate a build system for it in the current working directory. Specify an existing build directory to diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index cef2b9b..9859df1 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -48,6 +48,31 @@ run_cmake_command(cache-bad-entry run_cmake_command(cache-empty-entry ${CMAKE_COMMAND} --build ${RunCMake_SOURCE_DIR}/cache-empty-entry/) +function(run_ExplicitDirs) + set(source_dir ${RunCMake_SOURCE_DIR}/ExplicitDirs) + set(binary_dir ${RunCMake_BINARY_DIR}/ExplicitDirs-build) + + file(REMOVE_RECURSE "${binary_dir}") + file(MAKE_DIRECTORY "${binary_dir}") + run_cmake_command(S-arg ${CMAKE_COMMAND} -S ${source_dir} ${binary_dir}) + run_cmake_command(S-arg-reverse-order ${CMAKE_COMMAND} ${binary_dir} -S${source_dir} ) + run_cmake_command(S-no-arg ${CMAKE_COMMAND} -S ) + run_cmake_command(S-no-arg2 ${CMAKE_COMMAND} -S -T) + run_cmake_command(S-B ${CMAKE_COMMAND} -S ${source_dir} -B ${binary_dir}) + + # make sure that -B can explicitly construct build directories + file(REMOVE_RECURSE "${binary_dir}") + run_cmake_command(B-arg ${CMAKE_COMMAND} -B ${binary_dir} ${source_dir}) + file(REMOVE_RECURSE "${binary_dir}") + run_cmake_command(B-arg-reverse-order ${CMAKE_COMMAND} ${source_dir} -B${binary_dir}) + run_cmake_command(B-no-arg ${CMAKE_COMMAND} -B ) + run_cmake_command(B-no-arg2 ${CMAKE_COMMAND} -B -T) + file(REMOVE_RECURSE "${binary_dir}") + run_cmake_command(B-S ${CMAKE_COMMAND} -B${binary_dir} -S${source_dir}) + +endfunction() +run_ExplicitDirs() + function(run_BuildDir) # Use a single build tree for a few tests without cleaning. set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/BuildDir-build) @@ -102,32 +127,35 @@ if(RunCMake_GENERATOR STREQUAL "Ninja") unset(RunCMake_TEST_NO_CLEAN) endif() -if(UNIX) - run_cmake_command(E_create_symlink-no-arg - ${CMAKE_COMMAND} -E create_symlink - ) - run_cmake_command(E_create_symlink-missing-dir - ${CMAKE_COMMAND} -E create_symlink T missing-dir/L - ) +run_cmake_command(E_create_symlink-no-arg + ${CMAKE_COMMAND} -E create_symlink + ) +run_cmake_command(E_create_symlink-missing-dir + ${CMAKE_COMMAND} -E create_symlink T missing-dir/L + ) - # Use a single build tree for a few tests without cleaning. - set(RunCMake_TEST_BINARY_DIR - ${RunCMake_BINARY_DIR}/E_create_symlink-broken-build) - set(RunCMake_TEST_NO_CLEAN 1) - file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") - run_cmake_command(E_create_symlink-broken-create - ${CMAKE_COMMAND} -E create_symlink T L - ) - run_cmake_command(E_create_symlink-broken-replace - ${CMAKE_COMMAND} -E create_symlink . L - ) - unset(RunCMake_TEST_BINARY_DIR) - unset(RunCMake_TEST_NO_CLEAN) +# Use a single build tree for a few tests without cleaning. +# These tests are special on Windows since it will only fail if the user +# running the test does not have the priveldge to create symlinks. If this +# happens we clear the msg in the -check.cmake and say that the test passes +set(RunCMake_DEFAULT_stderr "(operation not permitted)?") +set(RunCMake_TEST_BINARY_DIR + ${RunCMake_BINARY_DIR}/E_create_symlink-broken-build) +set(RunCMake_TEST_NO_CLEAN 1) +file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") +run_cmake_command(E_create_symlink-broken-create + ${CMAKE_COMMAND} -E create_symlink T L + ) +run_cmake_command(E_create_symlink-broken-replace + ${CMAKE_COMMAND} -E create_symlink . L + ) +unset(RunCMake_TEST_BINARY_DIR) +unset(RunCMake_TEST_NO_CLEAN) +unset(RunCMake_DEFAULT_stderr) - run_cmake_command(E_create_symlink-no-replace-dir - ${CMAKE_COMMAND} -E create_symlink T . - ) -endif() +run_cmake_command(E_create_symlink-no-replace-dir + ${CMAKE_COMMAND} -E create_symlink T . + ) set(in ${RunCMake_SOURCE_DIR}/copy_input) set(out ${RunCMake_BINARY_DIR}/copy_output) diff --git a/Tests/RunCMake/CommandLine/S-no-arg-result.txt b/Tests/RunCMake/CommandLine/S-no-arg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-no-arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/S-no-arg-stderr.txt b/Tests/RunCMake/CommandLine/S-no-arg-stderr.txt new file mode 100644 index 0000000..d1a2ce3 --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-no-arg-stderr.txt @@ -0,0 +1 @@ +CMake Error: No source directory specified for -S diff --git a/Tests/RunCMake/CommandLine/S-no-arg2-result.txt b/Tests/RunCMake/CommandLine/S-no-arg2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-no-arg2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/S-no-arg2-stderr.txt b/Tests/RunCMake/CommandLine/S-no-arg2-stderr.txt new file mode 100644 index 0000000..d1a2ce3 --- /dev/null +++ b/Tests/RunCMake/CommandLine/S-no-arg2-stderr.txt @@ -0,0 +1 @@ +CMake Error: No source directory specified for -S diff --git a/Tests/RunCMake/Ninja/CMP0058-OLD-by-stderr.txt b/Tests/RunCMake/Ninja/CMP0058-OLD-by-stderr.txt new file mode 100644 index 0000000..9a606ee --- /dev/null +++ b/Tests/RunCMake/Ninja/CMP0058-OLD-by-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0058-OLD-by.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0058 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/Ninja/CMP0058-OLD-no-stderr.txt b/Tests/RunCMake/Ninja/CMP0058-OLD-no-stderr.txt new file mode 100644 index 0000000..ba6e5da --- /dev/null +++ b/Tests/RunCMake/Ninja/CMP0058-OLD-no-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0058-OLD-no.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0058 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/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/VS10Project/RunCMakeTest.cmake b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake index d50de3d..4bfb2f2 100644 --- a/Tests/RunCMake/VS10Project/RunCMakeTest.cmake +++ b/Tests/RunCMake/VS10Project/RunCMakeTest.cmake @@ -13,3 +13,4 @@ run_cmake(VsCSharpCustomTags) run_cmake(VsCSharpReferenceProps) run_cmake(VsCSharpWithoutSources) run_cmake(VsSdkDirectories) +run_cmake(VsGlobals) diff --git a/Tests/RunCMake/VS10Project/VsGlobals-check.cmake b/Tests/RunCMake/VS10Project/VsGlobals-check.cmake new file mode 100644 index 0000000..0e7fd45 --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsGlobals-check.cmake @@ -0,0 +1,44 @@ +set(vcProjectFile "${RunCMake_TEST_BINARY_DIR}/foo.vcxproj") +if(NOT EXISTS "${vcProjectFile}") + set(RunCMake_TEST_FAILED "Project file ${vcProjectFile} does not exist.") + return() +endif() + +set(InsideGlobals FALSE) +set(DefaultLanguageSet FALSE) +set(MinimumVisualStudioVersionSet FALSE) + +file(STRINGS "${vcProjectFile}" lines) +foreach(line IN LISTS lines) + if(line MATCHES "^ *<PropertyGroup Label=\"Globals\"> *$") + set(InsideGlobals TRUE) + elseif(line MATCHES "^ *<DefaultLanguage>([a-zA-Z\\-]+)</DefaultLanguage> *$") + if("${CMAKE_MATCH_1}" STREQUAL "en-US") + if(InsideGlobals) + message(STATUS "foo.vcxproj has correct DefaultLanguage global property") + set(DefaultLanguageSet TRUE) + else() + message(STATUS "DefaultLanguage is set but not within \"Globals\" property group") + endif() + endif() + elseif(line MATCHES "^ *<MinimumVisualStudioVersion>([0-9\\.]+)</MinimumVisualStudioVersion> *$") + if("${CMAKE_MATCH_1}" STREQUAL "14.0") + if(InsideGlobals) + message(STATUS "foo.vcxproj has correct MinimumVisualStudioVersion global property") + set(MinimumVisualStudioVersionSet TRUE) + else() + message(STATUS "MinimumVisualStudioVersion is set but not within \"Globals\" property group") + endif() + endif() + endif() +endforeach() + +if(NOT DefaultLanguageSet) + set(RunCMake_TEST_FAILED "DefaultLanguageSet not found or not set correctly.") + return() +endif() + +if(NOT MinimumVisualStudioVersionSet) + set(RunCMake_TEST_FAILED "MinimumVisualStudioVersionSet not found or not set correctly.") + return() +endif() diff --git a/Tests/RunCMake/VS10Project/VsGlobals.cmake b/Tests/RunCMake/VS10Project/VsGlobals.cmake new file mode 100644 index 0000000..a3ed5af --- /dev/null +++ b/Tests/RunCMake/VS10Project/VsGlobals.cmake @@ -0,0 +1,8 @@ +enable_language(CXX) + +set(CMAKE_VS_GLOBALS + "DefaultLanguage=en-US" + "MinimumVisualStudioVersion=14.0" +) + +add_library(foo foo.cpp) diff --git a/Tests/RunCMake/VisibilityPreset/CMP0063-OLD-stderr.txt b/Tests/RunCMake/VisibilityPreset/CMP0063-OLD-stderr.txt new file mode 100644 index 0000000..34ac57d --- /dev/null +++ b/Tests/RunCMake/VisibilityPreset/CMP0063-OLD-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0063-OLD.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0063 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/build_command/CMP0061-OLD-make-stderr.txt b/Tests/RunCMake/build_command/CMP0061-OLD-make-stderr.txt index 28e0e72..1938da3 100644 --- a/Tests/RunCMake/build_command/CMP0061-OLD-make-stderr.txt +++ b/Tests/RunCMake/build_command/CMP0061-OLD-make-stderr.txt @@ -1,4 +1,15 @@ -^[^ +^CMake Deprecation Warning at CMP0061-OLD-make.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0061 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) ++ +[^ ]+ --build \. --config "Release" -- -i [^ ]+ --build \. --config "Release" --target "MyTarget" -- -i diff --git a/Tests/RunCMake/build_command/CMP0061-OLD-other-stderr.txt b/Tests/RunCMake/build_command/CMP0061-OLD-other-stderr.txt index 1dde843..85bbdf1 100644 --- a/Tests/RunCMake/build_command/CMP0061-OLD-other-stderr.txt +++ b/Tests/RunCMake/build_command/CMP0061-OLD-other-stderr.txt @@ -1,4 +1,15 @@ -^[^ +^CMake Deprecation Warning at CMP0061-OLD-other.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0061 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) ++ +[^ ]+ --build \. --config "Release" [^ ]+ --build \. --config "Release" --target "MyTarget" diff --git a/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-result.txt b/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-result.txt new file mode 100644 index 0000000..b57e2de --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-result.txt @@ -0,0 +1 @@ +(-1|255) diff --git a/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-stderr.txt b/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-stderr.txt new file mode 100644 index 0000000..a8f10b5 --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-stderr.txt @@ -0,0 +1 @@ + *Error message was: ([Cc]ould *n.t resolve host:? '?-no-site-'?.*|The requested URL returned error:.*) diff --git a/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-stdout.txt b/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-stdout.txt new file mode 100644 index 0000000..11a4edf --- /dev/null +++ b/Tests/RunCMake/ctest_submit/CDashSubmitVerbose-stdout.txt @@ -0,0 +1 @@ +Upload file: .* to http:\/\/-no-site-\?FileName=test-site___test-build-name___.*-Experimental___XML___Configure.xml&build=test-build-name&site=test-site&stamp=.*-Experimental&subproject=mysubproj&MD5=.* Size: .* diff --git a/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake b/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake index ed0e666..7661383 100644 --- a/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake +++ b/Tests/RunCMake/ctest_submit/RunCMakeTest.cmake @@ -30,6 +30,7 @@ run_ctest_submit(CDashUploadNone CDASH_UPLOAD) run_ctest_submit(CDashUploadMissingFile CDASH_UPLOAD bad-upload) run_ctest_submit(CDashUploadRetry CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE} CDASH_UPLOAD_TYPE foo RETRY_COUNT 2 RETRY_DELAY 1 INTERNAL_TEST_CHECKSUM) run_ctest_submit(CDashSubmitQuiet QUIET) +run_ctest_submit_debug(CDashSubmitVerbose) run_ctest_submit_debug(CDashSubmitHeaders HTTPHEADER "Authorization: Bearer asdf") run_ctest_submit_debug(CDashUploadHeaders CDASH_UPLOAD ${CMAKE_CURRENT_LIST_FILE} CDASH_UPLOAD_TYPE foo HTTPHEADER "Authorization: Bearer asdf") diff --git a/Tests/RunCMake/ctest_submit/test.cmake.in b/Tests/RunCMake/ctest_submit/test.cmake.in index ba826f1..35cd16a 100644 --- a/Tests/RunCMake/ctest_submit/test.cmake.in +++ b/Tests/RunCMake/ctest_submit/test.cmake.in @@ -9,6 +9,7 @@ set(CTEST_CMAKE_GENERATOR_PLATFORM "@RunCMake_GENERATOR_PLATFORM@") set(CTEST_CMAKE_GENERATOR_TOOLSET "@RunCMake_GENERATOR_TOOLSET@") set(CTEST_BUILD_CONFIGURATION "$ENV{CMAKE_CONFIG_TYPE}") +set_property(GLOBAL PROPERTY SubProject "mysubproj") ctest_start(Experimental) ctest_configure() diff --git a/Tests/RunCMake/install/CMP0062-OLD-stderr.txt b/Tests/RunCMake/install/CMP0062-OLD-stderr.txt new file mode 100644 index 0000000..de0b70f --- /dev/null +++ b/Tests/RunCMake/install/CMP0062-OLD-stderr.txt @@ -0,0 +1,10 @@ +^CMake Deprecation Warning at CMP0062-OLD.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0062 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/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/Tests/RunCMake/try_compile/CMP0056-stderr.txt b/Tests/RunCMake/try_compile/CMP0056-stderr.txt index 5c1f0e4..de44205 100644 --- a/Tests/RunCMake/try_compile/CMP0056-stderr.txt +++ b/Tests/RunCMake/try_compile/CMP0056-stderr.txt @@ -10,4 +10,15 @@ CMake Warning \(dev\) at CMP0056.cmake:[0-9]+ \(try_compile\): caller link flags \(e.g. CMAKE_EXE_LINKER_FLAGS\) in the test project. Call Stack \(most recent call first\): CMakeLists.txt:[0-9]+ \(include\) -This warning is for project developers. Use -Wno-dev to suppress it.$ +This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Deprecation Warning at CMP0056.cmake:[0-9]+ \(cmake_policy\): + The OLD behavior for policy CMP0056 will be removed from a future version + of CMake. + + The cmake-policies\(7\) manual explains that the OLD behaviors of all + policies are deprecated and that a policy should be set to OLD only under + specific short-term circumstances. Projects should be ported to the NEW + behavior and not rely on setting a policy to OLD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/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/Release/win32_release.cmake b/Utilities/Release/win32_release.cmake index f9e35a5..2e817d9 100644 --- a/Utilities/Release/win32_release.cmake +++ b/Utilities/Release/win32_release.cmake @@ -39,6 +39,6 @@ get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH) set(GIT_EXTRA "git config core.autocrlf true") if(CMAKE_CREATE_VERSION STREQUAL "nightly") # Some tests fail spuriously too often. - set(EXTRA_CTEST_ARGS "-E 'ConsoleBuf'") + set(EXTRA_CTEST_ARGS "-E 'ConsoleBuf|Module.ExternalData'") endif() include(${path}/release_cmake.cmake) diff --git a/Utilities/Release/win64_release.cmake b/Utilities/Release/win64_release.cmake index 02e4096..33af830 100644 --- a/Utilities/Release/win64_release.cmake +++ b/Utilities/Release/win64_release.cmake @@ -39,6 +39,6 @@ get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH) set(GIT_EXTRA "git config core.autocrlf true") if(CMAKE_CREATE_VERSION STREQUAL "nightly") # Some tests fail spuriously too often. - set(EXTRA_CTEST_ARGS "-E 'ConsoleBuf'") + set(EXTRA_CTEST_ARGS "-E 'ConsoleBuf|Module.ExternalData'") endif() include(${path}/release_cmake.cmake) 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. diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt index ba1638e..a503041 100644 --- a/Utilities/cmlibuv/CMakeLists.txt +++ b/Utilities/cmlibuv/CMakeLists.txt @@ -208,6 +208,22 @@ if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") ) endif() +if(CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD") + list(APPEND uv_libraries + freebsd-glue + kvm + ) + list(APPEND uv_headers + include/uv-bsd.h + ) + list(APPEND uv_sources + src/unix/bsd-ifaddrs.c + src/unix/freebsd.c + src/unix/kqueue.c + src/unix/posix-hrtime.c + ) +endif() + if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") list(APPEND uv_libraries kvm @@ -1370,6 +1370,9 @@ else uv_c_flags="${uv_c_flags} -D_GNU_SOURCE" libs="${libs} -ldl -lrt" ;; + *kFreeBSD*) + libs="${libs} -lkvm -lfreebsd-glue" + ;; *BSD*) libs="${libs} -lkvm" ;; |