Преглед изворни кода

Merge topic '16733-bundle-genex'

d1dac1ac Xcode: Execute RunCMake.Framework also for Xcode generator
d02709d7 Genex: Add `TARGET_BUNDLE_[CONTENT_]_DIR` generator expressions
013ffe76 cmGeneratorTarget: Call GetFrameworkDirectory in GetFullNameInternal
32e9d0ca cmGeneratorTarget: Use enum to describe bundle directory query level

Acked-by: Kitware Robot <[email protected]>
Reviewed-by: Craig Scott <[email protected]>
Merge-request: !635
Brad King пре 8 година
родитељ
комит
c791fb1254
24 измењених фајлова са 245 додато и 54 уклоњено
  1. 9 0
      Help/manual/cmake-generator-expressions.7.rst
  2. 12 0
      Help/release/dev/bundle-genex.rst
  3. 61 0
      Source/cmGeneratorExpressionNode.cxx
  4. 35 29
      Source/cmGeneratorTarget.cxx
  5. 16 7
      Source/cmGeneratorTarget.h
  6. 15 9
      Source/cmOSXBundleGenerator.cxx
  7. 5 0
      Tests/RunCMake/Framework/FrameworkLayout.cmake
  8. 1 1
      Tests/RunCMake/Framework/OSXFrameworkLayout-build-check.cmake
  9. 4 7
      Tests/RunCMake/Framework/RunCMakeTest.cmake
  10. 1 1
      Tests/RunCMake/Framework/iOSFrameworkLayout-build-check.cmake
  11. 1 0
      Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR-result.txt
  12. 8 0
      Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR-stderr.txt
  13. 2 0
      Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR.cmake
  14. 1 0
      Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_DIR-result.txt
  15. 8 0
      Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_DIR-stderr.txt
  16. 2 0
      Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_DIR.cmake
  17. 1 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR-result.txt
  18. 8 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR-stderr.txt
  19. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR.cmake
  20. 1 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_DIR-result.txt
  21. 8 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_DIR-stderr.txt
  22. 9 0
      Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_DIR.cmake
  23. 4 0
      Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake
  24. 24 0
      Tests/RunCMake/XcodeProject/XcodeBundles.cmake

+ 9 - 0
Help/manual/cmake-generator-expressions.7.rst

@@ -205,6 +205,15 @@ Available informational expressions are:
   Name of the linker generated program database file (.pdb).
 ``$<TARGET_PDB_FILE_DIR:tgt>``
   Directory of the linker generated program database file (.pdb).
+``$<TARGET_BUNDLE_DIR:tgt>``
+  Full path to the bundle directory (``my.app``, ``my.framework``, or
+  ``my.bundle``) where ``tgt`` is the name of a target.
+``$<TARGET_BUNDLE_CONTENT_DIR:tgt>``
+  Full path to the bundle content directory where ``tgt`` is the name of a
+  target. For the macOS SDK it leads to ``my.app/Contents``, ``my.framework``,
+  or ``my.bundle/Contents``. For all other SDKs (e.g. iOS) it leads to
+  ``my.app``, ``my.framework``, or ``my.bundle`` due to the flat bundle
+  structure.
 ``$<TARGET_PROPERTY:tgt,prop>``
   Value of the property ``prop`` on the target ``tgt``.
 

+ 12 - 0
Help/release/dev/bundle-genex.rst

@@ -0,0 +1,12 @@
+bundle-genex
+------------
+
+* Two new informational generator expressions to retrieve Apple Bundle
+  directories have been added. The first one ``$<TARGET_BUNDLE_DIR:tgt>``
+  outputs the full path to the Bundle directory, the other one
+  ``$<TARGET_BUNDLE_CONTENT_DIR:tgt>`` outputs the full path to the
+  ``Contents`` directory of macOS Bundles and App Bundles. For all other
+  bundle types and SDKs it is identical with ``$<TARGET_BUNDLE_DIR:tgt>``.
+
+  Those new expressions are helpful to query Bundle locations independent of
+  the different Bundle types and layouts on macOS and iOS.

+ 61 - 0
Source/cmGeneratorExpressionNode.cxx

@@ -1504,6 +1504,8 @@ class ArtifactNameTag;
 class ArtifactPathTag;
 class ArtifactPdbTag;
 class ArtifactSonameTag;
+class ArtifactBundleDirTag;
+class ArtifactBundleContentDirTag;
 
 template <typename ArtifactT>
 struct TargetFilesystemArtifactResultCreator
@@ -1599,6 +1601,56 @@ struct TargetFilesystemArtifactResultCreator<ArtifactLinkerTag>
   }
 };
 
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactBundleDirTag>
+{
+  static std::string Create(cmGeneratorTarget* target,
+                            cmGeneratorExpressionContext* context,
+                            const GeneratorExpressionContent* content)
+  {
+    if (target->IsImported()) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "TARGET_BUNDLE_DIR not allowed for IMPORTED targets.");
+      return std::string();
+    }
+    if (!target->IsBundleOnApple()) {
+      ::reportError(context, content->GetOriginalExpression(),
+                    "TARGET_BUNDLE_DIR is allowed only for Bundle targets.");
+      return std::string();
+    }
+
+    std::string outpath = target->GetDirectory(context->Config) + '/';
+    return target->BuildBundleDirectory(outpath, context->Config,
+                                        cmGeneratorTarget::BundleDirLevel);
+  }
+};
+
+template <>
+struct TargetFilesystemArtifactResultCreator<ArtifactBundleContentDirTag>
+{
+  static std::string Create(cmGeneratorTarget* target,
+                            cmGeneratorExpressionContext* context,
+                            const GeneratorExpressionContent* content)
+  {
+    if (target->IsImported()) {
+      ::reportError(
+        context, content->GetOriginalExpression(),
+        "TARGET_BUNDLE_CONTENT_DIR not allowed for IMPORTED targets.");
+      return std::string();
+    }
+    if (!target->IsBundleOnApple()) {
+      ::reportError(
+        context, content->GetOriginalExpression(),
+        "TARGET_BUNDLE_CONTENT_DIR is allowed only for Bundle targets.");
+      return std::string();
+    }
+
+    std::string outpath = target->GetDirectory(context->Config) + '/';
+    return target->BuildBundleDirectory(outpath, context->Config,
+                                        cmGeneratorTarget::ContentLevel);
+  }
+};
+
 template <>
 struct TargetFilesystemArtifactResultCreator<ArtifactNameTag>
 {
@@ -1716,6 +1768,13 @@ static const TargetFilesystemArtifactNodeGroup<ArtifactSonameTag>
 static const TargetFilesystemArtifactNodeGroup<ArtifactPdbTag>
   targetPdbNodeGroup;
 
+static const TargetFilesystemArtifact<ArtifactBundleDirTag, ArtifactPathTag>
+  targetBundleDirNode;
+
+static const TargetFilesystemArtifact<ArtifactBundleContentDirTag,
+                                      ArtifactPathTag>
+  targetBundleContentDirNode;
+
 static const struct ShellPathNode : public cmGeneratorExpressionNode
 {
   ShellPathNode() {}
@@ -1772,6 +1831,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode(
     nodeMap["TARGET_LINKER_FILE_DIR"] = &targetLinkerNodeGroup.FileDir;
     nodeMap["TARGET_SONAME_FILE_DIR"] = &targetSoNameNodeGroup.FileDir;
     nodeMap["TARGET_PDB_FILE_DIR"] = &targetPdbNodeGroup.FileDir;
+    nodeMap["TARGET_BUNDLE_DIR"] = &targetBundleDirNode;
+    nodeMap["TARGET_BUNDLE_CONTENT_DIR"] = &targetBundleContentDirNode;
     nodeMap["STREQUAL"] = &strEqualNode;
     nodeMap["EQUAL"] = &equalNode;
     nodeMap["LOWER_CASE"] = &lowerCaseNode;

+ 35 - 29
Source/cmGeneratorTarget.cxx

@@ -914,7 +914,7 @@ const char* cmGeneratorTarget::GetLocationForBuild() const
   }
 
   if (this->IsAppBundleOnApple()) {
-    std::string macdir = this->BuildMacContentDirectory("", "", false);
+    std::string macdir = this->BuildBundleDirectory("", "", FullLevel);
     if (!macdir.empty()) {
       location += "/";
       location += macdir;
@@ -1544,8 +1544,19 @@ std::string cmGeneratorTarget::GetSOName(const std::string& config) const
   return soName;
 }
 
-std::string cmGeneratorTarget::GetAppBundleDirectory(const std::string& config,
-                                                     bool contentOnly) const
+static bool shouldAddFullLevel(cmGeneratorTarget::BundleDirectoryLevel level)
+{
+  return level == cmGeneratorTarget::FullLevel;
+}
+
+static bool shouldAddContentLevel(
+  cmGeneratorTarget::BundleDirectoryLevel level)
+{
+  return level == cmGeneratorTarget::ContentLevel || shouldAddFullLevel(level);
+}
+
+std::string cmGeneratorTarget::GetAppBundleDirectory(
+  const std::string& config, BundleDirectoryLevel level) const
 {
   std::string fpath = this->GetFullName(config, false);
   fpath += ".";
@@ -1554,9 +1565,9 @@ std::string cmGeneratorTarget::GetAppBundleDirectory(const std::string& config,
     ext = "app";
   }
   fpath += ext;
-  if (!this->Makefile->PlatformIsAppleIos()) {
+  if (shouldAddContentLevel(level) && !this->Makefile->PlatformIsAppleIos()) {
     fpath += "/Contents";
-    if (!contentOnly) {
+    if (shouldAddFullLevel(level)) {
       fpath += "/MacOS";
     }
   }
@@ -1569,8 +1580,8 @@ bool cmGeneratorTarget::IsBundleOnApple() const
     this->IsCFBundleOnApple();
 }
 
-std::string cmGeneratorTarget::GetCFBundleDirectory(const std::string& config,
-                                                    bool contentOnly) const
+std::string cmGeneratorTarget::GetCFBundleDirectory(
+  const std::string& config, BundleDirectoryLevel level) const
 {
   std::string fpath;
   fpath += this->GetOutputName(config, false);
@@ -1584,17 +1595,17 @@ std::string cmGeneratorTarget::GetCFBundleDirectory(const std::string& config,
     }
   }
   fpath += ext;
-  if (!this->Makefile->PlatformIsAppleIos()) {
+  if (shouldAddContentLevel(level) && !this->Makefile->PlatformIsAppleIos()) {
     fpath += "/Contents";
-    if (!contentOnly) {
+    if (shouldAddFullLevel(level)) {
       fpath += "/MacOS";
     }
   }
   return fpath;
 }
 
-std::string cmGeneratorTarget::GetFrameworkDirectory(const std::string& config,
-                                                     bool rootDir) const
+std::string cmGeneratorTarget::GetFrameworkDirectory(
+  const std::string& config, BundleDirectoryLevel level) const
 {
   std::string fpath;
   fpath += this->GetOutputName(config, false);
@@ -1604,7 +1615,7 @@ std::string cmGeneratorTarget::GetFrameworkDirectory(const std::string& config,
     ext = "framework";
   }
   fpath += ext;
-  if (!rootDir && !this->Makefile->PlatformIsAppleIos()) {
+  if (shouldAddFullLevel(level) && !this->Makefile->PlatformIsAppleIos()) {
     fpath += "/Versions/";
     fpath += this->GetFrameworkVersion();
   }
@@ -1919,18 +1930,19 @@ void cmGeneratorTarget::GetFullNameComponents(std::string& prefix,
   this->GetFullNameInternal(config, implib, prefix, base, suffix);
 }
 
-std::string cmGeneratorTarget::BuildMacContentDirectory(
-  const std::string& base, const std::string& config, bool contentOnly) const
+std::string cmGeneratorTarget::BuildBundleDirectory(
+  const std::string& base, const std::string& config,
+  BundleDirectoryLevel level) const
 {
   std::string fpath = base;
   if (this->IsAppBundleOnApple()) {
-    fpath += this->GetAppBundleDirectory(config, contentOnly);
+    fpath += this->GetAppBundleDirectory(config, level);
   }
   if (this->IsFrameworkOnApple()) {
-    fpath += this->GetFrameworkDirectory(config, contentOnly);
+    fpath += this->GetFrameworkDirectory(config, level);
   }
   if (this->IsCFBundleOnApple()) {
-    fpath += this->GetCFBundleDirectory(config, contentOnly);
+    fpath += this->GetCFBundleDirectory(config, level);
   }
   return fpath;
 }
@@ -1941,13 +1953,13 @@ std::string cmGeneratorTarget::GetMacContentDirectory(
   // Start with the output directory for the target.
   std::string fpath = this->GetDirectory(config, implib);
   fpath += "/";
-  bool contentOnly = true;
+  BundleDirectoryLevel level = ContentLevel;
   if (this->IsFrameworkOnApple()) {
     // additional files with a framework go into the version specific
     // directory
-    contentOnly = false;
+    level = FullLevel;
   }
-  fpath = this->BuildMacContentDirectory(fpath, config, contentOnly);
+  fpath = this->BuildBundleDirectory(fpath, config, level);
   return fpath;
 }
 
@@ -2997,7 +3009,7 @@ std::string cmGeneratorTarget::NormalGetFullPath(const std::string& config,
   std::string fpath = this->GetDirectory(config, implib);
   fpath += "/";
   if (this->IsAppBundleOnApple()) {
-    fpath = this->BuildMacContentDirectory(fpath, config, false);
+    fpath = this->BuildBundleDirectory(fpath, config, FullLevel);
     fpath += "/";
   }
 
@@ -3281,20 +3293,14 @@ void cmGeneratorTarget::GetFullNameInternal(const std::string& config,
   // frameworks have directory prefix but no suffix
   std::string fw_prefix;
   if (this->IsFrameworkOnApple()) {
-    fw_prefix = this->GetOutputName(config, false);
-    fw_prefix += ".";
-    const char* ext = this->GetProperty("BUNDLE_EXTENSION");
-    if (!ext) {
-      ext = "framework";
-    }
-    fw_prefix += ext;
+    fw_prefix = this->GetFrameworkDirectory(config, ContentLevel);
     fw_prefix += "/";
     targetPrefix = fw_prefix.c_str();
     targetSuffix = CM_NULLPTR;
   }
 
   if (this->IsCFBundleOnApple()) {
-    fw_prefix = this->GetCFBundleDirectory(config, false);
+    fw_prefix = this->GetCFBundleDirectory(config, FullLevel);
     fw_prefix += "/";
     targetPrefix = fw_prefix.c_str();
     targetSuffix = CM_NULLPTR;

+ 16 - 7
Source/cmGeneratorTarget.h

@@ -160,9 +160,17 @@ public:
                                 bool realname) const;
   std::string NormalGetRealName(const std::string& config) const;
 
+  /** What hierarchy level should the reported directory contain */
+  enum BundleDirectoryLevel
+  {
+    BundleDirLevel,
+    ContentLevel,
+    FullLevel
+  };
+
   /** @return the Mac App directory without the base */
   std::string GetAppBundleDirectory(const std::string& config,
-                                    bool contentOnly) const;
+                                    BundleDirectoryLevel level) const;
 
   /** Return whether this target is an executable Bundle, a framework
       or CFBundle on Apple.  */
@@ -175,7 +183,7 @@ public:
 
   /** @return the Mac framework directory without the base. */
   std::string GetFrameworkDirectory(const std::string& config,
-                                    bool rootDir) const;
+                                    BundleDirectoryLevel level) const;
 
   /** Return the framework version string.  Undefined if
       IsFrameworkOnApple returns false.  */
@@ -183,7 +191,7 @@ public:
 
   /** @return the Mac CFBundle directory without the base */
   std::string GetCFBundleDirectory(const std::string& config,
-                                   bool contentOnly) const;
+                                   BundleDirectoryLevel level) const;
 
   /** Return the install name directory for the target in the
     * build tree.  For example: "\@rpath/", "\@loader_path/",
@@ -218,10 +226,11 @@ public:
                              const std::string& config = "",
                              bool implib = false) const;
 
-  /** Append to @a base the mac content directory and return it. */
-  std::string BuildMacContentDirectory(const std::string& base,
-                                       const std::string& config = "",
-                                       bool contentOnly = true) const;
+  /** Append to @a base the bundle directory hierarchy up to a certain @a level
+   * and return it. */
+  std::string BuildBundleDirectory(const std::string& base,
+                                   const std::string& config,
+                                   BundleDirectoryLevel level) const;
 
   /** @return the mac content directory for this target. */
   std::string GetMacContentDirectory(const std::string& config = CM_NULLPTR,

+ 15 - 9
Source/cmOSXBundleGenerator.cxx

@@ -42,7 +42,8 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
   // Compute bundle directory names.
   std::string out = outpath;
   out += "/";
-  out += this->GT->GetAppBundleDirectory(this->ConfigName, false);
+  out += this->GT->GetAppBundleDirectory(this->ConfigName,
+                                         cmGeneratorTarget::FullLevel);
   cmSystemTools::MakeDirectory(out.c_str());
   this->Makefile->AddCMakeOutputFile(out);
 
@@ -52,7 +53,8 @@ void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
   // to be set.
   std::string plist = outpath;
   plist += "/";
-  plist += this->GT->GetAppBundleDirectory(this->ConfigName, true);
+  plist += this->GT->GetAppBundleDirectory(this->ConfigName,
+                                           cmGeneratorTarget::ContentLevel);
   plist += "/Info.plist";
   this->LocalGenerator->GenerateAppleInfoPList(this->GT, targetName,
                                                plist.c_str());
@@ -70,12 +72,14 @@ void cmOSXBundleGenerator::CreateFramework(const std::string& targetName,
   assert(this->MacContentFolders);
 
   // Compute the location of the top-level foo.framework directory.
-  std::string contentdir =
-    outpath + "/" + this->GT->GetFrameworkDirectory(this->ConfigName, true);
+  std::string contentdir = outpath + "/" +
+    this->GT->GetFrameworkDirectory(this->ConfigName,
+                                    cmGeneratorTarget::ContentLevel);
   contentdir += "/";
 
-  std::string newoutpath =
-    outpath + "/" + this->GT->GetFrameworkDirectory(this->ConfigName, false);
+  std::string newoutpath = outpath + "/" +
+    this->GT->GetFrameworkDirectory(this->ConfigName,
+                                    cmGeneratorTarget::FullLevel);
 
   std::string frameworkVersion = this->GT->GetFrameworkVersion();
 
@@ -170,14 +174,16 @@ void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName,
   // Compute bundle directory names.
   std::string out = root;
   out += "/";
-  out += this->GT->GetCFBundleDirectory(this->ConfigName, false);
+  out += this->GT->GetCFBundleDirectory(this->ConfigName,
+                                        cmGeneratorTarget::FullLevel);
   cmSystemTools::MakeDirectory(out.c_str());
   this->Makefile->AddCMakeOutputFile(out);
 
   // Configure the Info.plist file.  Note that it needs the executable name
   // to be set.
-  std::string plist =
-    root + "/" + this->GT->GetCFBundleDirectory(this->ConfigName, true);
+  std::string plist = root + "/" +
+    this->GT->GetCFBundleDirectory(this->ConfigName,
+                                   cmGeneratorTarget::ContentLevel);
   plist += "/Info.plist";
   std::string name = cmSystemTools::GetFilenameName(targetName);
   this->LocalGenerator->GenerateAppleInfoPList(this->GT, name, plist.c_str());

+ 5 - 0
Tests/RunCMake/Framework/FrameworkLayout.cmake

@@ -1,6 +1,9 @@
 cmake_minimum_required(VERSION 3.4)
 enable_language(C)
 
+set(CMAKE_CONFIGURATION_TYPES "Debug" CACHE INTERNAL "Supported configuration types")
+set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}) # get rid of ${EFFECTIVE_PLATFORM_NAME}
+
 add_library(Framework ${FRAMEWORK_TYPE}
             foo.c
             foo.h
@@ -18,3 +21,5 @@ set_source_files_properties(some.txt PROPERTIES MACOSX_PACKAGE_LOCATION somedir)
 
 add_custom_command(TARGET Framework POST_BUILD
                    COMMAND /usr/bin/file $<TARGET_FILE:Framework>)
+
+file(GENERATE OUTPUT FrameworkName.cmake CONTENT "set(framework-dir \"$<TARGET_BUNDLE_DIR:Framework>\")\n")

+ 1 - 1
Tests/RunCMake/Framework/OSXFrameworkLayout-build-check.cmake

@@ -1,4 +1,4 @@
-set(framework-dir "${RunCMake_TEST_BINARY_DIR}/Framework.framework")
+include("${RunCMake_TEST_BINARY_DIR}/FrameworkName.cmake")
 set(framework-resources "${framework-dir}/Resources")
 set(framework-resource-file "${framework-resources}/res.txt")
 set(framework-flat-resource-file "${framework-resources}/flatresource.txt")

+ 4 - 7
Tests/RunCMake/Framework/RunCMakeTest.cmake

@@ -13,13 +13,10 @@ function(framework_layout_test Name Toolchain Type)
   run_cmake_command(${Name} ${CMAKE_COMMAND} --build .)
 endfunction()
 
-# build check cannot cope with multi-configuration generators directory layout
-if(NOT RunCMake_GENERATOR STREQUAL "Xcode")
-  framework_layout_test(iOSFrameworkLayout-build ios SHARED)
-  framework_layout_test(iOSFrameworkLayout-build ios STATIC)
-  framework_layout_test(OSXFrameworkLayout-build osx SHARED)
-  framework_layout_test(OSXFrameworkLayout-build osx STATIC)
-endif()
+framework_layout_test(iOSFrameworkLayout-build ios SHARED)
+framework_layout_test(iOSFrameworkLayout-build ios STATIC)
+framework_layout_test(OSXFrameworkLayout-build osx SHARED)
+framework_layout_test(OSXFrameworkLayout-build osx STATIC)
 
 function(framework_type_test Toolchain Type)
   set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${Toolchain}${Type}FrameworkType-build)

+ 1 - 1
Tests/RunCMake/Framework/iOSFrameworkLayout-build-check.cmake

@@ -1,4 +1,4 @@
-set(framework-dir "${RunCMake_TEST_BINARY_DIR}/Framework.framework")
+include("${RunCMake_TEST_BINARY_DIR}/FrameworkName.cmake")
 set(framework-resources "${framework-dir}/Resources")
 set(framework-resource-file "${framework-dir}/res.txt")
 set(framework-flat-resource-file "${framework-dir}/flatresource.txt")

+ 1 - 0
Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at ImportedTarget-TARGET_BUNDLE_CONTENT_DIR.cmake:[0-9]* \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<TARGET_BUNDLE_CONTENT_DIR:empty>
+
+  TARGET_BUNDLE_CONTENT_DIR not allowed for IMPORTED targets.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]* \(include\)

+ 2 - 0
Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_CONTENT_DIR.cmake

@@ -0,0 +1,2 @@
+add_library(empty UNKNOWN IMPORTED)
+add_custom_target(custom COMMAND echo $<TARGET_BUNDLE_CONTENT_DIR:empty>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_DIR-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_DIR-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at ImportedTarget-TARGET_BUNDLE_DIR.cmake:[0-9]* \(add_custom_target\):
+  Error evaluating generator expression:
+
+    \$<TARGET_BUNDLE_DIR:empty>
+
+  TARGET_BUNDLE_DIR not allowed for IMPORTED targets.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]* \(include\)

+ 2 - 0
Tests/RunCMake/GeneratorExpression/ImportedTarget-TARGET_BUNDLE_DIR.cmake

@@ -0,0 +1,2 @@
+add_library(empty UNKNOWN IMPORTED)
+add_custom_target(custom COMMAND echo $<TARGET_BUNDLE_DIR:empty>)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at NonValidTarget-TARGET_BUNDLE_CONTENT_DIR.cmake:[0-9]* \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_BUNDLE_CONTENT_DIR:empty>
+
+  TARGET_BUNDLE_CONTENT_DIR is allowed only for Bundle targets.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]* \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_CONTENT_DIR.cmake

@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_library(empty STATIC empty.c)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_BUNDLE_CONTENT_DIR:empty>]"
+)

+ 1 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_DIR-result.txt

@@ -0,0 +1 @@
+1

+ 8 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_DIR-stderr.txt

@@ -0,0 +1,8 @@
+CMake Error at NonValidTarget-TARGET_BUNDLE_DIR.cmake:[0-9]* \(file\):
+  Error evaluating generator expression:
+
+    \$<TARGET_BUNDLE_DIR:empty>
+
+  TARGET_BUNDLE_DIR is allowed only for Bundle targets.
+Call Stack \(most recent call first\):
+  CMakeLists.txt:[0-9]* \(include\)

+ 9 - 0
Tests/RunCMake/GeneratorExpression/NonValidTarget-TARGET_BUNDLE_DIR.cmake

@@ -0,0 +1,9 @@
+
+enable_language(C)
+
+add_library(empty STATIC empty.c)
+
+file(GENERATE
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/test.txt"
+  CONTENT "[$<TARGET_BUNDLE_DIR:empty>]"
+)

+ 4 - 0
Tests/RunCMake/GeneratorExpression/RunCMakeTest.cmake

@@ -17,6 +17,8 @@ run_cmake(NonValidTarget-C_COMPILER_ID)
 run_cmake(NonValidTarget-CXX_COMPILER_ID)
 run_cmake(NonValidTarget-C_COMPILER_VERSION)
 run_cmake(NonValidTarget-CXX_COMPILER_VERSION)
+run_cmake(NonValidTarget-TARGET_BUNDLE_DIR)
+run_cmake(NonValidTarget-TARGET_BUNDLE_CONTENT_DIR)
 run_cmake(NonValidTarget-TARGET_PROPERTY)
 run_cmake(NonValidTarget-TARGET_POLICY)
 run_cmake(COMPILE_LANGUAGE-add_custom_target)
@@ -32,6 +34,8 @@ run_cmake(OUTPUT_NAME-recursion)
 run_cmake(TARGET_PROPERTY-LOCATION)
 run_cmake(LINK_ONLY-not-linking)
 
+run_cmake(ImportedTarget-TARGET_BUNDLE_DIR)
+run_cmake(ImportedTarget-TARGET_BUNDLE_CONTENT_DIR)
 run_cmake(ImportedTarget-TARGET_PDB_FILE)
 if(LINKER_SUPPORTS_PDB)
   run_cmake(NonValidTarget-TARGET_PDB_FILE)

+ 24 - 0
Tests/RunCMake/XcodeProject/XcodeBundles.cmake

@@ -57,6 +57,10 @@ if(NOT TEST_IOS OR NOT XCODE_VERSION VERSION_LESS 6)
   set_target_properties(SharedFramework PROPERTIES FRAMEWORK TRUE)
 
   add_custom_target(SharedFrameworkTest ALL
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_DIR:SharedFramework>" "$<TARGET_BUNDLE_DIR:SharedFramework>.old"
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_CONTENT_DIR:SharedFramework>" "$<TARGET_BUNDLE_CONTENT_DIR:SharedFramework>.old"
     COMMAND ${CMAKE_COMMAND} -E copy
       "$<TARGET_FILE:SharedFramework>" "$<TARGET_FILE:SharedFramework>.old")
 
@@ -70,6 +74,10 @@ if(NOT TEST_IOS OR NOT XCODE_VERSION VERSION_LESS 6)
   install(TARGETS SharedFrameworkExt FRAMEWORK DESTINATION FooExtension)
 
   add_custom_target(SharedFrameworkExtTest ALL
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_DIR:SharedFrameworkExt>" "$<TARGET_BUNDLE_DIR:SharedFrameworkExt>.old"
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_CONTENT_DIR:SharedFrameworkExt>" "$<TARGET_BUNDLE_CONTENT_DIR:SharedFrameworkExt>.old"
     COMMAND ${CMAKE_COMMAND} -E copy
       "$<TARGET_FILE:SharedFrameworkExt>" "$<TARGET_FILE:SharedFrameworkExt>.old")
 
@@ -83,6 +91,10 @@ if(NOT XCODE_VERSION VERSION_LESS 6)
   set_target_properties(StaticFramework PROPERTIES FRAMEWORK TRUE)
 
   add_custom_target(StaticFrameworkTest ALL
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_DIR:StaticFramework>" "$<TARGET_BUNDLE_DIR:StaticFramework>.old"
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_CONTENT_DIR:StaticFramework>" "$<TARGET_BUNDLE_CONTENT_DIR:StaticFramework>.old"
     COMMAND ${CMAKE_COMMAND} -E copy
       "$<TARGET_FILE:StaticFramework>" "$<TARGET_FILE:StaticFramework>.old")
 
@@ -96,6 +108,10 @@ if(NOT XCODE_VERSION VERSION_LESS 6)
   install(TARGETS StaticFrameworkExt FRAMEWORK DESTINATION StaticFooExtension)
 
   add_custom_target(StaticFrameworkExtTest ALL
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_DIR:StaticFrameworkExt>" "$<TARGET_BUNDLE_DIR:StaticFrameworkExt>.old"
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_CONTENT_DIR:StaticFrameworkExt>" "$<TARGET_BUNDLE_CONTENT_DIR:StaticFrameworkExt>.old"
     COMMAND ${CMAKE_COMMAND} -E copy
       "$<TARGET_FILE:StaticFrameworkExt>" "$<TARGET_FILE:StaticFrameworkExt>.old")
 
@@ -109,6 +125,10 @@ if(NOT CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE)
   set_target_properties(Bundle PROPERTIES BUNDLE TRUE)
 
   add_custom_target(BundleTest ALL
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_DIR:Bundle>" "$<TARGET_BUNDLE_DIR:Bundle>.old"
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_CONTENT_DIR:Bundle>" "$<TARGET_BUNDLE_CONTENT_DIR:Bundle>.old"
     COMMAND ${CMAKE_COMMAND} -E copy
       "$<TARGET_FILE:Bundle>" "$<TARGET_FILE:Bundle>.old")
 
@@ -122,6 +142,10 @@ if(NOT CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE)
   install(TARGETS BundleExt LIBRARY DESTINATION FooExtension)
 
   add_custom_target(BundleExtTest ALL
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_DIR:BundleExt>" "$<TARGET_BUNDLE_DIR:BundleExt>.old"
+    COMMAND ${CMAKE_COMMAND} -E copy
+      "$<TARGET_BUNDLE_CONTENT_DIR:BundleExt>" "$<TARGET_BUNDLE_CONTENT_DIR:BundleExt>.old"
     COMMAND ${CMAKE_COMMAND} -E copy
       "$<TARGET_FILE:BundleExt>" "$<TARGET_FILE:BundleExt>.old")