summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-tidy1
-rw-r--r--Help/command/link_directories.rst50
-rw-r--r--Help/command/target_link_directories.rst55
-rw-r--r--Help/cpack_gen/deb.rst20
-rw-r--r--Help/cpack_gen/rpm.rst6
-rw-r--r--Help/manual/cmake-commands.7.rst1
-rw-r--r--Help/manual/cmake-policies.7.rst1
-rw-r--r--Help/manual/cmake-properties.7.rst2
-rw-r--r--Help/manual/cmake-variables.7.rst1
-rw-r--r--Help/policy/CMP0081.rst22
-rw-r--r--Help/prop_dir/LINK_DIRECTORIES.rst15
-rw-r--r--Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst9
-rw-r--r--Help/prop_tgt/LINK_DIRECTORIES.rst18
-rw-r--r--Help/release/dev/LINK_DIRECTORIES-policy.rst5
-rw-r--r--Help/release/dev/LINK_DIRECTORIES.rst9
-rw-r--r--Help/release/dev/cpack-deb-dbgsym-ddeb.rst6
-rw-r--r--Help/release/dev/link_directories-enhancements.rst5
-rw-r--r--Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst9
-rw-r--r--Modules/FindGLUT.cmake42
-rw-r--r--Modules/Internal/CPack/CPackDeb.cmake106
-rw-r--r--Source/CMakeLists.txt2
-rw-r--r--Source/CMakeVersion.cmake2
-rw-r--r--Source/CPack/cmCPackDebGenerator.cxx944
-rw-r--r--Source/CPack/cmCPackDebGenerator.h2
-rw-r--r--Source/cmCPluginAPI.cxx2
-rw-r--r--Source/cmCommands.cxx3
-rw-r--r--Source/cmComputeLinkInformation.cxx11
-rw-r--r--Source/cmExportBuildFileGenerator.cxx3
-rw-r--r--Source/cmExportFileGenerator.cxx31
-rw-r--r--Source/cmExportFileGenerator.h4
-rw-r--r--Source/cmExportInstallFileGenerator.cxx2
-rw-r--r--Source/cmGeneratorExpression.cxx6
-rw-r--r--Source/cmGeneratorExpression.h9
-rw-r--r--Source/cmGeneratorExpressionDAGChecker.h1
-rw-r--r--Source/cmGeneratorTarget.cxx131
-rw-r--r--Source/cmGeneratorTarget.h8
-rw-r--r--Source/cmIncludeDirectoryCommand.cxx8
-rw-r--r--Source/cmLinkDirectoriesCommand.cxx30
-rw-r--r--Source/cmLinkDirectoriesCommand.h3
-rw-r--r--Source/cmListFileCache.cxx1
-rw-r--r--Source/cmListFileCache.h8
-rw-r--r--Source/cmMakefile.cxx38
-rw-r--r--Source/cmMakefile.h3
-rw-r--r--Source/cmPolicies.h8
-rw-r--r--Source/cmState.cxx5
-rw-r--r--Source/cmStateDirectory.cxx80
-rw-r--r--Source/cmStateDirectory.h10
-rw-r--r--Source/cmStatePrivate.h4
-rw-r--r--Source/cmStateSnapshot.cxx7
-rw-r--r--Source/cmTarget.cxx83
-rw-r--r--Source/cmTarget.h11
-rw-r--r--Source/cmTargetLinkDirectoriesCommand.cxx61
-rw-r--r--Source/cmTargetLinkDirectoriesCommand.h41
-rw-r--r--Tests/CMakeCommands/link_directories/CMakeLists.txt30
-rw-r--r--Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c4
-rw-r--r--Tests/CMakeCommands/target_link_directories/CMakeLists.txt40
-rw-r--r--Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c7
-rw-r--r--Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt2
-rw-r--r--Tests/CMakeLists.txt2
-rw-r--r--Tests/ExportImport/Export/CMakeLists.txt12
-rw-r--r--Tests/ExportImport/Import/A/CMakeLists.txt5
-rw-r--r--Tests/LinkDirectory/External/CMakeLists.txt14
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-Common.cmake5
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt1
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-NEW.cmake4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt1
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-OLD.cmake4
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt1
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt10
-rw-r--r--Tests/RunCMake/CMP0081/CMP0081-WARN.cmake2
-rw-r--r--Tests/RunCMake/CMP0081/CMakeLists.txt3
-rw-r--r--Tests/RunCMake/CMP0081/RunCMakeTest.cmake5
-rw-r--r--Tests/RunCMake/CMP0081/empty.cpp7
-rw-r--r--Tests/RunCMake/CMakeLists.txt1
-rw-r--r--Tests/RunCMake/CPack/DEB/Helpers.cmake2
-rw-r--r--Tests/RunCMake/CPack/RunCMakeTest.cmake2
-rw-r--r--Tests/RunCMake/CPack/VerifyResult.cmake2
-rw-r--r--Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake39
-rw-r--r--Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake4
-rw-r--r--Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt1
-rw-r--r--Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt2
-rw-r--r--Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake3
-rw-r--r--Tests/RunCMake/set_property/RunCMakeTest.cmake1
-rw-r--r--Utilities/Release/linux64_release.cmake7
85 files changed, 1671 insertions, 501 deletions
diff --git a/.clang-tidy b/.clang-tidy
index ebe3c20..8d79b0c 100644
--- a/.clang-tidy
+++ b/.clang-tidy
@@ -5,7 +5,6 @@ misc-*,\
-misc-incorrect-roundings,\
-misc-macro-parentheses,\
-misc-misplaced-widening-cast,\
--misc-noexcept-move-constructor,\
-misc-static-assert,\
modernize-*,\
-modernize-deprecated-headers,\
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/manual/cmake-commands.7.rst b/Help/manual/cmake-commands.7.rst
index 753647d..0cc5fca 100644
--- a/Help/manual/cmake-commands.7.rst
+++ b/Help/manual/cmake-commands.7.rst
@@ -111,6 +111,7 @@ These commands are available only in CMake projects.
/command/target_compile_features
/command/target_compile_options
/command/target_include_directories
+ /command/target_link_directories
/command/target_link_libraries
/command/target_link_options
/command/target_sources
diff --git a/Help/manual/cmake-policies.7.rst b/Help/manual/cmake-policies.7.rst
index 904ebee..2cc52fe 100644
--- a/Help/manual/cmake-policies.7.rst
+++ b/Help/manual/cmake-policies.7.rst
@@ -57,6 +57,7 @@ Policies Introduced by CMake 3.13
.. toctree::
:maxdepth: 1
+ CMP0081: Relative paths not allowed in LINK_DIRECTORIES target property. </policy/CMP0081>
CMP0080: BundleUtilities cannot be included at configure time. </policy/CMP0080>
CMP0079: target_link_libraries allows use with targets in other directories. </policy/CMP0079>
CMP0078: UseSWIG generates standard target names. </policy/CMP0078>
diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst
index 8ccd7f6..5c3eb81 100644
--- a/Help/manual/cmake-properties.7.rst
+++ b/Help/manual/cmake-properties.7.rst
@@ -228,6 +228,7 @@ Properties on Targets
/prop_tgt/INTERFACE_COMPILE_OPTIONS
/prop_tgt/INTERFACE_INCLUDE_DIRECTORIES
/prop_tgt/INTERFACE_LINK_DEPENDS
+ /prop_tgt/INTERFACE_LINK_DIRECTORIES
/prop_tgt/INTERFACE_LINK_LIBRARIES
/prop_tgt/INTERFACE_LINK_OPTIONS
/prop_tgt/INTERFACE_POSITION_INDEPENDENT_CODE
@@ -252,6 +253,7 @@ Properties on Targets
/prop_tgt/LINK_DEPENDS_NO_SHARED
/prop_tgt/LINK_DEPENDS
/prop_tgt/LINKER_LANGUAGE
+ /prop_tgt/LINK_DIRECTORIES
/prop_tgt/LINK_FLAGS_CONFIG
/prop_tgt/LINK_FLAGS
/prop_tgt/LINK_INTERFACE_LIBRARIES_CONFIG
diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst
index 6071999..78353fb 100644
--- a/Help/manual/cmake-variables.7.rst
+++ b/Help/manual/cmake-variables.7.rst
@@ -179,6 +179,7 @@ Variables that Change Behavior
/variable/CMAKE_INSTALL_PREFIX
/variable/CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT
/variable/CMAKE_LIBRARY_PATH
+ /variable/CMAKE_LINK_DIRECTORIES_BEFORE
/variable/CMAKE_MFC_FLAG
/variable/CMAKE_MODULE_PATH
/variable/CMAKE_NOT_USING_CONFIG_FLAGS
diff --git a/Help/policy/CMP0081.rst b/Help/policy/CMP0081.rst
new file mode 100644
index 0000000..d3b2872
--- /dev/null
+++ b/Help/policy/CMP0081.rst
@@ -0,0 +1,22 @@
+CMP0081
+-------
+
+Relative paths not allowed in :prop_tgt:`LINK_DIRECTORIES` target property.
+
+CMake 3.12 and lower allowed the :prop_dir:`LINK_DIRECTORIES` directory
+property to contain relative paths. The base path for such relative
+entries is not well defined. CMake 3.13 and later will issue a
+``FATAL_ERROR`` if the :prop_tgt:`LINK_DIRECTORIES` target property
+(which is initialized by the :prop_dir:`LINK_DIRECTORIES` directory property)
+contains a relative path.
+
+The ``OLD`` behavior for this policy is not to warn about relative paths
+in the :prop_tgt:`LINK_DIRECTORIES` target property. The ``NEW`` behavior for
+this policy is to issue a ``FATAL_ERROR`` if :prop_tgt:`LINK_DIRECTORIES`
+contains a relative path.
+
+This policy was introduced in CMake version 3.13. CMake version
+|release| warns when the policy is not set and uses ``OLD`` behavior. Use
+the :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
+
+.. include:: DEPRECATED.txt
diff --git a/Help/prop_dir/LINK_DIRECTORIES.rst b/Help/prop_dir/LINK_DIRECTORIES.rst
index fa37576..f9fb815 100644
--- a/Help/prop_dir/LINK_DIRECTORIES.rst
+++ b/Help/prop_dir/LINK_DIRECTORIES.rst
@@ -3,6 +3,15 @@ LINK_DIRECTORIES
List of linker search directories.
-This read-only property specifies the list of directories given so far
-to the link_directories command. It is intended for debugging
-purposes.
+This property holds a :ref:`;-list <CMake Language Lists>` of directories
+and is typically populated using the :command:`link_directories` command.
+It gets its initial value from its parent directory, if it has one.
+
+The directory property is used to initialize the :prop_tgt:`LINK_DIRECTORIES`
+target property when a target is created. That target property is used
+by the generators to set the library search directories for the linker.
+
+Contents of ``LINK_DIRECTORIES`` may use "generator expressions" with
+the syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)`
+manual for available expressions. See the :manual:`cmake-buildsystem(7)`
+manual for more on defining buildsystem properties.
diff --git a/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..56a4ec0
--- /dev/null
+++ b/Help/prop_tgt/INTERFACE_LINK_DIRECTORIES.rst
@@ -0,0 +1,9 @@
+INTERFACE_LINK_DIRECTORIES
+--------------------------
+
+.. |property_name| replace:: link directories
+.. |command_name| replace:: :command:`target_link_directories`
+.. |PROPERTY_INTERFACE_NAME| replace:: ``INTERFACE_LINK_DIRECTORIES``
+.. |PROPERTY_LINK| replace:: :prop_tgt:`LINK_DIRECTORIES`
+.. |PROPERTY_GENEX| replace:: ``$<TARGET_PROPERTY:foo,INTERFACE_LINK_DIRECTORIES>``
+.. include:: INTERFACE_BUILD_PROPERTY.txt
diff --git a/Help/prop_tgt/LINK_DIRECTORIES.rst b/Help/prop_tgt/LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..085a701
--- /dev/null
+++ b/Help/prop_tgt/LINK_DIRECTORIES.rst
@@ -0,0 +1,18 @@
+LINK_DIRECTORIES
+----------------
+
+List of directories to use for the link step of shared library, module
+and executable targets.
+
+This property holds a :ref:`;-list <CMake Language Lists>` of directories
+specified so far for its target. Use the :command:`target_link_directories`
+command to append more search directories.
+
+This property is initialized by the :prop_dir:`LINK_DIRECTORIES` directory
+property when a target is created, and is used by the generators to set
+the search directories for the linker.
+
+Contents of ``LINK_DIRECTORIES`` may use "generator expressions" with the
+syntax ``$<...>``. See the :manual:`cmake-generator-expressions(7)` manual
+for available expressions. See the :manual:`cmake-buildsystem(7)` manual
+for more on defining buildsystem properties.
diff --git a/Help/release/dev/LINK_DIRECTORIES-policy.rst b/Help/release/dev/LINK_DIRECTORIES-policy.rst
new file mode 100644
index 0000000..5bbfa51
--- /dev/null
+++ b/Help/release/dev/LINK_DIRECTORIES-policy.rst
@@ -0,0 +1,5 @@
+LINK_DIRECTORIES-policy
+-----------------------
+
+* The :prop_tgt:`LINK_DIRECTORIES` target property expects absolute paths.
+ See policy :policy:`CMP0081`.
diff --git a/Help/release/dev/LINK_DIRECTORIES.rst b/Help/release/dev/LINK_DIRECTORIES.rst
new file mode 100644
index 0000000..dc7d609
--- /dev/null
+++ b/Help/release/dev/LINK_DIRECTORIES.rst
@@ -0,0 +1,9 @@
+LINK_DIRECTORIES
+----------------
+
+* CMake gained new capabilities to manage link directories:
+
+ * :prop_tgt:`LINK_DIRECTORIES` and :prop_tgt:`INTERFACE_LINK_DIRECTORIES`
+ target properties.
+ * :command:`target_link_directories` command to add link directories to
+ targets.
diff --git a/Help/release/dev/cpack-deb-dbgsym-ddeb.rst b/Help/release/dev/cpack-deb-dbgsym-ddeb.rst
new file mode 100644
index 0000000..dc3e96e
--- /dev/null
+++ b/Help/release/dev/cpack-deb-dbgsym-ddeb.rst
@@ -0,0 +1,6 @@
+cpack-deb-dbgsym-ddeb
+---------------------
+
+* The :cpack_gen:`CPack Deb Generator` learned to split debug symbols into
+ a corresponding .ddeb package when ``CPACK_DEBIAN_DEBUGINFO_PACKAGE`` is
+ set.
diff --git a/Help/release/dev/link_directories-enhancements.rst b/Help/release/dev/link_directories-enhancements.rst
new file mode 100644
index 0000000..2521fa1
--- /dev/null
+++ b/Help/release/dev/link_directories-enhancements.rst
@@ -0,0 +1,5 @@
+link_directories-enhancements
+-----------------------------
+
+* :command:`link_directories` command gains capability to control directories
+ insertion position.
diff --git a/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst b/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst
new file mode 100644
index 0000000..026ca35
--- /dev/null
+++ b/Help/variable/CMAKE_LINK_DIRECTORIES_BEFORE.rst
@@ -0,0 +1,9 @@
+CMAKE_LINK_DIRECTORIES_BEFORE
+-----------------------------
+
+Whether to append or prepend directories by default in
+:command:`link_directories`.
+
+This variable affects the default behavior of the :command:`link_directories`
+command. Setting this variable to ``ON`` is equivalent to using the ``BEFORE``
+option in all uses of that command.
diff --git a/Modules/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/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 bfddbc6..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
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 360b561..1f51aa4 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 20180925)
+set(CMake_VERSION_PATCH 20180926)
#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/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx
index 3aa59d6..22ae340 100644
--- a/Source/cmCPluginAPI.cxx
+++ b/Source/cmCPluginAPI.cxx
@@ -171,7 +171,7 @@ void CCONV cmAddLinkDirectoryForTarget(void* arg, const char* tgt,
" for directory ", d);
return;
}
- t->AddLinkDirectory(d);
+ t->InsertLinkDirectory(d, mf->GetBacktrace());
}
void CCONV cmAddExecutable(void* arg, const char* exename, int numSrcs,
diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx
index 15fbd40..873372f 100644
--- a/Source/cmCommands.cxx
+++ b/Source/cmCommands.cxx
@@ -101,6 +101,7 @@
# include "cmRemoveDefinitionsCommand.h"
# include "cmSourceGroupCommand.h"
# include "cmSubdirDependsCommand.h"
+# include "cmTargetLinkDirectoriesCommand.h"
# include "cmTargetLinkOptionsCommand.h"
# include "cmUseMangledMesaCommand.h"
# include "cmUtilitySourceCommand.h"
@@ -278,6 +279,8 @@ void GetProjectCommands(cmState* state)
state->AddBuiltinCommand("link_libraries", new cmLinkLibrariesCommand);
state->AddBuiltinCommand("target_link_options",
new cmTargetLinkOptionsCommand);
+ state->AddBuiltinCommand("target_link_directories",
+ new cmTargetLinkDirectoriesCommand);
state->AddBuiltinCommand("load_cache", new cmLoadCacheCommand);
state->AddBuiltinCommand("qt_wrap_cpp", new cmQTWrapCPPCommand);
state->AddBuiltinCommand("qt_wrap_ui", new cmQTWrapUICommand);
diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx
index a3e135f..0e48ca8 100644
--- a/Source/cmComputeLinkInformation.cxx
+++ b/Source/cmComputeLinkInformation.cxx
@@ -357,10 +357,10 @@ cmComputeLinkInformation::cmComputeLinkInformation(
}
// Add the search path entries requested by the user to path ordering.
- this->OrderLinkerSearchPath->AddUserDirectories(
- this->Target->GetLinkDirectories());
- this->OrderRuntimeSearchPath->AddUserDirectories(
- this->Target->GetLinkDirectories());
+ std::vector<std::string> directories;
+ this->Target->GetLinkDirectories(directories, config, this->LinkLanguage);
+ this->OrderLinkerSearchPath->AddUserDirectories(directories);
+ this->OrderRuntimeSearchPath->AddUserDirectories(directories);
// Set up the implicit link directories.
this->LoadImplicitLinkInfo();
@@ -387,8 +387,7 @@ cmComputeLinkInformation::cmComputeLinkInformation(
if (this->OldLinkDirMode) {
// Construct a mask to not bother with this behavior for link
// directories already specified by the user.
- std::vector<std::string> const& dirs = this->Target->GetLinkDirectories();
- this->OldLinkDirMask.insert(dirs.begin(), dirs.end());
+ this->OldLinkDirMask.insert(directories.begin(), directories.end());
}
this->CMP0060Warn = this->Makefile->PolicyOptionalWarningEnabled(
diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx
index 7f42035..024e641 100644
--- a/Source/cmExportBuildFileGenerator.cxx
+++ b/Source/cmExportBuildFileGenerator.cxx
@@ -98,6 +98,9 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gte,
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
+ this->PopulateInterfaceProperty("INTERFACE_LINK_DIRECTORIES", gte,
+ cmGeneratorExpression::BuildInterface,
+ properties, missingTargets);
this->PopulateInterfaceProperty("INTERFACE_LINK_DEPENDS", gte,
cmGeneratorExpression::BuildInterface,
properties, missingTargets);
diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx
index d6573b8..4cf9dd7 100644
--- a/Source/cmExportFileGenerator.cxx
+++ b/Source/cmExportFileGenerator.cxx
@@ -451,6 +451,37 @@ void cmExportFileGenerator::PopulateLinkDependsInterface(
}
}
+void cmExportFileGenerator::PopulateLinkDirectoriesInterface(
+ cmTargetExport* tei, cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets)
+{
+ cmGeneratorTarget* gt = tei->Target;
+ assert(preprocessRule == cmGeneratorExpression::InstallInterface);
+
+ const char* propName = "INTERFACE_LINK_DIRECTORIES";
+ const char* input = gt->GetProperty(propName);
+
+ if (!input) {
+ return;
+ }
+
+ if (!*input) {
+ properties[propName].clear();
+ return;
+ }
+
+ std::string prepro =
+ cmGeneratorExpression::Preprocess(input, preprocessRule, true);
+ if (!prepro.empty()) {
+ this->ResolveTargetsInGeneratorExpressions(prepro, gt, missingTargets);
+
+ if (!checkInterfaceDirs(prepro, gt, propName)) {
+ return;
+ }
+ properties[propName] = prepro;
+ }
+}
+
void cmExportFileGenerator::PopulateInterfaceProperty(
const std::string& propName, cmGeneratorTarget* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h
index 6ca2e07..41c6538 100644
--- a/Source/cmExportFileGenerator.h
+++ b/Source/cmExportFileGenerator.h
@@ -147,6 +147,10 @@ protected:
cmTargetExport* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
+ void PopulateLinkDirectoriesInterface(
+ cmTargetExport* target,
+ cmGeneratorExpression::PreprocessContext preprocessRule,
+ ImportPropertyMap& properties, std::vector<std::string>& missingTargets);
void PopulateLinkDependsInterface(
cmTargetExport* target,
cmGeneratorExpression::PreprocessContext preprocessRule,
diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx
index bfb7a05..e444087 100644
--- a/Source/cmExportInstallFileGenerator.cxx
+++ b/Source/cmExportInstallFileGenerator.cxx
@@ -106,6 +106,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os)
this->PopulateInterfaceProperty("INTERFACE_LINK_OPTIONS", gt,
cmGeneratorExpression::InstallInterface,
properties, missingTargets);
+ this->PopulateLinkDirectoriesInterface(
+ te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
this->PopulateLinkDependsInterface(
te, cmGeneratorExpression::InstallInterface, properties, missingTargets);
diff --git a/Source/cmGeneratorExpression.cxx b/Source/cmGeneratorExpression.cxx
index 658e9a7..2727d9a 100644
--- a/Source/cmGeneratorExpression.cxx
+++ b/Source/cmGeneratorExpression.cxx
@@ -168,7 +168,7 @@ static std::string stripAllGeneratorExpressions(const std::string& input)
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
- if (c[0] == '$' && c[1] == '<') {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;
@@ -243,7 +243,7 @@ static std::string stripExportInterface(
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
- if (c[0] == '$' && c[1] == '<') {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;
@@ -310,7 +310,7 @@ void cmGeneratorExpression::Split(const std::string& input,
const char* c = input.c_str() + pos;
const char* const cStart = c;
for (; *c; ++c) {
- if (c[0] == '$' && c[1] == '<') {
+ if (cmGeneratorExpression::StartsWithGeneratorExpression(c)) {
++nestingLevel;
++c;
continue;
diff --git a/Source/cmGeneratorExpression.h b/Source/cmGeneratorExpression.h
index 8176d5c..9c05f60 100644
--- a/Source/cmGeneratorExpression.h
+++ b/Source/cmGeneratorExpression.h
@@ -63,6 +63,15 @@ public:
static std::string StripEmptyListElements(const std::string& input);
+ static inline bool StartsWithGeneratorExpression(const std::string& input)
+ {
+ return input.length() >= 2 && input[0] == '$' && input[1] == '<';
+ }
+ static inline bool StartsWithGeneratorExpression(const char* input)
+ {
+ return input != nullptr && input[0] == '$' && input[1] == '<';
+ }
+
private:
cmListFileBacktrace Backtrace;
};
diff --git a/Source/cmGeneratorExpressionDAGChecker.h b/Source/cmGeneratorExpressionDAGChecker.h
index 8b1697b..a5134c3 100644
--- a/Source/cmGeneratorExpressionDAGChecker.h
+++ b/Source/cmGeneratorExpressionDAGChecker.h
@@ -28,6 +28,7 @@ class cmGeneratorTarget;
SELECT(F, EvaluatingSources, SOURCES) \
SELECT(F, EvaluatingCompileFeatures, COMPILE_FEATURES) \
SELECT(F, EvaluatingLinkOptions, LINK_OPTIONS) \
+ SELECT(F, EvaluatingLinkDirectories, LINK_DIRECTORIES) \
SELECT(F, EvaluatingLinkDepends, LINK_DEPENDS)
#define CM_FOR_EACH_TRANSITIVE_PROPERTY(F) \
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index a58d3cb..29c6058 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -103,6 +103,7 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
, DebugCompileFeaturesDone(false)
, DebugCompileDefinitionsDone(false)
, DebugLinkOptionsDone(false)
+ , DebugLinkDirectoriesDone(false)
, DebugSourcesDone(false)
, LinkImplementationLanguageIsContextDependent(true)
, UtilityItemsDone(false)
@@ -133,6 +134,10 @@ cmGeneratorTarget::cmGeneratorTarget(cmTarget* t, cmLocalGenerator* lg)
t->GetLinkOptionsBacktraces(),
this->LinkOptionsEntries);
+ CreatePropertyGeneratorExpressions(t->GetLinkDirectoriesEntries(),
+ t->GetLinkDirectoriesBacktraces(),
+ this->LinkDirectoriesEntries);
+
CreatePropertyGeneratorExpressions(t->GetSourceEntries(),
t->GetSourceBacktraces(),
this->SourceEntries, true);
@@ -150,6 +155,7 @@ cmGeneratorTarget::~cmGeneratorTarget()
cmDeleteAll(this->CompileFeaturesEntries);
cmDeleteAll(this->CompileDefinitionsEntries);
cmDeleteAll(this->LinkOptionsEntries);
+ cmDeleteAll(this->LinkDirectoriesEntries);
cmDeleteAll(this->SourceEntries);
cmDeleteAll(this->LinkInformation);
}
@@ -1704,11 +1710,6 @@ cmListFileBacktrace cmGeneratorTarget::GetBacktrace() const
return this->Target->GetBacktrace();
}
-const std::vector<std::string>& cmGeneratorTarget::GetLinkDirectories() const
-{
- return this->Target->GetLinkDirectories();
-}
-
const std::set<std::string>& cmGeneratorTarget::GetUtilities() const
{
return this->Target->GetUtilities();
@@ -3068,6 +3069,126 @@ void cmGeneratorTarget::GetStaticLibraryLinkOptions(
}
namespace {
+void processLinkDirectories(
+ cmGeneratorTarget const* tgt,
+ const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
+ std::vector<std::string>& directories,
+ std::unordered_set<std::string>& uniqueDirectories,
+ cmGeneratorExpressionDAGChecker* dagChecker, const std::string& config,
+ bool debugDirectories, std::string const& language)
+{
+ for (cmGeneratorTarget::TargetPropertyEntry* entry : entries) {
+ cmLinkImplItem const& item = entry->LinkImplItem;
+ std::string const& targetName = item.AsStr();
+
+ std::vector<std::string> entryDirectories;
+ cmSystemTools::ExpandListArgument(
+ entry->ge->Evaluate(tgt->GetLocalGenerator(), config, false, tgt,
+ dagChecker, language),
+ entryDirectories);
+
+ std::string usedDirectories;
+ for (std::string& entryDirectory : entryDirectories) {
+ if (!cmSystemTools::FileIsFullPath(entryDirectory)) {
+ std::ostringstream e;
+ bool noMessage = false;
+ cmake::MessageType messageType = cmake::FATAL_ERROR;
+ if (!targetName.empty()) {
+ /* clang-format off */
+ e << "Target \"" << targetName << "\" contains relative "
+ "path in its INTERFACE_LINK_DIRECTORIES:\n"
+ " \"" << entryDirectory << "\"";
+ /* clang-format on */
+ } else {
+ switch (tgt->GetPolicyStatusCMP0081()) {
+ case cmPolicies::WARN: {
+ e << cmPolicies::GetPolicyWarning(cmPolicies::CMP0081) << "\n";
+ messageType = cmake::AUTHOR_WARNING;
+ } break;
+ case cmPolicies::OLD:
+ noMessage = true;
+ break;
+ case cmPolicies::REQUIRED_IF_USED:
+ case cmPolicies::REQUIRED_ALWAYS:
+ case cmPolicies::NEW:
+ // Issue the fatal message.
+ break;
+ }
+ e << "Found relative path while evaluating link directories of "
+ "\""
+ << tgt->GetName() << "\":\n \"" << entryDirectory << "\"\n";
+ }
+ if (!noMessage) {
+ tgt->GetLocalGenerator()->IssueMessage(messageType, e.str());
+ if (messageType == cmake::FATAL_ERROR) {
+ return;
+ }
+ }
+ }
+
+ // Sanitize the path the same way the link_directories command does
+ // in case projects set the LINK_DIRECTORIES property directly.
+ cmSystemTools::ConvertToUnixSlashes(entryDirectory);
+ if (uniqueDirectories.insert(entryDirectory).second) {
+ directories.push_back(entryDirectory);
+ if (debugDirectories) {
+ usedDirectories += " * " + entryDirectory + "\n";
+ }
+ }
+ }
+ if (!usedDirectories.empty()) {
+ tgt->GetLocalGenerator()->GetCMakeInstance()->IssueMessage(
+ cmake::LOG,
+ std::string("Used link directories for target ") + tgt->GetName() +
+ ":\n" + usedDirectories,
+ entry->ge->GetBacktrace());
+ }
+ }
+}
+}
+
+void cmGeneratorTarget::GetLinkDirectories(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const
+{
+ std::unordered_set<std::string> uniqueDirectories;
+
+ cmGeneratorExpressionDAGChecker dagChecker(this, "LINK_DIRECTORIES", nullptr,
+ nullptr);
+
+ std::vector<std::string> debugProperties;
+ const char* debugProp =
+ this->Makefile->GetDefinition("CMAKE_DEBUG_TARGET_PROPERTIES");
+ if (debugProp) {
+ cmSystemTools::ExpandListArgument(debugProp, debugProperties);
+ }
+
+ bool debugDirectories = !this->DebugLinkDirectoriesDone &&
+ std::find(debugProperties.begin(), debugProperties.end(),
+ "LINK_DIRECTORIES") != debugProperties.end();
+
+ if (this->GlobalGenerator->GetConfigureDoneCMP0026()) {
+ this->DebugLinkDirectoriesDone = true;
+ }
+
+ processLinkDirectories(this, this->LinkDirectoriesEntries, result,
+ uniqueDirectories, &dagChecker, config,
+ debugDirectories, language);
+
+ std::vector<cmGeneratorTarget::TargetPropertyEntry*>
+ linkInterfaceLinkDirectoriesEntries;
+
+ AddInterfaceEntries(this, config, "INTERFACE_LINK_DIRECTORIES",
+ linkInterfaceLinkDirectoriesEntries);
+
+ processLinkDirectories(this, linkInterfaceLinkDirectoriesEntries, result,
+ uniqueDirectories, &dagChecker, config,
+ debugDirectories, language);
+
+ cmDeleteAll(linkInterfaceLinkDirectoriesEntries);
+}
+
+namespace {
void processLinkDepends(
cmGeneratorTarget const* tgt,
const std::vector<cmGeneratorTarget::TargetPropertyEntry*>& entries,
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 9d8c9f5..bfd95ac 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -273,8 +273,6 @@ public:
cmListFileBacktrace GetBacktrace() const;
- const std::vector<std::string>& GetLinkDirectories() const;
-
std::set<std::string> const& GetUtilities() const;
cmListFileBacktrace const* GetUtilityBacktrace(const std::string& u) const;
@@ -435,6 +433,10 @@ public:
const std::string& config,
const std::string& language) const;
+ void GetLinkDirectories(std::vector<std::string>& result,
+ const std::string& config,
+ const std::string& language) const;
+
void GetLinkDepends(std::vector<std::string>& result,
const std::string& config,
const std::string& language) const;
@@ -825,6 +827,7 @@ private:
std::vector<TargetPropertyEntry*> CompileFeaturesEntries;
std::vector<TargetPropertyEntry*> CompileDefinitionsEntries;
std::vector<TargetPropertyEntry*> LinkOptionsEntries;
+ std::vector<TargetPropertyEntry*> LinkDirectoriesEntries;
std::vector<TargetPropertyEntry*> SourceEntries;
mutable std::set<std::string> LinkImplicitNullProperties;
@@ -874,6 +877,7 @@ private:
mutable bool DebugCompileFeaturesDone;
mutable bool DebugCompileDefinitionsDone;
mutable bool DebugLinkOptionsDone;
+ mutable bool DebugLinkDirectoriesDone;
mutable bool DebugSourcesDone;
mutable bool LinkImplementationLanguageIsContextDependent;
mutable bool UtilityItemsDone;
diff --git a/Source/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/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 e465e1a..4d7e1e2 100644
--- a/Source/cmListFileCache.cxx
+++ b/Source/cmListFileCache.cxx
@@ -377,6 +377,7 @@ cmListFileBacktrace cmListFileBacktrace::Pop() const
cmListFileContext const& cmListFileBacktrace::Top() const
{
assert(this->TopEntry);
+ assert(!this->TopEntry->IsBottom());
return this->TopEntry->Context;
}
diff --git a/Source/cmListFileCache.h b/Source/cmListFileCache.h
index 2c91f7a..3d3afdf 100644
--- a/Source/cmListFileCache.h
+++ b/Source/cmListFileCache.h
@@ -124,9 +124,11 @@ public:
// Backtraces may be copied, moved, and assigned as values.
cmListFileBacktrace(cmListFileBacktrace const&) = default;
- cmListFileBacktrace(cmListFileBacktrace&&) noexcept = default;
+ cmListFileBacktrace(cmListFileBacktrace&&) // NOLINT(clang-tidy)
+ noexcept = default;
cmListFileBacktrace& operator=(cmListFileBacktrace const&) = default;
- cmListFileBacktrace& operator=(cmListFileBacktrace&&) noexcept = default;
+ cmListFileBacktrace& operator=(cmListFileBacktrace&&) // NOLINT(clang-tidy)
+ noexcept = default;
~cmListFileBacktrace() = default;
cmStateSnapshot GetBottom() const;
@@ -144,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.
diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx
index 354da4e..8d163b7 100644
--- a/Source/cmMakefile.cxx
+++ b/Source/cmMakefile.cxx
@@ -243,6 +243,17 @@ cmBacktraceRange cmMakefile::GetLinkOptionsBacktraces() const
return this->StateSnapshot.GetDirectory().GetLinkOptionsEntryBacktraces();
}
+cmStringRange cmMakefile::GetLinkDirectoriesEntries() const
+{
+ return this->StateSnapshot.GetDirectory().GetLinkDirectoriesEntries();
+}
+
+cmBacktraceRange cmMakefile::GetLinkDirectoriesBacktraces() const
+{
+ return this->StateSnapshot.GetDirectory()
+ .GetLinkDirectoriesEntryBacktraces();
+}
+
cmListFileBacktrace cmMakefile::GetBacktrace() const
{
return this->Backtrace;
@@ -1237,6 +1248,18 @@ void cmMakefile::AddLinkOption(std::string const& option)
this->AppendProperty("LINK_OPTIONS", option.c_str());
}
+void cmMakefile::AddLinkDirectory(std::string const& directory, bool before)
+{
+ cmListFileBacktrace lfbt = this->GetBacktrace();
+ if (before) {
+ this->StateSnapshot.GetDirectory().PrependLinkDirectoriesEntry(directory,
+ lfbt);
+ } else {
+ this->StateSnapshot.GetDirectory().AppendLinkDirectoriesEntry(directory,
+ lfbt);
+ }
+}
+
bool cmMakefile::ParseDefineFlag(std::string const& def, bool remove)
{
// Create a regular expression to match valid definitions.
@@ -1335,10 +1358,6 @@ void cmMakefile::InitializeFromParent(cmMakefile* parent)
// link libraries
this->SetProperty("LINK_LIBRARIES", parent->GetProperty("LINK_LIBRARIES"));
- // link directories
- this->SetProperty("LINK_DIRECTORIES",
- parent->GetProperty("LINK_DIRECTORIES"));
-
// the initial project name
this->StateSnapshot.SetProjectName(parent->StateSnapshot.GetProjectName());
@@ -1872,17 +1891,6 @@ void cmMakefile::AddGlobalLinkInformation(cmTarget& target)
return;
default:;
}
- if (const char* linkDirsProp = this->GetProperty("LINK_DIRECTORIES")) {
- std::vector<std::string> linkDirs;
- cmSystemTools::ExpandListArgument(linkDirsProp, linkDirs);
-
- for (std::string& linkDir : linkDirs) {
- // Sanitize the path the same way the link_directories command does
- // in case projects set the LINK_DIRECTORIES property directly.
- cmSystemTools::ConvertToUnixSlashes(linkDir);
- target.AddLinkDirectory(linkDir);
- }
- }
if (const char* linkLibsProp = this->GetProperty("LINK_LIBRARIES")) {
std::vector<std::string> linkLibs;
diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h
index bb01c0b..b30f281 100644
--- a/Source/cmMakefile.h
+++ b/Source/cmMakefile.h
@@ -182,6 +182,7 @@ public:
void AddCompileDefinition(std::string const& definition);
void AddCompileOption(std::string const& option);
void AddLinkOption(std::string const& option);
+ void AddLinkDirectory(std::string const& directory, bool before = false);
/** Create a new imported target with the name and type given. */
cmTarget* AddImportedTarget(const std::string& name,
@@ -802,6 +803,8 @@ public:
cmBacktraceRange GetCompileDefinitionsBacktraces() const;
cmStringRange GetLinkOptionsEntries() const;
cmBacktraceRange GetLinkOptionsBacktraces() const;
+ cmStringRange GetLinkDirectoriesEntries() const;
+ cmBacktraceRange GetLinkDirectoriesBacktraces() const;
std::set<std::string> const& GetSystemIncludeDirectories() const
{
diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h
index f99cc0f..a367e47 100644
--- a/Source/cmPolicies.h
+++ b/Source/cmPolicies.h
@@ -237,7 +237,10 @@ class cmMakefile;
13, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0080, \
"BundleUtilities cannot be included at configure time", 3, 13, 0, \
- cmPolicies::WARN)
+ cmPolicies::WARN) \
+ SELECT(POLICY, CMP0081, \
+ "Relative paths not allowed in LINK_DIRECTORIES target property.", \
+ 3, 13, 0, cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \
@@ -263,7 +266,8 @@ class cmMakefile;
F(CMP0068) \
F(CMP0069) \
F(CMP0073) \
- F(CMP0076)
+ F(CMP0076) \
+ F(CMP0081)
/** \class cmPolicies
* \brief Handles changes in CMake behavior and policies
diff --git a/Source/cmState.cxx b/Source/cmState.cxx
index c6667f6..4b65cf1 100644
--- a/Source/cmState.cxx
+++ b/Source/cmState.cxx
@@ -284,6 +284,8 @@ cmStateSnapshot cmState::Reset()
it->CompileOptionsBacktraces.clear();
it->LinkOptions.clear();
it->LinkOptionsBacktraces.clear();
+ it->LinkDirectories.clear();
+ it->LinkDirectoriesBacktraces.clear();
it->DirectoryEnd = pos;
it->NormalTargetNames.clear();
it->Properties.clear();
@@ -660,6 +662,7 @@ cmStateSnapshot cmState::CreateBaseSnapshot()
pos->CompileDefinitionsPosition = 0;
pos->CompileOptionsPosition = 0;
pos->LinkOptionsPosition = 0;
+ pos->LinkDirectoriesPosition = 0;
pos->BuildSystemDirectory->DirectoryEnd = pos;
pos->Policies = this->PolicyStack.Root();
pos->PolicyRoot = this->PolicyStack.Root();
@@ -813,6 +816,8 @@ cmStateSnapshot cmState::Pop(cmStateSnapshot const& originSnapshot)
prevPos->BuildSystemDirectory->CompileOptions.size();
prevPos->LinkOptionsPosition =
prevPos->BuildSystemDirectory->LinkOptions.size();
+ prevPos->LinkDirectoriesPosition =
+ prevPos->BuildSystemDirectory->LinkDirectories.size();
prevPos->BuildSystemDirectory->DirectoryEnd = prevPos;
if (!pos->Keep && this->SnapshotData.IsLast(pos)) {
diff --git a/Source/cmStateDirectory.cxx b/Source/cmStateDirectory.cxx
index 925b161..f94e714 100644
--- a/Source/cmStateDirectory.cxx
+++ b/Source/cmStateDirectory.cxx
@@ -396,6 +396,70 @@ void cmStateDirectory::ClearLinkOptions()
this->Snapshot_.Position->LinkOptionsPosition);
}
+cmStringRange cmStateDirectory::GetLinkDirectoriesEntries() const
+{
+ return GetPropertyContent(this->DirectoryState->LinkDirectories,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
+cmBacktraceRange cmStateDirectory::GetLinkDirectoriesEntryBacktraces() const
+{
+ return GetPropertyBacktraces(
+ this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
+void cmStateDirectory::AppendLinkDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ AppendEntry(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
+}
+void cmStateDirectory::PrependLinkDirectoriesEntry(
+ const std::string& vec, const cmListFileBacktrace& lfbt)
+{
+ std::vector<std::string>::iterator entryEnd =
+ this->DirectoryState->LinkDirectories.begin() +
+ this->Snapshot_.Position->LinkDirectoriesPosition;
+
+ std::vector<std::string>::reverse_iterator rend =
+ this->DirectoryState->LinkDirectories.rend();
+ std::vector<std::string>::reverse_iterator rbegin =
+ cmMakeReverseIterator(entryEnd);
+ rbegin = std::find(rbegin, rend, cmPropertySentinal);
+
+ std::vector<std::string>::iterator entryIt = rbegin.base();
+ std::vector<std::string>::iterator entryBegin =
+ this->DirectoryState->LinkDirectories.begin();
+
+ std::vector<cmListFileBacktrace>::iterator btIt =
+ this->DirectoryState->LinkDirectoriesBacktraces.begin() +
+ std::distance(entryBegin, entryIt);
+
+ this->DirectoryState->LinkDirectories.insert(entryIt, vec);
+ this->DirectoryState->LinkDirectoriesBacktraces.insert(btIt, lfbt);
+
+ this->Snapshot_.Position->LinkDirectoriesPosition =
+ this->DirectoryState->LinkDirectories.size();
+}
+
+void cmStateDirectory::SetLinkDirectories(const std::string& vec,
+ const cmListFileBacktrace& lfbt)
+{
+ SetContent(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition, vec, lfbt);
+}
+
+void cmStateDirectory::ClearLinkDirectories()
+{
+ ClearContent(this->DirectoryState->LinkDirectories,
+ this->DirectoryState->LinkDirectoriesBacktraces,
+ this->Snapshot_.Position->LinkDirectoriesPosition);
+}
+
void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
cmListFileBacktrace const& lfbt)
{
@@ -431,6 +495,14 @@ void cmStateDirectory::SetProperty(const std::string& prop, const char* value,
this->SetLinkOptions(value, lfbt);
return;
}
+ if (prop == "LINK_DIRECTORIES") {
+ if (!value) {
+ this->ClearLinkDirectories();
+ return;
+ }
+ this->SetLinkDirectories(value, lfbt);
+ return;
+ }
this->DirectoryState->Properties.SetProperty(prop, value);
}
@@ -455,6 +527,10 @@ void cmStateDirectory::AppendProperty(const std::string& prop,
this->AppendLinkOptionsEntry(value, lfbt);
return;
}
+ if (prop == "LINK_DIRECTORIES") {
+ this->AppendLinkDirectoriesEntry(value, lfbt);
+ return;
+ }
this->DirectoryState->Properties.AppendProperty(prop, value, asString);
}
@@ -542,6 +618,10 @@ const char* cmStateDirectory::GetProperty(const std::string& prop,
output = cmJoin(this->GetLinkOptionsEntries(), ";");
return output.c_str();
}
+ if (prop == "LINK_DIRECTORIES") {
+ output = cmJoin(this->GetLinkDirectoriesEntries(), ";");
+ return output.c_str();
+ }
const char* retVal = this->DirectoryState->Properties.GetPropertyValue(prop);
if (!retVal && chain) {
diff --git a/Source/cmStateDirectory.h b/Source/cmStateDirectory.h
index 412664f..e5f4d05 100644
--- a/Source/cmStateDirectory.h
+++ b/Source/cmStateDirectory.h
@@ -62,9 +62,19 @@ public:
cmBacktraceRange GetLinkOptionsEntryBacktraces() const;
void AppendLinkOptionsEntry(std::string const& vec,
cmListFileBacktrace const& lfbt);
+ void PrependLinkDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
void SetLinkOptions(std::string const& vec, cmListFileBacktrace const& lfbt);
void ClearLinkOptions();
+ cmStringRange GetLinkDirectoriesEntries() const;
+ cmBacktraceRange GetLinkDirectoriesEntryBacktraces() const;
+ void AppendLinkDirectoriesEntry(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void SetLinkDirectories(std::string const& vec,
+ cmListFileBacktrace const& lfbt);
+ void ClearLinkDirectories();
+
void SetProperty(const std::string& prop, const char* value,
cmListFileBacktrace const& lfbt);
void AppendProperty(const std::string& prop, const char* value,
diff --git a/Source/cmStatePrivate.h b/Source/cmStatePrivate.h
index 7177221..e76f2af 100644
--- a/Source/cmStatePrivate.h
+++ b/Source/cmStatePrivate.h
@@ -43,6 +43,7 @@ struct cmStateDetail::SnapshotDataType
std::vector<std::string>::size_type CompileDefinitionsPosition;
std::vector<std::string>::size_type CompileOptionsPosition;
std::vector<std::string>::size_type LinkOptionsPosition;
+ std::vector<std::string>::size_type LinkDirectoriesPosition;
};
struct cmStateDetail::PolicyStackEntry : public cmPolicies::PolicyMap
@@ -88,6 +89,9 @@ struct cmStateDetail::BuildsystemDirectoryStateType
std::vector<std::string> LinkOptions;
std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
+ std::vector<std::string> LinkDirectories;
+ std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
+
std::vector<std::string> NormalTargetNames;
std::string ProjectName;
diff --git a/Source/cmStateSnapshot.cxx b/Source/cmStateSnapshot.cxx
index 0379e7e..c2510f3 100644
--- a/Source/cmStateSnapshot.cxx
+++ b/Source/cmStateSnapshot.cxx
@@ -398,6 +398,13 @@ void cmStateSnapshot::InitializeFromParent()
this->Position->BuildSystemDirectory->LinkOptionsBacktraces,
this->Position->LinkOptionsPosition);
+ InitializeContentFromParent(
+ parent->BuildSystemDirectory->LinkDirectories,
+ this->Position->BuildSystemDirectory->LinkDirectories,
+ parent->BuildSystemDirectory->LinkDirectoriesBacktraces,
+ this->Position->BuildSystemDirectory->LinkDirectoriesBacktraces,
+ this->Position->LinkDirectoriesPosition);
+
const char* include_regex =
parent->BuildSystemDirectory->Properties.GetPropertyValue(
"INCLUDE_REGULAR_EXPRESSION");
diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx
index 4e353c7..c5295f2 100644
--- a/Source/cmTarget.cxx
+++ b/Source/cmTarget.cxx
@@ -168,6 +168,8 @@ public:
std::vector<cmListFileBacktrace> SourceBacktraces;
std::vector<std::string> LinkOptionsEntries;
std::vector<cmListFileBacktrace> LinkOptionsBacktraces;
+ std::vector<std::string> LinkDirectoriesEntries;
+ std::vector<cmListFileBacktrace> LinkDirectoriesBacktraces;
std::vector<std::string> LinkImplementationPropertyEntries;
std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces;
};
@@ -391,6 +393,18 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
this->Internal->LinkOptionsBacktraces.insert(
this->Internal->LinkOptionsBacktraces.end(),
parentLinkOptionsBts.begin(), parentLinkOptionsBts.end());
+
+ const cmStringRange parentLinkDirectories =
+ this->Makefile->GetLinkDirectoriesEntries();
+ const cmBacktraceRange parentLinkDirectoriesBts =
+ this->Makefile->GetLinkDirectoriesBacktraces();
+
+ this->Internal->LinkDirectoriesEntries.insert(
+ this->Internal->LinkDirectoriesEntries.end(),
+ parentLinkDirectories.begin(), parentLinkDirectories.end());
+ this->Internal->LinkDirectoriesBacktraces.insert(
+ this->Internal->LinkDirectoriesBacktraces.end(),
+ parentLinkDirectoriesBts.begin(), parentLinkDirectoriesBts.end());
}
if (this->GetType() != cmStateEnums::INTERFACE_LIBRARY &&
@@ -514,9 +528,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()) {
@@ -656,19 +668,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();
@@ -876,6 +875,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);
@@ -902,6 +911,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);
@@ -988,6 +998,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();
@@ -1099,6 +1117,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();
@@ -1196,6 +1220,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,
@@ -1316,6 +1355,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);
@@ -1332,6 +1372,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);
@@ -1399,6 +1440,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/Tests/CMakeCommands/link_directories/CMakeLists.txt b/Tests/CMakeCommands/link_directories/CMakeLists.txt
new file mode 100644
index 0000000..60c07b6
--- /dev/null
+++ b/Tests/CMakeCommands/link_directories/CMakeLists.txt
@@ -0,0 +1,30 @@
+cmake_minimum_required(VERSION 3.12)
+
+project(link_directories LANGUAGES C)
+
+
+link_directories(/A)
+link_directories(BEFORE /B)
+
+set(CMAKE_LINK_DIRECTORIES_BEFORE ON)
+link_directories(/C)
+
+get_directory_property(result LINK_DIRECTORIES)
+if (NOT result MATCHES "/C;/B;/A")
+ message(SEND_ERROR "link_directories not populated the LINK_DIRECTORIES directory property")
+endif()
+
+
+add_executable(link_directories EXCLUDE_FROM_ALL LinkDirectoriesExe.c)
+
+get_target_property(result link_directories LINK_DIRECTORIES)
+if (NOT result MATCHES "/C;/B;/A")
+ message(SEND_ERROR "link_directories not populated the LINK_DIRECTORIES target property")
+endif()
+
+
+add_library(imp UNKNOWN IMPORTED)
+get_target_property(result imp LINK_DIRECTORIES)
+if (result)
+ message(FATAL_ERROR "link_directories populated the LINK_DIRECTORIES target property")
+endif()
diff --git a/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c b/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c
new file mode 100644
index 0000000..8488f4e
--- /dev/null
+++ b/Tests/CMakeCommands/link_directories/LinkDirectoriesExe.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_directories/CMakeLists.txt b/Tests/CMakeCommands/target_link_directories/CMakeLists.txt
new file mode 100644
index 0000000..bc7b9b2
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/CMakeLists.txt
@@ -0,0 +1,40 @@
+
+cmake_minimum_required(VERSION 3.12)
+
+project(target_link_directories LANGUAGES C)
+
+add_library(target_link_directories SHARED LinkDirectoriesLib.c)
+# Test no items
+target_link_directories(target_link_directories PRIVATE)
+
+add_library(target_link_directories_2 SHARED EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_2 PRIVATE /private/dir INTERFACE /interface/dir)
+get_target_property(result target_link_directories_2 LINK_DIRECTORIES)
+if (NOT result MATCHES "/private/dir")
+ message(SEND_ERROR "${result} target_link_directories not populated the LINK_DIRECTORIES target property")
+endif()
+get_target_property(result target_link_directories_2 INTERFACE_LINK_DIRECTORIES)
+if (NOT result MATCHES "/interface/dir")
+ message(SEND_ERROR "target_link_directories not populated the INTERFACE_LINK_DIRECTORIES target property of shared library")
+endif()
+
+add_library(target_link_directories_3 STATIC EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_3 INTERFACE /interface/dir)
+get_target_property(result target_link_directories_3 INTERFACE_LINK_DIRECTORIES)
+if (NOT result MATCHES "/interface/dir")
+ message(SEND_ERROR "target_link_directories not populated the INTERFACE_LINK_DIRECTORIES target property of static library")
+endif()
+
+add_library(target_link_directories_4 SHARED EXCLUDE_FROM_ALL LinkDirectoriesLib.c)
+target_link_directories(target_link_directories_4 PRIVATE relative/dir)
+get_target_property(result target_link_directories_4 LINK_DIRECTORIES)
+if (NOT result MATCHES "${CMAKE_CURRENT_SOURCE_DIR}/relative/dir")
+ message(SEND_ERROR "target_link_directories not populated the LINK_DIRECTORIES with relative path")
+endif()
+
+add_subdirectory(subdir)
+target_link_directories(target_link_directories_5 PRIVATE relative/dir)
+get_target_property(result target_link_directories_5 LINK_DIRECTORIES)
+if (NOT result MATCHES "${CMAKE_CURRENT_SOURCE_DIR}/relative/dir")
+ message(SEND_ERROR "target_link_directories not populated the LINK_DIRECTORIES with relative path")
+endif()
diff --git a/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c b/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c
new file mode 100644
index 0000000..9bbd24c
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/LinkDirectoriesLib.c
@@ -0,0 +1,7 @@
+#if defined(_WIN32)
+__declspec(dllexport)
+#endif
+ int flags_lib(void)
+{
+ return 0;
+}
diff --git a/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt b/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt
new file mode 100644
index 0000000..7e7ad2a
--- /dev/null
+++ b/Tests/CMakeCommands/target_link_directories/subdir/CMakeLists.txt
@@ -0,0 +1,2 @@
+
+add_library(target_link_directories_5 SHARED EXCLUDE_FROM_ALL ../LinkDirectoriesLib.c)
diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt
index fb44077..83349e3 100644
--- a/Tests/CMakeLists.txt
+++ b/Tests/CMakeLists.txt
@@ -2830,6 +2830,8 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release
ADD_TEST_MACRO(CMakeCommands.add_link_options)
ADD_TEST_MACRO(CMakeCommands.target_link_options)
+ ADD_TEST_MACRO(CMakeCommands.link_directories)
+ ADD_TEST_MACRO(CMakeCommands.target_link_directories)
# The cmake server-mode test requires python for a simple client.
find_package(PythonInterp QUIET)
diff --git a/Tests/ExportImport/Export/CMakeLists.txt b/Tests/ExportImport/Export/CMakeLists.txt
index cb048be..c6b7dbc 100644
--- a/Tests/ExportImport/Export/CMakeLists.txt
+++ b/Tests/ExportImport/Export/CMakeLists.txt
@@ -619,6 +619,18 @@ export(TARGETS testLinkOptions NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
#------------------------------------------------------------------------------
+# test export of INTERFACE_LINK_DIRECTORIES
+add_library(testLinkDirectories INTERFACE)
+target_link_directories(testLinkDirectories INTERFACE
+ $<BUILD_INTERFACE:/interface/build>
+ $<INSTALL_INTERFACE:interface/install>)
+
+install(TARGETS testLinkDirectories
+ EXPORT RequiredExp DESTINATION lib)
+export(TARGETS testLinkDirectories NAMESPACE bld_ APPEND FILE ExportBuildTree.cmake)
+
+
+#------------------------------------------------------------------------------
# test export of INTERFACE_LINK_DEPENDS
if(CMAKE_GENERATOR MATCHES "Make|Ninja")
add_library(testLinkDepends INTERFACE)
diff --git a/Tests/ExportImport/Import/A/CMakeLists.txt b/Tests/ExportImport/Import/A/CMakeLists.txt
index 8791a19..67fcc02 100644
--- a/Tests/ExportImport/Import/A/CMakeLists.txt
+++ b/Tests/ExportImport/Import/A/CMakeLists.txt
@@ -490,6 +490,11 @@ checkForProperty(bld_testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
checkForProperty(Req::testLinkOptions "INTERFACE_LINK_OPTIONS" "INTERFACE_FLAG")
#---------------------------------------------------------------------------------
+# check that imported libraries have the expected INTERFACE_LINK_DIRECTORIES property
+checkForProperty(bld_testLinkDirectories "INTERFACE_LINK_DIRECTORIES" "/interface/build")
+checkForProperty(Req::testLinkDirectories "INTERFACE_LINK_DIRECTORIES" "${CMAKE_INSTALL_PREFIX}/interface/install")
+
+#---------------------------------------------------------------------------------
# check that imported libraries have the expected INTERFACE_LINK_DEPENDS property
if(CMAKE_GENERATOR MATCHES "Make|Ninja")
checkForProperty(bld_testLinkDepends "INTERFACE_LINK_DEPENDS" "BUILD_LINK_DEPENDS")
diff --git a/Tests/LinkDirectory/External/CMakeLists.txt b/Tests/LinkDirectory/External/CMakeLists.txt
index f7c840f..d2a1f9f 100644
--- a/Tests/LinkDirectory/External/CMakeLists.txt
+++ b/Tests/LinkDirectory/External/CMakeLists.txt
@@ -1,6 +1,20 @@
cmake_minimum_required(VERSION 2.8)
project(LinkDirectoryExternal C)
+
+add_executable(myexe2 myexe.c)
+set_property(TARGET myexe2 PROPERTY OUTPUT_NAME LinkDirectory2)
+target_link_directories(myexe2 PRIVATE lib "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
+target_link_libraries(myexe2 PRIVATE mylibA mylibB)
+
+add_library (mylibs INTERFACE)
+target_link_directories(mylibs INTERFACE lib "${CMAKE_CURRENT_SOURCE_DIR}/../lib")
+target_link_libraries(mylibs INTERFACE mylibA mylibB)
+add_executable(myexe3 myexe.c)
+set_property(TARGET myexe3 PROPERTY OUTPUT_NAME LinkDirectory3)
+target_link_libraries(myexe3 PRIVATE mylibs)
+
+
# Test CMP0015 OLD behavior: -L../lib
cmake_policy(SET CMP0015 OLD)
link_directories(../lib)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-Common.cmake b/Tests/RunCMake/CMP0081/CMP0081-Common.cmake
new file mode 100644
index 0000000..3ea5277
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-Common.cmake
@@ -0,0 +1,5 @@
+
+enable_language(CXX)
+
+add_library(foo SHARED empty.cpp)
+set_target_properties(foo PROPERTIES LINK_DIRECTORIES "../lib")
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt b/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt
new file mode 100644
index 0000000..d31c149
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW-stderr.txt
@@ -0,0 +1,4 @@
+CMake Error in CMakeLists.txt:
+ Found relative path while evaluating link directories of "foo":
+
+ "../lib"
diff --git a/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake b/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake
new file mode 100644
index 0000000..9b927a2
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-NEW.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0081 NEW)
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt b/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-OLD-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake b/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake
new file mode 100644
index 0000000..2e91bf6
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-OLD.cmake
@@ -0,0 +1,4 @@
+
+cmake_policy(SET CMP0081 OLD)
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt b/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt
new file mode 100644
index 0000000..573541a
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN-result.txt
@@ -0,0 +1 @@
+0
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt b/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt
new file mode 100644
index 0000000..eac0648
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN-stderr.txt
@@ -0,0 +1,10 @@
+CMake Warning \(dev\) in CMakeLists.txt:
+ Policy CMP0081 is not set: Relative paths not allowed in LINK_DIRECTORIES
+ target property. Run "cmake --help-policy CMP0081" for policy details.
+ Use the cmake_policy command to set the policy and suppress this warning.
+
+ Found relative path while evaluating link directories of "foo":
+
+ "../lib"
+
+This warning is for project developers. Use -Wno-dev to suppress it.
diff --git a/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake b/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake
new file mode 100644
index 0000000..33bb21d
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMP0081-WARN.cmake
@@ -0,0 +1,2 @@
+
+include (CMP0081-Common.cmake)
diff --git a/Tests/RunCMake/CMP0081/CMakeLists.txt b/Tests/RunCMake/CMP0081/CMakeLists.txt
new file mode 100644
index 0000000..ef2163c
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.1)
+project(${RunCMake_TEST} NONE)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/CMP0081/RunCMakeTest.cmake b/Tests/RunCMake/CMP0081/RunCMakeTest.cmake
new file mode 100644
index 0000000..335d8c5
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/RunCMakeTest.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+run_cmake(CMP0081-OLD)
+run_cmake(CMP0081-NEW)
+run_cmake(CMP0081-WARN)
diff --git a/Tests/RunCMake/CMP0081/empty.cpp b/Tests/RunCMake/CMP0081/empty.cpp
new file mode 100644
index 0000000..11ec041
--- /dev/null
+++ b/Tests/RunCMake/CMP0081/empty.cpp
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+ int empty()
+{
+ return 0;
+}
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 69cb5b7..080d0d0 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -106,6 +106,7 @@ if(CMAKE_SYSTEM_NAME MATCHES Darwin AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG)
add_RunCMake_test(CMP0068)
endif()
add_RunCMake_test(CMP0069)
+add_RunCMake_test(CMP0081)
# The test for Policy 65 requires the use of the
# CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode
diff --git a/Tests/RunCMake/CPack/DEB/Helpers.cmake b/Tests/RunCMake/CPack/DEB/Helpers.cmake
index e01f81d..9b98ed4 100644
--- a/Tests/RunCMake/CPack/DEB/Helpers.cmake
+++ b/Tests/RunCMake/CPack/DEB/Helpers.cmake
@@ -1,4 +1,4 @@
-set(ALL_FILES_GLOB "*.deb")
+set(ALL_FILES_GLOB "*.deb" "*.ddeb")
function(getPackageContent FILE RESULT_VAR)
execute_process(COMMAND ${CMAKE_COMMAND} -E env TZ=Etc/UTC ${DPKG_EXECUTABLE} -c "${FILE}"
diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake
index 91fed3e..91d3cb7 100644
--- a/Tests/RunCMake/CPack/RunCMakeTest.cmake
+++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake
@@ -6,7 +6,7 @@ include("${RunCMake_SOURCE_DIR}/CPackTestHelpers.cmake")
# run_cpack_test args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP "PACKAGING_TYPES"
run_cpack_test(CUSTOM_BINARY_SPEC_FILE "RPM" false "MONOLITHIC;COMPONENT")
run_cpack_test(CUSTOM_NAMES "RPM;DEB;TGZ" true "COMPONENT")
-run_cpack_test(DEBUGINFO "RPM" true "COMPONENT")
+run_cpack_test(DEBUGINFO "RPM;DEB" true "COMPONENT")
run_cpack_test_subtests(DEFAULT_PERMISSIONS "CMAKE_var_set;CPACK_var_set;both_set;invalid_CMAKE_var;invalid_CPACK_var" "RPM;DEB" false "MONOLITHIC;COMPONENT")
run_cpack_test(DEPENDENCIES "RPM;DEB" true "COMPONENT")
run_cpack_test(DIST "RPM" false "MONOLITHIC")
diff --git a/Tests/RunCMake/CPack/VerifyResult.cmake b/Tests/RunCMake/CPack/VerifyResult.cmake
index af12d37..345b37f 100644
--- a/Tests/RunCMake/CPack/VerifyResult.cmake
+++ b/Tests/RunCMake/CPack/VerifyResult.cmake
@@ -92,7 +92,7 @@ if(NOT EXPECTED_FILES_COUNT EQUAL 0)
# check that there were no extra files generated
foreach(all_files_glob_ IN LISTS ALL_FILES_GLOB)
file(GLOB foundAll_ RELATIVE "${bin_dir}" "${all_files_glob_}")
- list(APPEND allFoundFiles_ "${foundAll_}")
+ list(APPEND allFoundFiles_ ${foundAll_})
endforeach()
list(LENGTH foundFiles_ foundFilesCount_)
diff --git a/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake b/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
index c745828..cf2e8ac 100644
--- a/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
+++ b/Tests/RunCMake/CPack/tests/DEBUGINFO/ExpectedFiles.cmake
@@ -3,16 +3,39 @@ set(whitespaces_ "[\t\n\r ]*")
set(EXPECTED_FILES_COUNT "5")
set(EXPECTED_FILES_NAME_GENERATOR_SPECIFIC_FORMAT TRUE)
-set(EXPECTED_FILE_1_NAME "Debuginfo")
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(NAME "Debuginfo")
+ set(DEBUG_SUFFIX "debuginfo")
+ set(PKG "rpm")
+ set(DEBUG_PKG "rpm")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(NAME "debuginfo")
+ set(DEBUG_SUFFIX "dbgsym")
+ set(PKG "deb")
+ set(DEBUG_PKG "ddeb")
+endif()
+
+set(EXPECTED_FILE_1_NAME "${NAME}")
set(EXPECTED_FILE_1_COMPONENT "applications")
set(EXPECTED_FILE_CONTENT_1_LIST "/foo;/foo/test_prog")
-set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.rpm")
+
+set(EXPECTED_FILE_2 "TestDinfo-pkg*-headers.${PKG}")
set(EXPECTED_FILE_CONTENT_2_LIST "/bar;/bar/CMakeLists.txt")
-set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.rpm")
+
+set(EXPECTED_FILE_3 "TestDinfo-pkg*-libs.${PKG}")
set(EXPECTED_FILE_CONTENT_3_LIST "/bas;/bas/libtest_lib.so")
-set(EXPECTED_FILE_4_NAME "Debuginfo")
-set(EXPECTED_FILE_4_COMPONENT "applications-debuginfo")
-set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
-set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
-set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
+set(EXPECTED_FILE_4 "${NAME}-applications-${DEBUG_SUFFIX}*.${DEBUG_PKG}")
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(EXPECTED_FILE_CONTENT_4 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/main.cpp.*\.debug.*")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(EXPECTED_FILE_CONTENT_4 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+endif()
+
+if(GENERATOR_TYPE STREQUAL "RPM")
+ set(EXPECTED_FILE_5 "libs-DebugInfoPackage.rpm")
+ set(EXPECTED_FILE_CONTENT_5 ".*/src${whitespaces_}/src/src_1${whitespaces_}/src/src_1/test_lib.cpp.*\.debug.*")
+elseif(GENERATOR_TYPE STREQUAL "DEB")
+ set(EXPECTED_FILE_5 "TestDinfo-pkg-libs-dbgsym.ddeb")
+ set(EXPECTED_FILE_CONTENT_5 ".*/usr/lib/debug/.build-id/.*\.debug.*")
+endif()
diff --git a/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake b/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
index 71457d4..161a36a 100644
--- a/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
+++ b/Tests/RunCMake/CPack/tests/DEBUGINFO/test.cmake
@@ -29,12 +29,16 @@ install(TARGETS test_lib DESTINATION bas COMPONENT libs)
set(CPACK_RPM_APPLICATIONS_FILE_NAME "RPM-DEFAULT")
set(CPACK_RPM_APPLICATIONS_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_APPLICATIONS_FILE_NAME "DEB-DEFAULT")
+set(CPACK_DEBIAN_APPLICATIONS_DEBUGINFO_PACKAGE ON)
# test that components with debuginfo enabled still honor
# CPACK_PACKAGE_FILE_NAME setting
set(CPACK_RPM_PACKAGE_NAME "Debuginfo")
set(CPACK_PACKAGE_FILE_NAME "TestDinfo-pkg")
set(CPACK_RPM_LIBS_DEBUGINFO_PACKAGE ON)
+set(CPACK_DEBIAN_PACKAGE_NAME "Debuginfo")
+set(CPACK_DEBIAN_LIBS_DEBUGINFO_PACKAGE ON)
# test debuginfo package rename
set(CPACK_RPM_DEBUGINFO_FILE_NAME
diff --git a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
index 6c861fa..2441a9c 100644
--- a/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
+++ b/Tests/RunCMake/TargetPolicies/PolicyList-stderr.txt
@@ -25,6 +25,7 @@
\* CMP0069
\* CMP0073
\* CMP0076
+ \* CMP0081
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
diff --git a/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt b/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt
new file mode 100644
index 0000000..580c373
--- /dev/null
+++ b/Tests/RunCMake/set_property/LINK_DIRECTORIES-stdout.txt
@@ -0,0 +1,2 @@
+-- Target LINK_DIRECTORIES is 'a;b;c;d;;e'
+-- Directory LINK_DIRECTORIES is 'a;b;c;d;;e'
diff --git a/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake b/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake
new file mode 100644
index 0000000..8529ef5
--- /dev/null
+++ b/Tests/RunCMake/set_property/LINK_DIRECTORIES.cmake
@@ -0,0 +1,3 @@
+include(Common.cmake)
+test_target_property(LINK_DIRECTORIES)
+test_directory_property(LINK_DIRECTORIES)
diff --git a/Tests/RunCMake/set_property/RunCMakeTest.cmake b/Tests/RunCMake/set_property/RunCMakeTest.cmake
index 77da703..8d4614c 100644
--- a/Tests/RunCMake/set_property/RunCMakeTest.cmake
+++ b/Tests/RunCMake/set_property/RunCMakeTest.cmake
@@ -6,6 +6,7 @@ run_cmake(COMPILE_OPTIONS)
run_cmake(IMPORTED_GLOBAL)
run_cmake(INCLUDE_DIRECTORIES)
run_cmake(LINK_OPTIONS)
+run_cmake(LINK_DIRECTORIES)
run_cmake(LINK_LIBRARIES)
run_cmake(SOURCES)
run_cmake(TYPE)
diff --git a/Utilities/Release/linux64_release.cmake b/Utilities/Release/linux64_release.cmake
index f2ca2d5..dc34120 100644
--- a/Utilities/Release/linux64_release.cmake
+++ b/Utilities/Release/linux64_release.cmake
@@ -3,8 +3,8 @@ set(BOOTSTRAP_ARGS "--docdir=doc/cmake")
set(HOST linux64)
set(MAKE_PROGRAM "make")
set(CPACK_BINARY_GENERATORS "STGZ TGZ")
-set(CC /opt/gcc-6.1.0/bin/gcc)
-set(CXX /opt/gcc-6.1.0/bin/g++)
+set(CC /opt/gcc-8.2.0/bin/gcc)
+set(CXX /opt/gcc-8.2.0/bin/g++)
set(CFLAGS "")
set(CXXFLAGS "")
set(qt_prefix "/home/kitware/qt-5.7.0")
@@ -41,6 +41,9 @@ CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:STRING=3
CMAKE_PREFIX_PATH:STRING=${qt_prefix}
CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES:STRING=${qt_xcb_libs}
")
+set(ENV [[
+export CMAKE_PREFIX_PATH=/opt/binutils-2.31
+]])
# Exclude Qt5 tests because our Qt5 is static.
set(EXTRA_CTEST_ARGS "-E Qt5")