Merge topic 'FindBoost-msvc-toolset-14.2'

032e969879 Merge branch 'backport-FindBoost-msvc-toolset-14.2'
717e85418b FindBoost: Add support for MSVC toolset version 14.2
9010f5c18a FindBoost: Add support for MSVC toolset version 14.2

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !3221
diff --git a/Help/command/add_library.rst b/Help/command/add_library.rst
index ec6cb9d..b42fe42 100644
--- a/Help/command/add_library.rst
+++ b/Help/command/add_library.rst
@@ -80,12 +80,17 @@
 within the project.  ``IMPORTED`` libraries are useful for convenient
 reference from commands like :command:`target_link_libraries`.  Details
 about the imported library are specified by setting properties whose names
-begin in ``IMPORTED_`` and ``INTERFACE_``.  The most important such
-property is :prop_tgt:`IMPORTED_LOCATION` (and its per-configuration
-variant :prop_tgt:`IMPORTED_LOCATION_<CONFIG>`) which specifies the
-location of the main library file on disk.  Or, for object libraries,
-:prop_tgt:`IMPORTED_OBJECTS` (and :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>`)
-specifies the locations of object files on disk.
+begin in ``IMPORTED_`` and ``INTERFACE_``.
+
+The most important properties are:
+
+* :prop_tgt:`IMPORTED_LOCATION` (and its per-configuration
+  variant :prop_tgt:`IMPORTED_LOCATION_<CONFIG>`) which specifies the
+  location of the main library file on disk.
+* :prop_tgt:`IMPORTED_OBJECTS` (and :prop_tgt:`IMPORTED_OBJECTS_<CONFIG>`)
+  for object libraries, specifies the locations of object files on disk.
+* :prop_tgt:`PUBLIC_HEADER` files to be installed during :command:`install` invocation
+
 See documentation of the ``IMPORTED_*`` and ``INTERFACE_*`` properties
 for more information.
 
diff --git a/Help/command/install.rst b/Help/command/install.rst
index a4cee71..7571aae 100644
--- a/Help/command/install.rst
+++ b/Help/command/install.rst
@@ -148,13 +148,13 @@
   property are treated as ``FRAMEWORK`` targets on macOS.
 
 ``BUNDLE``
-  Executables marked with the ``MACOSX_BUNDLE`` property are treated as
+  Executables marked with the :prop_tgt:`MACOSX_BUNDLE` property are treated as
   ``BUNDLE`` targets on macOS.
 
 ``PUBLIC_HEADER``
-  Any ``PUBLIC_HEADER`` files associated with a library are installed in
+  Any :prop_tgt:`PUBLIC_HEADER` files associated with a library are installed in
   the destination specified by the ``PUBLIC_HEADER`` argument on non-Apple
-  platforms. Rules defined by this argument are ignored for ``FRAMEWORK``
+  platforms. Rules defined by this argument are ignored for :prop_tgt:`FRAMEWORK`
   libraries on Apple platforms because the associated files are installed
   into the appropriate locations inside the framework folder. See
   :prop_tgt:`PUBLIC_HEADER` for details.
diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst
index e3a96bd..e9b3f4c 100644
--- a/Help/manual/cmake-generator-expressions.7.rst
+++ b/Help/manual/cmake-generator-expressions.7.rst
@@ -393,7 +393,18 @@
   Note that ``tgt`` is not added as a dependency of the target this
   expression is evaluated on.
 ``$<TARGET_FILE:tgt>``
-  Full path to main file (.exe, .so.1.2, .a) where ``tgt`` is the name of a target.
+  Full path to main file (.exe, .so.1.2, .a) where ``tgt`` is the name of a
+  target.
+``$<TARGET_FILE_PREFIX:tgt>``
+  Prefix of main file where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
+``$<TARGET_FILE_SUFFIX:tgt>``
+  Suffix of main file where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
 ``$<TARGET_FILE_NAME:tgt>``
   Name of main file (.exe, .so.1.2, .a).
 ``$<TARGET_FILE_DIR:tgt>``
@@ -405,6 +416,16 @@
   expression is evaluated on.
 ``$<TARGET_LINKER_FILE:tgt>``
   File used to link (.a, .lib, .so) where ``tgt`` is the name of a target.
+``$<TARGET_LINKER_FILE_PREFIX:tgt>``
+  Prefix of file used to link where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
+``$<TARGET_LINKER_FILE_SUFFIX:tgt>``
+  Suffix of file used to link where ``tgt`` is the name of a target.
+
+  Note that ``tgt`` is not added as a dependency of the target this
+  expression is evaluated on.
 ``$<TARGET_LINKER_FILE_NAME:tgt>``
   Name of file used to link (.a, .lib, .so).
 ``$<TARGET_LINKER_FILE_DIR:tgt>``
diff --git a/Help/release/dev/genex-TARGET_FILE_PREFIX.rst b/Help/release/dev/genex-TARGET_FILE_PREFIX.rst
new file mode 100644
index 0000000..3e480bb
--- /dev/null
+++ b/Help/release/dev/genex-TARGET_FILE_PREFIX.rst
@@ -0,0 +1,7 @@
+genex-TARGET_FILE_PREFIX
+------------------------
+
+* New ``$<TARGET_FILE_PREFIX:...>``, ``$<TARGET_LINKER_FILE_PREFIX:...>``,
+  ``$<TARGET_FILE_SUFFIX:...>`` and ``$<TARGET_LINKER_FILE_SUFFIX:...>``
+  :manual:`generator expressions <cmake-generator-expressions(7)>` have been
+  added to retrieve the prefix and suffix of various artifacts.
diff --git a/Help/release/dev/iface-headers.rst b/Help/release/dev/iface-headers.rst
new file mode 100644
index 0000000..2e1de5e
--- /dev/null
+++ b/Help/release/dev/iface-headers.rst
@@ -0,0 +1,7 @@
+iface-headers
+-------------
+
+* ``INTERFACE`` library can now have :prop_tgt:`PUBLIC_HEADER` and
+  :prop_tgt:`PRIVATE_HEADER` properties set. The headers specified by those
+  properties can be installed using the :command:`install(TARGETS)` command by
+  passing the ``PUBLIC_HEADER`` and ``PRIVATE_HEADER`` arguments respectively.
diff --git a/Modules/Compiler/AppleClang-CXX.cmake b/Modules/Compiler/AppleClang-CXX.cmake
index e5fd647..d34d494 100644
--- a/Modules/Compiler/AppleClang-CXX.cmake
+++ b/Modules/Compiler/AppleClang-CXX.cmake
@@ -8,6 +8,7 @@
 if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0)
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
 
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
diff --git a/Modules/Compiler/Clang-CXX.cmake b/Modules/Compiler/Clang-CXX.cmake
index e99011b..34ffd66 100644
--- a/Modules/Compiler/Clang-CXX.cmake
+++ b/Modules/Compiler/Clang-CXX.cmake
@@ -19,6 +19,7 @@
   if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.1)
     set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
     set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+    set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 2.1)
     set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
     set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x")
@@ -59,6 +60,7 @@
   # support for -std: flags.
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
   set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14")
diff --git a/Modules/Compiler/GNU-CXX.cmake b/Modules/Compiler/GNU-CXX.cmake
index 0058223..7202607 100644
--- a/Modules/Compiler/GNU-CXX.cmake
+++ b/Modules/Compiler/GNU-CXX.cmake
@@ -19,6 +19,7 @@
 if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
 elseif (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4)
   # 4.3 supports 0x variants
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++0x")
diff --git a/Modules/Compiler/Intel-CXX.cmake b/Modules/Compiler/Intel-CXX.cmake
index c115b6a..471dd4a 100644
--- a/Modules/Compiler/Intel-CXX.cmake
+++ b/Modules/Compiler/Intel-CXX.cmake
@@ -30,6 +30,7 @@
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
     set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
     set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+    set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
 
 else()
@@ -64,6 +65,7 @@
   if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1)
     set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++98")
     set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98")
+    set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   endif()
 
 endif()
diff --git a/Modules/Compiler/MSVC-CXX.cmake b/Modules/Compiler/MSVC-CXX.cmake
index be259ff..691926f 100644
--- a/Modules/Compiler/MSVC-CXX.cmake
+++ b/Modules/Compiler/MSVC-CXX.cmake
@@ -11,6 +11,7 @@
   # with the default and minimum level being C++14.
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "")
   set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std:c++14")
diff --git a/Modules/Compiler/SunPro-CXX.cmake b/Modules/Compiler/SunPro-CXX.cmake
index 5ce58b2..c2f6d1d 100644
--- a/Modules/Compiler/SunPro-CXX.cmake
+++ b/Modules/Compiler/SunPro-CXX.cmake
@@ -48,6 +48,7 @@
 if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.13)
   set(CMAKE_CXX98_STANDARD_COMPILE_OPTION "-std=c++03")
   set(CMAKE_CXX98_EXTENSION_COMPILE_OPTION "-std=c++03")
+  set(CMAKE_CXX98_STANDARD__HAS_FULL_SUPPORT ON)
   set(CMAKE_CXX11_STANDARD_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CXX11_EXTENSION_COMPILE_OPTION "-std=c++11")
   set(CMAKE_CXX_LINK_WITH_STANDARD_COMPILE_OPTION 1)
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake
index 70c44e1..4e7e400 100644
--- a/Source/CMakeVersion.cmake
+++ b/Source/CMakeVersion.cmake
@@ -1,5 +1,5 @@
 # CMake version number components.
 set(CMake_VERSION_MAJOR 3)
 set(CMake_VERSION_MINOR 14)
-set(CMake_VERSION_PATCH 20190412)
+set(CMake_VERSION_PATCH 20190415)
 #set(CMake_VERSION_RC 1)
diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx
index d8e1c42..af409e4 100644
--- a/Source/cmGeneratorExpressionNode.cxx
+++ b/Source/cmGeneratorExpressionNode.cxx
@@ -2297,6 +2297,119 @@
 
 static const TargetOutputNameArtifact<ArtifactPdbTag> targetPdbOutputNameNode;
 
+class ArtifactFilePrefixTag;
+class ArtifactLinkerFilePrefixTag;
+class ArtifactFileSuffixTag;
+class ArtifactLinkerFileSuffixTag;
+
+template <typename ArtifactT>
+struct TargetFileArtifactResultGetter
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content);
+};
+
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFilePrefixTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent*)
+  {
+    return target->GetFilePrefix(context->Config);
+  }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFilePrefixTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content)
+  {
+    if (!target->IsLinkable()) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "TARGET_LINKER_PREFIX is allowed only for libraries and "
+                    "executables with ENABLE_EXPORTS.");
+      return std::string();
+    }
+
+    cmStateEnums::ArtifactType artifact =
+      target->HasImportLibrary(context->Config)
+      ? cmStateEnums::ImportLibraryArtifact
+      : cmStateEnums::RuntimeBinaryArtifact;
+
+    return target->GetFilePrefix(context->Config, artifact);
+  }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactFileSuffixTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent*)
+  {
+    return target->GetFileSuffix(context->Config);
+  }
+};
+template <>
+struct TargetFileArtifactResultGetter<ArtifactLinkerFileSuffixTag>
+{
+  static std::string Get(cmGeneratorTarget* target,
+                         cmGeneratorExpressionContext* context,
+                         const GeneratorExpressionContent* content)
+  {
+    if (!target->IsLinkable()) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "TARGET_LINKER_SUFFIX is allowed only for libraries and "
+                    "executables with ENABLE_EXPORTS.");
+      return std::string();
+    }
+
+    cmStateEnums::ArtifactType artifact =
+      target->HasImportLibrary(context->Config)
+      ? cmStateEnums::ImportLibraryArtifact
+      : cmStateEnums::RuntimeBinaryArtifact;
+
+    return target->GetFileSuffix(context->Config, artifact);
+  }
+};
+
+template <typename ArtifactT>
+struct TargetFileArtifact : public TargetArtifactBase
+{
+  TargetFileArtifact() {} // NOLINT(modernize-use-equals-default)
+
+  int NumExpectedParameters() const override { return 1; }
+
+  std::string Evaluate(
+    const std::vector<std::string>& parameters,
+    cmGeneratorExpressionContext* context,
+    const GeneratorExpressionContent* content,
+    cmGeneratorExpressionDAGChecker* dagChecker) const override
+  {
+    cmGeneratorTarget* target =
+      this->GetTarget(parameters, context, content, dagChecker);
+    if (!target) {
+      return std::string();
+    }
+
+    std::string result =
+      TargetFileArtifactResultGetter<ArtifactT>::Get(target, context, content);
+    if (context->HadError) {
+      return std::string();
+    }
+    return result;
+  }
+};
+
+static const TargetFileArtifact<ArtifactFilePrefixTag> targetFilePrefixNode;
+static const TargetFileArtifact<ArtifactLinkerFilePrefixTag>
+  targetLinkerFilePrefixNode;
+static const TargetFileArtifact<ArtifactFileSuffixTag> targetFileSuffixNode;
+static const TargetFileArtifact<ArtifactLinkerFileSuffixTag>
+  targetLinkerFileSuffixNode;
+
 static const struct ShellPathNode : public cmGeneratorExpressionNode
 {
   ShellPathNode() {} // NOLINT(modernize-use-equals-default)
@@ -2361,6 +2474,10 @@
     { "TARGET_LINKER_FILE", &targetLinkerNodeGroup.File },
     { "TARGET_SONAME_FILE", &targetSoNameNodeGroup.File },
     { "TARGET_PDB_FILE", &targetPdbNodeGroup.File },
+    { "TARGET_FILE_PREFIX", &targetFilePrefixNode },
+    { "TARGET_LINKER_FILE_PREFIX", &targetLinkerFilePrefixNode },
+    { "TARGET_FILE_SUFFIX", &targetFileSuffixNode },
+    { "TARGET_LINKER_FILE_SUFFIX", &targetLinkerFileSuffixNode },
     { "TARGET_FILE_NAME", &targetNodeGroup.FileName },
     { "TARGET_LINKER_FILE_NAME", &targetLinkerNodeGroup.FileName },
     { "TARGET_SONAME_FILE_NAME", &targetSoNameNodeGroup.FileName },
diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx
index f8c16cc..3fb95bf 100644
--- a/Source/cmGeneratorTarget.cxx
+++ b/Source/cmGeneratorTarget.cxx
@@ -464,6 +464,134 @@
   return i->second;
 }
 
+std::string cmGeneratorTarget::GetFilePrefix(
+  const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+  if (this->IsImported()) {
+    const char* prefix = this->GetFilePrefixInternal(artifact);
+
+    return prefix ? prefix : std::string();
+  }
+
+  std::string prefix, suffix, base;
+  this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+  return prefix;
+}
+std::string cmGeneratorTarget::GetFileSuffix(
+  const std::string& config, cmStateEnums::ArtifactType artifact) const
+{
+  if (this->IsImported()) {
+    const char* suffix = this->GetFileSuffixInternal(artifact);
+
+    return suffix ? suffix : std::string();
+  }
+
+  std::string prefix, suffix, base;
+  this->GetFullNameInternal(config, artifact, prefix, base, suffix);
+  return suffix;
+}
+
+const char* cmGeneratorTarget::GetFilePrefixInternal(
+  cmStateEnums::ArtifactType artifact, const std::string& language) const
+{
+  // no prefix for non-main target types.
+  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
+    return nullptr;
+  }
+
+  const bool isImportedLibraryArtifact =
+    (artifact == cmStateEnums::ImportLibraryArtifact);
+
+  // Return an empty prefix for the import library if this platform
+  // does not support import libraries.
+  if (isImportedLibraryArtifact &&
+      !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+    return nullptr;
+  }
+
+  // The implib option is only allowed for shared libraries, module
+  // libraries, and executables.
+  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
+    artifact = cmStateEnums::RuntimeBinaryArtifact;
+  }
+
+  // Compute prefix value.
+  const char* targetPrefix =
+    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
+                               : this->GetProperty("PREFIX"));
+
+  if (!targetPrefix) {
+    const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
+    if (!language.empty() && prefixVar && *prefixVar) {
+      std::string langPrefix = prefixVar + std::string("_") + language;
+      targetPrefix = this->Makefile->GetDefinition(langPrefix);
+    }
+
+    // if there is no prefix on the target nor specific language
+    // use the cmake definition.
+    if (!targetPrefix && prefixVar) {
+      targetPrefix = this->Makefile->GetDefinition(prefixVar);
+    }
+  }
+
+  return targetPrefix;
+}
+const char* cmGeneratorTarget::GetFileSuffixInternal(
+  cmStateEnums::ArtifactType artifact, const std::string& language) const
+{
+  // no suffix for non-main target types.
+  if (this->GetType() != cmStateEnums::STATIC_LIBRARY &&
+      this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
+    return nullptr;
+  }
+
+  const bool isImportedLibraryArtifact =
+    (artifact == cmStateEnums::ImportLibraryArtifact);
+
+  // Return an empty suffix for the import library if this platform
+  // does not support import libraries.
+  if (isImportedLibraryArtifact &&
+      !this->Makefile->GetDefinition("CMAKE_IMPORT_LIBRARY_SUFFIX")) {
+    return nullptr;
+  }
+
+  // The implib option is only allowed for shared libraries, module
+  // libraries, and executables.
+  if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
+      this->GetType() != cmStateEnums::MODULE_LIBRARY &&
+      this->GetType() != cmStateEnums::EXECUTABLE) {
+    artifact = cmStateEnums::RuntimeBinaryArtifact;
+  }
+
+  // Compute suffix value.
+  const char* targetSuffix =
+    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
+                               : this->GetProperty("SUFFIX"));
+
+  if (!targetSuffix) {
+    const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
+    if (!language.empty() && suffixVar && *suffixVar) {
+      std::string langSuffix = suffixVar + std::string("_") + language;
+      targetSuffix = this->Makefile->GetDefinition(langSuffix);
+    }
+
+    // if there is no suffix on the target nor specific language
+    // use the cmake definition.
+    if (!targetSuffix && suffixVar) {
+      targetSuffix = this->Makefile->GetDefinition(suffixVar);
+    }
+  }
+
+  return targetSuffix;
+}
+
 void cmGeneratorTarget::ClearSourcesCache()
 {
   this->KindedSourcesMap.clear();
@@ -3788,6 +3916,11 @@
     return;
   }
 
+  // retrieve prefix and suffix
+  std::string ll = this->GetLinkerLanguage(config);
+  const char* targetPrefix = this->GetFilePrefixInternal(artifact, ll);
+  const char* targetSuffix = this->GetFileSuffixInternal(artifact, ll);
+
   // The implib option is only allowed for shared libraries, module
   // libraries, and executables.
   if (this->GetType() != cmStateEnums::SHARED_LIBRARY &&
@@ -3797,12 +3930,6 @@
   }
 
   // Compute the full name for main target types.
-  const char* targetPrefix =
-    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_PREFIX")
-                               : this->GetProperty("PREFIX"));
-  const char* targetSuffix =
-    (isImportedLibraryArtifact ? this->GetProperty("IMPORT_SUFFIX")
-                               : this->GetProperty("SUFFIX"));
   const char* configPostfix = nullptr;
   if (!config.empty()) {
     std::string configProp = cmSystemTools::UpperCase(config);
@@ -3814,30 +3941,6 @@
       configPostfix = nullptr;
     }
   }
-  const char* prefixVar = this->Target->GetPrefixVariableInternal(artifact);
-  const char* suffixVar = this->Target->GetSuffixVariableInternal(artifact);
-
-  // Check for language-specific default prefix and suffix.
-  std::string ll = this->GetLinkerLanguage(config);
-  if (!ll.empty()) {
-    if (!targetSuffix && suffixVar && *suffixVar) {
-      std::string langSuff = suffixVar + std::string("_") + ll;
-      targetSuffix = this->Makefile->GetDefinition(langSuff);
-    }
-    if (!targetPrefix && prefixVar && *prefixVar) {
-      std::string langPrefix = prefixVar + std::string("_") + ll;
-      targetPrefix = this->Makefile->GetDefinition(langPrefix);
-    }
-  }
-
-  // if there is no prefix on the target use the cmake definition
-  if (!targetPrefix && prefixVar) {
-    targetPrefix = this->Makefile->GetSafeDefinition(prefixVar).c_str();
-  }
-  // if there is no suffix on the target use the cmake definition
-  if (!targetSuffix && suffixVar) {
-    targetSuffix = this->Makefile->GetSafeDefinition(suffixVar).c_str();
-  }
 
   // frameworks have directory prefix but no suffix
   std::string fw_prefix;
diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h
index 065b457..81f5255 100644
--- a/Source/cmGeneratorTarget.h
+++ b/Source/cmGeneratorTarget.h
@@ -534,6 +534,15 @@
   std::string GetOutputName(const std::string& config,
                             cmStateEnums::ArtifactType artifact) const;
 
+  /** Get target file prefix */
+  std::string GetFilePrefix(const std::string& config,
+                            cmStateEnums::ArtifactType artifact =
+                              cmStateEnums::RuntimeBinaryArtifact) const;
+  /** Get target file prefix */
+  std::string GetFileSuffix(const std::string& config,
+                            cmStateEnums::ArtifactType artifact =
+                              cmStateEnums::RuntimeBinaryArtifact) const;
+
   /** Clears cached meta data for local and external source files.
    * The meta data will be recomputed on demand.
    */
@@ -728,6 +737,11 @@
 
   mutable std::map<std::string, bool> DebugCompatiblePropertiesDone;
 
+  const char* GetFilePrefixInternal(cmStateEnums::ArtifactType artifact,
+                                    const std::string& language = "") const;
+  const char* GetFileSuffixInternal(cmStateEnums::ArtifactType artifact,
+                                    const std::string& language = "") const;
+
   std::string GetFullNameInternal(const std::string& config,
                                   cmStateEnums::ArtifactType artifact) const;
   void GetFullNameInternal(const std::string& config,
diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx
index 9736b41..dba4bbb 100644
--- a/Source/cmInstallCommand.cxx
+++ b/Source/cmInstallCommand.cxx
@@ -666,8 +666,7 @@
     // generators for them.
     bool createInstallGeneratorsForTargetFileSets = true;
 
-    if (target.IsFrameworkOnApple() ||
-        target.GetType() == cmStateEnums::INTERFACE_LIBRARY) {
+    if (target.IsFrameworkOnApple()) {
       createInstallGeneratorsForTargetFileSets = false;
     }
 
diff --git a/Source/cmTargetPropertyComputer.cxx b/Source/cmTargetPropertyComputer.cxx
index d2c3496..994fcf7 100644
--- a/Source/cmTargetPropertyComputer.cxx
+++ b/Source/cmTargetPropertyComputer.cxx
@@ -67,6 +67,8 @@
     builtIns.insert("IMPORTED_GLOBAL");
     builtIns.insert("MANUALLY_ADDED_DEPENDENCIES");
     builtIns.insert("NAME");
+    builtIns.insert("PRIVATE_HEADER");
+    builtIns.insert("PUBLIC_HEADER");
     builtIns.insert("TYPE");
   }
 
diff --git a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
index 4202064..0b0fb78 100644
--- a/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
+++ b/Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
@@ -33,6 +33,14 @@
 run_cmake(COMPILE_LANGUAGE-unknown-lang)
 run_cmake(TARGET_FILE-recursion)
 run_cmake(OUTPUT_NAME-recursion)
+run_cmake(TARGET_FILE_PREFIX)
+run_cmake(TARGET_FILE_PREFIX-imported-target)
+run_cmake(TARGET_FILE_PREFIX-non-valid-target)
+run_cmake(TARGET_LINKER_FILE_PREFIX-non-valid-target)
+run_cmake(TARGET_FILE_SUFFIX)
+run_cmake(TARGET_FILE_SUFFIX-imported-target)
+run_cmake(TARGET_FILE_SUFFIX-non-valid-target)
+run_cmake(TARGET_LINKER_FILE_SUFFIX-non-valid-target)
 run_cmake(TARGET_OUTPUT_NAME)
 run_cmake(TARGET_OUTPUT_NAME-imported-target)
 run_cmake(TARGET_OUTPUT_NAME-non-valid-target)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake
new file mode 100644
index 0000000..676ad4b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake
new file mode 100644
index 0000000..676ad4b
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake
new file mode 100644
index 0000000..34e500a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-imported-target.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable(exec1 IMPORTED)
+add_library (shared1 SHARED IMPORTED)
+add_library (static1 STATIC IMPORTED)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable default\" \"$<TARGET_FILE_PREFIX:exec1>\" \"\")
+check_value (\"TARGET_FILE_PREFIX shared default\" \"$<TARGET_FILE_PREFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker default\" \"$<TARGET_LINKER_FILE_PREFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_PREFIX},${CMAKE_SHARED_LIBRARY_PREFIX}>\")
+check_value (\"TARGET_FILE_PREFIX static default\" \"$<TARGET_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker default\" \"$<TARGET_LINKER_FILE_PREFIX:static1>\"  \"${CMAKE_STATIC_LIBRARY_PREFIX}\")\n")
+
+
+add_executable (exec2 IMPORTED)
+set_property (TARGET exec2 PROPERTY PREFIX exec2_prefix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_PREFIX exec2_import_prefix)
+add_library (shared2 SHARED IMPORTED)
+set_property (TARGET shared2 PROPERTY PREFIX shared2_prefix)
+set_property (TARGET shared2 PROPERTY IMPORT_PREFIX shared2_import_prefix)
+add_library (static2 STATIC IMPORTED)
+set_property (TARGET static2 PROPERTY PREFIX static2_prefix)
+set_property (TARGET static2 PROPERTY IMPORT_PREFIX static2_import_prefix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable custom\" \"$<TARGET_FILE_PREFIX:exec2>\" \"exec2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX executable linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_prefix,exec2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX shared custom\" \"$<TARGET_FILE_PREFIX:shared2>\" \"shared2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_prefix,shared2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX static custom\" \"$<TARGET_FILE_PREFIX:static2>\" \"static2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:static2>\" \"static2_prefix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt
new file mode 100644
index 0000000..81362ef
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_FILE_PREFIX-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_FILE_PREFIX:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake
new file mode 100644
index 0000000..d1095fa
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_FILE_PREFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake
new file mode 100644
index 0000000..6bb1e44
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_PREFIX.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable (exec1 empty.c)
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable default\" \"$<TARGET_FILE_PREFIX:exec1>\" \"\")
+check_value (\"TARGET_FILE_PREFIX shared default\" \"$<TARGET_FILE_PREFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker default\" \"$<TARGET_LINKER_FILE_PREFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_PREFIX},${CMAKE_SHARED_LIBRARY_PREFIX}>\")
+check_value (\"TARGET_FILE_PREFIX static default\" \"$<TARGET_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker default\" \"$<TARGET_LINKER_FILE_PREFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_PREFIX}\")\n")
+
+
+add_executable (exec2 empty.c)
+set_property (TARGET exec2 PROPERTY PREFIX exec2_prefix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_PREFIX exec2_import_prefix)
+add_library (shared2 SHARED empty.c)
+set_property (TARGET shared2 PROPERTY PREFIX shared2_prefix)
+set_property (TARGET shared2 PROPERTY IMPORT_PREFIX shared2_import_prefix)
+add_library (static2 STATIC empty.c)
+set_property (TARGET static2 PROPERTY PREFIX static2_prefix)
+set_property (TARGET static2 PROPERTY IMPORT_PREFIX static2_import_prefix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_PREFIX executable custom\" \"$<TARGET_FILE_PREFIX:exec2>\" \"exec2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX executable linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_prefix,exec2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX shared custom\" \"$<TARGET_FILE_PREFIX:shared2>\" \"shared2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX shared linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_prefix,shared2_prefix>\")
+check_value (\"TARGET_FILE_PREFIX static custom\" \"$<TARGET_FILE_PREFIX:static2>\" \"static2_prefix\")
+check_value (\"TARGET_LINKER_FILE_PREFIX static linker custom\" \"$<TARGET_LINKER_FILE_PREFIX:static2>\" \"static2_prefix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_PREFIX-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake
new file mode 100644
index 0000000..f159370
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake
new file mode 100644
index 0000000..f159370
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target-check.cmake
@@ -0,0 +1,2 @@
+
+include ("${RunCMake_TEST_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake
new file mode 100644
index 0000000..e1b7654
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-imported-target.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable (exec1 IMPORTED)
+add_library (shared1 SHARED IMPORTED)
+add_library (static1 STATIC IMPORTED)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable default\" \"$<TARGET_FILE_SUFFIX:exec1>\" \"${CMAKE_EXECUTABLE_SUFFIX}\")
+check_value (\"TARGET_FILE_SUFFIX shared default\" \"$<TARGET_FILE_SUFFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_SUFFIX},${CMAKE_SHARED_LIBRARY_SUFFIX}>\")
+check_value (\"TARGET_FILE_SUFFIX static default\" \"$<TARGET_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n")
+
+
+add_executable (exec2 IMPORTED)
+set_property (TARGET exec2 PROPERTY SUFFIX exec2_suffix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_SUFFIX exec2_import_suffix)
+add_library (shared2 SHARED IMPORTED)
+set_property (TARGET shared2 PROPERTY SUFFIX shared2_suffix)
+set_property (TARGET shared2 PROPERTY IMPORT_SUFFIX shared2_import_suffix)
+add_library (static2 STATIC IMPORTED)
+set_property (TARGET static2 PROPERTY SUFFIX static2_suffix)
+set_property (TARGET static2 PROPERTY IMPORT_SUFFIX static2_import_suffix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable custom\" \"$<TARGET_FILE_SUFFIX:exec2>\" \"exec2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX executable linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_suffix,exec2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX shared custom\" \"$<TARGET_FILE_SUFFIX:shared2>\" \"shared2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_suffix,shared2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX static custom\" \"$<TARGET_FILE_SUFFIX:static2>\" \"static2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:static2>\" \"static2_suffix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt
new file mode 100644
index 0000000..9ea09d1
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_FILE_SUFFIX-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_FILE_SUFFIX:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake
new file mode 100644
index 0000000..f7089f9
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_FILE_SUFFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake
new file mode 100644
index 0000000..78afecd
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_FILE_SUFFIX.cmake
@@ -0,0 +1,49 @@
+
+cmake_minimum_required(VERSION 3.14)
+
+enable_language (C)
+
+set (win_platforms Windows CYGWIN)
+
+set (GENERATE_CONTENT [[
+macro (CHECK_VALUE test_msg value expected)
+  if (NOT "${value}" STREQUAL "${expected}")
+    string (APPEND RunCMake_TEST_FAILED "${test_msg}: actual result:\n [${value}]\nbut expected:\n [${expected}]\n")
+  endif()
+endmacro()
+]])
+
+add_executable (exec1 empty.c)
+add_library (shared1 SHARED empty.c)
+add_library (static1 STATIC empty.c)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable default\" \"$<TARGET_FILE_SUFFIX:exec1>\" \"${CMAKE_EXECUTABLE_SUFFIX}\")
+check_value (\"TARGET_FILE_SUFFIX shared default\" \"$<TARGET_FILE_SUFFIX:shared1>\" \"${CMAKE_SHARED_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:shared1>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,${CMAKE_IMPORT_LIBRARY_SUFFIX},${CMAKE_SHARED_LIBRARY_SUFFIX}>\")
+check_value (\"TARGET_FILE_SUFFIX static default\" \"$<TARGET_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker default\" \"$<TARGET_LINKER_FILE_SUFFIX:static1>\" \"${CMAKE_STATIC_LIBRARY_SUFFIX}\")\n")
+
+
+add_executable (exec2 empty.c)
+set_property (TARGET exec2 PROPERTY SUFFIX exec2_suffix)
+set_property (TARGET exec2 PROPERTY ENABLE_EXPORTS TRUE)
+set_property (TARGET exec2 PROPERTY IMPORT_SUFFIX exec2_import_suffix)
+add_library (shared2 SHARED empty.c)
+set_property (TARGET shared2 PROPERTY SUFFIX shared2_suffix)
+set_property (TARGET shared2 PROPERTY IMPORT_SUFFIX shared2_import_suffix)
+add_library (static2 STATIC empty.c)
+set_property (TARGET static2 PROPERTY SUFFIX static2_suffix)
+set_property (TARGET static2 PROPERTY IMPORT_SUFFIX static2_import_suffix)
+
+string (APPEND GENERATE_CONTENT
+"\ncheck_value (\"TARGET_FILE_SUFFIX executable custom\" \"$<TARGET_FILE_SUFFIX:exec2>\" \"exec2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX executable linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:exec2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,exec2_import_suffix,exec2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX shared custom\" \"$<TARGET_FILE_SUFFIX:shared2>\" \"shared2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX shared linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:shared2>\" \"$<IF:$<IN_LIST:$<PLATFORM_ID>,${win_platforms}>,shared2_import_suffix,shared2_suffix>\")
+check_value (\"TARGET_FILE_SUFFIX static custom\" \"$<TARGET_FILE_SUFFIX:static2>\" \"static2_suffix\")
+check_value (\"TARGET_LINKER_FILE_SUFFIX static linker custom\" \"$<TARGET_LINKER_FILE_SUFFIX:static2>\" \"static2_suffix\")\n")
+
+
+file (GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/TARGET_FILE_SUFFIX-generated.cmake"
+  CONTENT "${GENERATE_CONTENT}")
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt
new file mode 100644
index 0000000..7a36cef
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_LINKER_FILE_PREFIX:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake
new file mode 100644
index 0000000..8dad4da
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_PREFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_LINKER_FILE_PREFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-result.txt
@@ -0,0 +1 @@
+1
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt
new file mode 100644
index 0000000..cc5217a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target-stderr.txt
@@ -0,0 +1,6 @@
+CMake Error at TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake:[0-9]+ \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_LINKER_FILE_SUFFIX:empty>
+
+  Target "empty" is not an executable or library\.
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake
new file mode 100644
index 0000000..82c2f3a
--- /dev/null
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_FILE_SUFFIX-non-valid-target.cmake
@@ -0,0 +1,7 @@
+
+add_custom_target(empty)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_LINKER_FILE_SUFFIX:empty>]"
+)
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-stderr.txt
index 29f6211..0e09469 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake:6 \(file\):
+CMake Error at TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake:[0-9]+ \(file\):
   Error evaluating generator expression:
 
     \$<TARGET_LINKER_OUTPUT_NAME:empty>
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake
index e1496b4..c439535 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_LINKER_OUTPUT_NAME-non-valid-target.cmake
@@ -1,6 +1,4 @@
 
-enable_language(C)
-
 add_custom_target(empty)
 
 file(GENERATE
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-stderr.txt b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-stderr.txt
index e78ec01..9672a99 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-stderr.txt
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target-stderr.txt
@@ -1,4 +1,4 @@
-CMake Error at TARGET_OUTPUT_NAME-non-valid-target.cmake:6 \(file\):
+CMake Error at TARGET_OUTPUT_NAME-non-valid-target.cmake:[0-9]+ \(file\):
   Error evaluating generator expression:
 
     \$<TARGET_OUTPUT_NAME:empty>
diff --git a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target.cmake b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target.cmake
index 2ff733c..5248dfa 100644
--- a/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target.cmake
+++ b/Tests/RunCMake/GeneratorExpression/TARGET_OUTPUT_NAME-non-valid-target.cmake
@@ -1,6 +1,4 @@
 
-enable_language(C)
-
 add_custom_target(empty)
 
 file(GENERATE
diff --git a/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake b/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
index c41cb2a..15335b2 100644
--- a/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
+++ b/Tests/RunCMake/install/TARGETS-Defaults-all-check.cmake
@@ -4,6 +4,8 @@
     [[bin/exe\.exe]]
     [[bin/(lib)?lib1\.dll]]
     [[include]]
+    [[include/obj1\.h]]
+    [[include/obj2\.h]]
     [[include/obj4\.h]]
     [[include/obj5\.h]]
     [[lib]]
@@ -20,6 +22,8 @@
     [[bin/cyglib1\.dll]]
     [[bin/exe\.exe]]
     [[include]]
+    [[include/obj1\.h]]
+    [[include/obj2\.h]]
     [[include/obj4\.h]]
     [[include/obj5\.h]]
     [[lib]]
@@ -35,6 +39,8 @@
     [[bin]]
     [[bin/exe]]
     [[include]]
+    [[include/obj1\.h]]
+    [[include/obj2\.h]]
     [[include/obj4\.h]]
     [[include/obj5\.h]]
     [[lib]]
diff --git a/Tests/RunCMake/install/TARGETS-Defaults.cmake b/Tests/RunCMake/install/TARGETS-Defaults.cmake
index bfd8c2c..324aa11 100644
--- a/Tests/RunCMake/install/TARGETS-Defaults.cmake
+++ b/Tests/RunCMake/install/TARGETS-Defaults.cmake
@@ -8,6 +8,11 @@
 add_library(lib4 SHARED obj5.c)
 set_property(TARGET lib4 PROPERTY PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj5.h)
 
+add_library(iface INTERFACE)
+set_target_properties(iface PROPERTIES
+  PUBLIC_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj1.h
+  PRIVATE_HEADER ${CMAKE_CURRENT_SOURCE_DIR}/obj2.h)
+
 install(TARGETS exe lib1 lib2)
 install(TARGETS lib3
   LIBRARY DESTINATION lib3
@@ -17,3 +22,6 @@
   LIBRARY DESTINATION lib4
   RUNTIME DESTINATION lib4
   )
+install(TARGETS iface
+  PUBLIC_HEADER DESTINATION include
+  PRIVATE_HEADER DESTINATION include)
diff --git a/Tests/RunCMake/install/obj2.h b/Tests/RunCMake/install/obj2.h
new file mode 100644
index 0000000..90bcd34
--- /dev/null
+++ b/Tests/RunCMake/install/obj2.h
@@ -0,0 +1,6 @@
+#ifndef OBJ2_H
+#define OBJ2_H
+
+int obj2(void);
+
+#endif /* OBJ2_H */
diff --git a/Tests/RunCMake/interface_library/whitelist.cmake b/Tests/RunCMake/interface_library/whitelist.cmake
index bf64f01..0db6375 100644
--- a/Tests/RunCMake/interface_library/whitelist.cmake
+++ b/Tests/RunCMake/interface_library/whitelist.cmake
@@ -14,3 +14,12 @@
 set_property(TARGET iface PROPERTY "custom_property" output)
 set_property(TARGET iface APPEND PROPERTY "custom_property" append)
 get_target_property(outname iface "custom_property")
+
+# PUBLIC_HEADER / PRIVATE_HEADER properties are allowed
+set_property(TARGET iface PROPERTY PUBLIC_HEADER foo.h)
+set_property(TARGET iface APPEND PROPERTY PUBLIC_HEADER bar.h)
+get_target_property(outname iface PUBLIC_HEADER)
+
+set_property(TARGET iface PROPERTY PRIVATE_HEADER foo.h)
+set_property(TARGET iface APPEND PROPERTY PRIVATE_HEADER bar.h)
+get_target_property(outname iface PRIVATE_HEADER)