Quellcode durchsuchen

ENH: Finish up the Framework creation code restructuring. Frameworks build and install now. More work needed on the packaging step. See Tests/Framework for example use.

David Cole vor 18 Jahren
Ursprung
Commit
8e4c7b99e1

+ 22 - 0
Source/cmGlobalGenerator.cxx

@@ -1277,6 +1277,7 @@ cmLocalGenerator* cmGlobalGenerator::FindLocalGenerator(const char* start_dir)
 }
 
 
+//----------------------------------------------------------------------------
 cmTarget* cmGlobalGenerator::FindTarget(const char* project,
                                         const char* name,
                                         bool useImportedTargets)
@@ -1318,6 +1319,27 @@ cmTarget* cmGlobalGenerator::FindTarget(const char* project,
   return 0;
 }
 
+//----------------------------------------------------------------------------
+bool cmGlobalGenerator::NameResolvesToFramework(const std::string& libname)
+{
+  if(cmSystemTools::IsPathToFramework(libname.c_str()))
+    {
+    return true;
+    }
+
+  if(cmTarget* tgt = this->FindTarget(0, libname.c_str(), true))
+    {
+    if(tgt->GetType() == cmTarget::SHARED_LIBRARY &&
+       tgt->GetPropertyAsBool("FRAMEWORK"))
+       {
+       return true;
+       }
+    }
+
+  return false;
+}
+
+//----------------------------------------------------------------------------
 inline std::string removeQuotes(const std::string& s)
 {
   if(s[0] == '\"' && s[s.size()-1] == '\"')

+ 4 - 0
Source/cmGlobalGenerator.h

@@ -187,6 +187,10 @@ public:
                        const char* name, 
                        bool useImportedTargets);
 
+  /** Determine if a name resolves to a framework on disk or a built target
+      that is a framework. */
+  bool NameResolvesToFramework(const std::string& libname);
+
   /** If check to see if the target is linked to by any other
       target in the project */
   bool IsDependedOn(const char* project, cmTarget* target);

+ 44 - 29
Source/cmGlobalXCodeGenerator.cxx

@@ -23,7 +23,6 @@ PURPOSE.  See the above copyright notices for more information.
 #include "cmake.h"
 #include "cmGeneratedFileStream.h"
 #include "cmSourceFile.h"
-#include "cmOrderLinkDirectories.h"
 
 //----------------------------------------------------------------------------
 #if defined(CMAKE_BUILD_WITH_CMAKE)
@@ -427,18 +426,6 @@ cmXCodeObject* cmGlobalXCodeGenerator
   return obj;
 }
 
-//----------------------------------------------------------------------------
-bool IsResource(cmSourceFile* sf)
-{
-  const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION");
-
-  bool isResource =
-    (sf->GetPropertyAsBool("FRAMEWORK_RESOURCE") ||
-     (location && cmStdString(location) == "Resources"));
-
-  return isResource;
-}
-
 //----------------------------------------------------------------------------
 cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
 {
@@ -449,8 +436,8 @@ cmStdString GetGroupMapKey(cmTarget& cmtarget, cmSourceFile* sf)
 }
 
 //----------------------------------------------------------------------------
-cmXCodeObject* 
-cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg, 
+cmXCodeObject*
+cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
                                               cmSourceFile* sf,
                                               cmTarget& cmtarget)
 {
@@ -498,7 +485,8 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
 
   // Is this a resource file in this target? Add it to the resources group...
   //
-  bool isResource = IsResource(sf);
+  cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf);
+  bool isResource = tsFlags.Resource;
 
   // Is this a "private" or "public" framework header file?
   // Set the ATTRIBUTES attribute appropriately...
@@ -506,14 +494,14 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
   if(cmtarget.GetType() == cmTarget::SHARED_LIBRARY &&
      cmtarget.GetPropertyAsBool("FRAMEWORK"))
     {
-    if(sf->GetPropertyAsBool("FRAMEWORK_PRIVATE_HEADER"))
+    if(tsFlags.PrivateHeader)
       {
       cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
       attrs->AddObject(this->CreateString("Private"));
       settings->AddAttribute("ATTRIBUTES", attrs);
       isResource = true;
       }
-    else if(sf->GetPropertyAsBool("FRAMEWORK_PUBLIC_HEADER"))
+    else if(tsFlags.PublicHeader)
       {
       cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
       attrs->AddObject(this->CreateString("Public"));
@@ -693,6 +681,9 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
       cmXCodeObject* filetype = 
         fr->GetObject()->GetObject("lastKnownFileType");
 
+      cmTarget::SourceFileFlags tsFlags =
+        cmtarget.GetTargetSourceFileFlags(*i);
+
       if(strcmp(filetype->GetString(), "\"compiled.mach-o.objfile\"") == 0)
         {
         externalObjFiles.push_back(xsf);
@@ -701,7 +692,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
         {
         headerFiles.push_back(xsf);
         }
-      else if(IsResource(*i))
+      else if(tsFlags.Resource)
         {
         resourceFiles.push_back(xsf);
         }
@@ -813,8 +804,8 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
           }
         copyFilesBuildPhase->AddAttribute("dstPath",
           this->CreateString(ostr.str().c_str()));
-        copyFilesBuildPhase->AddAttribute("runOnlyForDeploymentPostprocessing",
-          this->CreateString("0"));
+        copyFilesBuildPhase->AddAttribute(
+          "runOnlyForDeploymentPostprocessing", this->CreateString("0"));
         buildFiles = this->CreateObject(cmXCodeObject::OBJECT_LIST);
         copyFilesBuildPhase->AddAttribute("files", buildFiles);
         std::vector<cmSourceFile*>::iterator sfIt;
@@ -1418,6 +1409,14 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
       productType = "com.apple.product-type.framework";
 
       const char* version = target.GetProperty("FRAMEWORK_VERSION");
+      if(!version)
+        {
+        version = target.GetProperty("VERSION");
+        }
+      if(!version)
+        {
+        version = "A";
+        }
       buildSettings->AddAttribute("FRAMEWORK_VERSION",
                                   this->CreateString(version));
       }
@@ -1501,7 +1500,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target,
   for(std::vector<std::string>::iterator i = includes.begin();
       i != includes.end(); ++i)
     {
-    if(cmSystemTools::IsPathToFramework(i->c_str()))
+    if(this->NameResolvesToFramework(i->c_str()))
       {
       std::string frameworkDir = *i;
       frameworkDir += "/../";
@@ -1927,9 +1926,22 @@ void cmGlobalXCodeGenerator::AppendOrAddBuildSetting(cmXCodeObject* settings,
     else
       {
       std::string oldValue = attr->GetString();
-      cmSystemTools::ReplaceString(oldValue, "\"", "");
+
+      // unescape escaped quotes internal to the string:
+      cmSystemTools::ReplaceString(oldValue, "\\\"", "\"");
+
+      // remove surrounding quotes, if any:
+      std::string::size_type len = oldValue.length();
+      if(oldValue[0] == '\"' && oldValue[len-1] == '\"')
+        {
+        oldValue = oldValue.substr(1, len-2);
+        }
+
       oldValue += " ";
       oldValue += value;
+
+      // SetString automatically escapes internal quotes and then surrounds
+      // the result with quotes if necessary...
       attr->SetString(oldValue.c_str());
       }
     }
@@ -2098,8 +2110,8 @@ void cmGlobalXCodeGenerator
           {
           // now add the same one but append $(CONFIGURATION) to it:
           linkDirs += " ";
-          linkDirs += this->XCodeEscapePath(libDir->c_str());
-          linkDirs += "/$(CONFIGURATION)";
+          linkDirs += this->XCodeEscapePath(
+            (*libDir + "/$(CONFIGURATION)").c_str());
           }
         linkDirs += " ";
         linkDirs += this->XCodeEscapePath(libDir->c_str());
@@ -2506,8 +2518,8 @@ cmGlobalXCodeGenerator::CreateXCodeDependHackTarget(
   // one more pass for external depend information not handled
   // correctly by xcode
   makefileStream << "# DO NOT EDIT\n";
-  makefileStream << "# This makefile makes sure all linkable targets are \n";
-  makefileStream << "# up-to-date with anything they link to,avoiding a "
+  makefileStream << "# This makefile makes sure all linkable targets are\n";
+  makefileStream << "# up-to-date with anything they link to, avoiding a "
     "bug in XCode 1.5\n";
   for(std::vector<std::string>::const_iterator
         ct = this->CurrentConfigurationTypes.begin();
@@ -2826,10 +2838,13 @@ cmGlobalXCodeGenerator
       {
       if(dir.find(".framework") != dir.npos)
         {
+        // Remove trailing slashes (so that the rfind does not find the one at
+        // the very end...!)
+        //
+        cmSystemTools::ConvertToUnixSlashes(dir);
         std::string::size_type pos = dir.rfind("/");
         std::string framework = dir.substr(pos);
-        std::string newDir;
-        newDir = dir.substr(0, pos);
+        std::string newDir = dir.substr(0, pos);
         newDir += "/";
         newDir += config;
         dir = newDir;

+ 95 - 81
Source/cmInstallCommand.cxx

@@ -175,9 +175,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
   cmCAStringVector runtimeArgVector     (&argHelper, "RUNTIME", &group);
   cmCAStringVector frameworkArgVector   (&argHelper, "FRAMEWORK", &group);
   cmCAStringVector bundleArgVector      (&argHelper, "BUNDLE", &group);
-  cmCAStringVector resourcesArgVector   (&argHelper, "RESOURCE", &group);
-  cmCAStringVector publicHeaderArgVector(&argHelper, "PUBLIC_HEADER", &group);
   cmCAStringVector privateHeaderArgVector(&argHelper,"PRIVATE_HEADER", &group);
+  cmCAStringVector publicHeaderArgVector(&argHelper, "PUBLIC_HEADER", &group);
+  cmCAStringVector resourceArgVector   (&argHelper, "RESOURCE", &group);
   genericArgVector.Follows(0);
   group.Follows(&genericArgVector);
 
@@ -197,18 +197,18 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
   cmInstallCommandArguments runtimeArgs;
   cmInstallCommandArguments frameworkArgs;
   cmInstallCommandArguments bundleArgs;
-  cmInstallCommandArguments resourcesArgs;
-  cmInstallCommandArguments publicHeaderArgs;
   cmInstallCommandArguments privateHeaderArgs;
+  cmInstallCommandArguments publicHeaderArgs;
+  cmInstallCommandArguments resourceArgs;
 
   archiveArgs.Parse      (&archiveArgVector.GetVector(),       &unknownArgs);
   libraryArgs.Parse      (&libraryArgVector.GetVector(),       &unknownArgs);
   runtimeArgs.Parse      (&runtimeArgVector.GetVector(),       &unknownArgs);
   frameworkArgs.Parse    (&frameworkArgVector.GetVector(),     &unknownArgs);
   bundleArgs.Parse       (&bundleArgVector.GetVector(),        &unknownArgs);
-  resourcesArgs.Parse    (&resourcesArgVector.GetVector(),     &unknownArgs);
-  publicHeaderArgs.Parse (&publicHeaderArgVector.GetVector(),  &unknownArgs);
   privateHeaderArgs.Parse(&privateHeaderArgVector.GetVector(), &unknownArgs);
+  publicHeaderArgs.Parse (&publicHeaderArgVector.GetVector(),  &unknownArgs);
+  resourceArgs.Parse     (&resourceArgVector.GetVector(),      &unknownArgs);
 
   if(!unknownArgs.empty())
     {
@@ -225,18 +225,18 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
   runtimeArgs.SetGenericArguments(&genericArgs);
   frameworkArgs.SetGenericArguments(&genericArgs);
   bundleArgs.SetGenericArguments(&genericArgs);
-  resourcesArgs.SetGenericArguments(&genericArgs);
-  publicHeaderArgs.SetGenericArguments(&genericArgs);
   privateHeaderArgs.SetGenericArguments(&genericArgs);
+  publicHeaderArgs.SetGenericArguments(&genericArgs);
+  resourceArgs.SetGenericArguments(&genericArgs);
 
   success = success && archiveArgs.Finalize();
   success = success && libraryArgs.Finalize();
   success = success && runtimeArgs.Finalize();
   success = success && frameworkArgs.Finalize();
   success = success && bundleArgs.Finalize();
-  success = success && resourcesArgs.Finalize();
-  success = success && publicHeaderArgs.Finalize();
   success = success && privateHeaderArgs.Finalize();
+  success = success && publicHeaderArgs.Finalize();
+  success = success && resourceArgs.Finalize();
 
   if(!success)
     {
@@ -299,9 +299,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     cmInstallTargetGenerator* runtimeGenerator = 0;
     cmInstallTargetGenerator* frameworkGenerator = 0;
     cmInstallTargetGenerator* bundleGenerator = 0;
-    cmInstallFilesGenerator* resourcesGenerator = 0;
-    cmInstallFilesGenerator* publicHeaderGenerator = 0;
     cmInstallFilesGenerator* privateHeaderGenerator = 0;
+    cmInstallFilesGenerator* publicHeaderGenerator = 0;
+    cmInstallFilesGenerator* resourceGenerator = 0;
 
     switch(target.GetType())
       {
@@ -465,84 +465,98 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
 
 //       if(target.GetProperty("ASSOCIATED_FILES");
 
-  const char* files = target.GetProperty("PUBLIC_HEADER");
-  if ((files) && (*files))
-    {
-    std::vector<std::string> relFiles;
-    cmSystemTools::ExpandListArgument(files, relFiles);
-    std::vector<std::string> absFiles;
-    if (!this->MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles))
-      {
-      return false;
-      }
+  // These well-known sets of files are installed *automatically* for FRAMEWORK
+  // SHARED library targets on the Mac as part of installing the FRAMEWORK.
+  // For other target types or on other platforms, they are not installed
+  // automatically and so we need to create install files generators for them.
+  //
+  bool createInstallGeneratorsForTargetFileSets = true;
 
-    // Create the files install generator.
-    if (!publicHeaderArgs.GetDestination().empty())
-      {
-      publicHeaderGenerator = CreateInstallFilesGenerator(absFiles, 
-                                                      publicHeaderArgs, false);
-      }
-    else
-      {
-      cmOStringStream e;
-      e << "TARGETS given no PUBLIC_HEADER DESTINATION for header files\"" 
-          << target.GetName() << "\".";
-      this->SetError(e.str().c_str());
-      return false;
-      }
+  if(cmTarget::SHARED_LIBRARY == target.GetType() &&
+    target.GetPropertyAsBool("FRAMEWORK") &&
+    this->Makefile->IsOn("APPLE"))
+    {
+    createInstallGeneratorsForTargetFileSets = false;
     }
 
-  files = target.GetProperty("PRIVATE_HEADER");
-  if ((files) && (*files))
+  if(createInstallGeneratorsForTargetFileSets)
     {
-    std::vector<std::string> relFiles;
-    cmSystemTools::ExpandListArgument(files, relFiles);
-    std::vector<std::string> absFiles;
-    if (!this->MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles))
+    const char* files = target.GetProperty("PRIVATE_HEADER");
+    if ((files) && (*files))
       {
-      return false;
-      }
+      std::vector<std::string> relFiles;
+      cmSystemTools::ExpandListArgument(files, relFiles);
+      std::vector<std::string> absFiles;
+      if (!this->MakeFilesFullPath("PRIVATE_HEADER", relFiles, absFiles))
+        {
+        return false;
+        }
 
-    // Create the files install generator.
-    if (!privateHeaderArgs.GetDestination().empty())
-      {
-      privateHeaderGenerator = CreateInstallFilesGenerator(absFiles, 
+      // Create the files install generator.
+      if (!privateHeaderArgs.GetDestination().empty())
+        {
+        privateHeaderGenerator = CreateInstallFilesGenerator(absFiles, 
                                                      privateHeaderArgs, false);
+        }
+      else
+        {
+        cmOStringStream e;
+        e << "INSTALL TARGETS - target " << target.GetName() << " has "
+          << "PRIVATE_HEADER files but no PRIVATE_HEADER DESTINATION.";
+        cmSystemTools::Message(e.str().c_str(), "Warning");
+        }
       }
-    else
-      {
-      cmOStringStream e;
-      e << "TARGETS given no PRIVATE_HEADER DESTINATION for header files\"" 
-          << target.GetName() << "\".";
-      this->SetError(e.str().c_str());
-      return false;
-      }
-    }
 
-  files = target.GetProperty("RESOURCE_FILES");
-  if ((files) && (*files))
-    {
-    std::vector<std::string> relFiles;
-    cmSystemTools::ExpandListArgument(files, relFiles);
-    std::vector<std::string> absFiles;
-    if (!this->MakeFilesFullPath("RESOURCE_FILES", relFiles, absFiles))
+    files = target.GetProperty("PUBLIC_HEADER");
+    if ((files) && (*files))
       {
-      return false;
-      }
+      std::vector<std::string> relFiles;
+      cmSystemTools::ExpandListArgument(files, relFiles);
+      std::vector<std::string> absFiles;
+      if (!this->MakeFilesFullPath("PUBLIC_HEADER", relFiles, absFiles))
+        {
+        return false;
+        }
 
-    // Create the files install generator.
-    if (!privateHeaderArgs.GetDestination().empty())
-      {
-      resourcesGenerator = CreateInstallFilesGenerator(absFiles, 
-                                                       resourcesArgs, false);
+      // Create the files install generator.
+      if (!publicHeaderArgs.GetDestination().empty())
+        {
+        publicHeaderGenerator = CreateInstallFilesGenerator(absFiles, 
+                                                      publicHeaderArgs, false);
+        }
+      else
+        {
+        cmOStringStream e;
+        e << "INSTALL TARGETS - target " << target.GetName() << " has "
+          << "PUBLIC_HEADER files but no PUBLIC_HEADER DESTINATION.";
+        cmSystemTools::Message(e.str().c_str(), "Warning");
+        }
       }
-    else
+
+    files = target.GetProperty("RESOURCE");
+    if ((files) && (*files))
       {
-      cmOStringStream e;
-      e << "TARGETS given no RESOURCES DESTINATION for resource files\"" 
-          << target.GetName() << "\".";
-      this->SetError(e.str().c_str());
-      return false;
+      std::vector<std::string> relFiles;
+      cmSystemTools::ExpandListArgument(files, relFiles);
+      std::vector<std::string> absFiles;
+      if (!this->MakeFilesFullPath("RESOURCE", relFiles, absFiles))
+        {
+        return false;
+        }
+
+      // Create the files install generator.
+      if (!resourceArgs.GetDestination().empty())
+        {
+        resourceGenerator = CreateInstallFilesGenerator(absFiles, 
+                                                        resourceArgs, false);
+        }
+      else
+        {
+        cmOStringStream e;
+        e << "INSTALL TARGETS - target " << target.GetName() << " has "
+          << "RESOURCE files but no RESOURCE DESTINATION.";
+        cmSystemTools::Message(e.str().c_str(), "Warning");
+        }
       }
     }
 
@@ -551,9 +565,9 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
     this->Makefile->AddInstallGenerator(runtimeGenerator);
     this->Makefile->AddInstallGenerator(frameworkGenerator);
     this->Makefile->AddInstallGenerator(bundleGenerator);
-    this->Makefile->AddInstallGenerator(publicHeaderGenerator);
     this->Makefile->AddInstallGenerator(privateHeaderGenerator);
-    this->Makefile->AddInstallGenerator(resourcesGenerator);
+    this->Makefile->AddInstallGenerator(publicHeaderGenerator);
+    this->Makefile->AddInstallGenerator(resourceGenerator);
 
     if (!exports.GetString().empty())
       {
@@ -577,11 +591,11 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args)
   this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
                       ->AddInstallComponent(bundleArgs.GetComponent().c_str());
   this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
-                   ->AddInstallComponent(resourcesArgs.GetComponent().c_str());
+               ->AddInstallComponent(privateHeaderArgs.GetComponent().c_str());
   this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
                 ->AddInstallComponent(publicHeaderArgs.GetComponent().c_str());
   this->Makefile->GetLocalGenerator()->GetGlobalGenerator()
-               ->AddInstallComponent(privateHeaderArgs.GetComponent().c_str());
+                    ->AddInstallComponent(resourceArgs.GetComponent().c_str());
 
   return true;
 }

+ 12 - 2
Source/cmInstallTargetGenerator.cxx

@@ -238,8 +238,18 @@ cmInstallTargetGenerator
       {
       // Compute the build tree location of the framework directory
       std::string from1 = fromDirConfig;
-      // Remove trailing slashes
-      cmSystemTools::ConvertToUnixSlashes(from1);
+      if(config && *config)
+        {
+        from1 += "/";
+        from1 += targetName;
+        from1 += ".framework";
+        }
+      else
+        {
+        // Remove trailing slashes... so that from1 ends with ".framework":
+        //
+        cmSystemTools::ConvertToUnixSlashes(from1);
+        }
       files.push_back(from1);
 
       type = cmTarget::INSTALL_DIRECTORY;

+ 19 - 19
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -252,16 +252,12 @@ void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs(
   symlink2 = "Resources";
   cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
   this->Makefile->AddCMakeOutputFile((outpath + "Resources").c_str());
-  // Libraries -> Versions/Current/Libraries
-  //symlink = "Versions/Current/Libraries";
-  //symlink2 = "Libraries";
-  //cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
-  //this->Makefile->AddCMakeOutputFile((outpath + "Libraries").c_str());
   // Headers -> Versions/Current/Headers
   symlink = "Versions/Current/Headers";
   symlink2 = "Headers";
   cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
   this->Makefile->AddCMakeOutputFile((outpath + "Headers").c_str());
+  // PrivateHeaders -> Versions/Current/PrivateHeaders
   symlink = "Versions/Current/PrivateHeaders";
   symlink2 = "PrivateHeaders";
   cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
@@ -278,12 +274,14 @@ void cmMakefileLibraryTargetGenerator::CopyFrameworkSources(
   const char* propertyName,
   const char* subdir)
 {
-  std::string fullOutput=  outpath + targetName;
+  std::string fullOutput = outpath + targetName;
   cmCustomCommandLines commandLines;
   std::vector<std::string> depends;
   const std::vector<cmSourceFile*>& sources =
     this->Target->GetSourceFiles();
 
+  std::string propName(propertyName);
+
   for(std::vector<cmSourceFile*>::const_iterator i = sources.begin();
       i != sources.end(); ++i)
     {
@@ -296,16 +294,20 @@ void cmMakefileLibraryTargetGenerator::CopyFrameworkSources(
       continue;
       }
 
+    cmTarget::SourceFileFlags tsFlags =
+      this->Target->GetTargetSourceFileFlags(sf);
+
     // If processing public headers, skip headers also marked with the private
     // property. Private wins.
     //
-    if((std::string(propertyName) == "FRAMEWORK_PUBLIC_HEADER") &&
-      sf->GetPropertyAsBool("FRAMEWORK_PRIVATE_HEADER"))
+    if(tsFlags.PrivateHeader && (propName == "PUBLIC_HEADER"))
       {
       continue;
       }
 
-    if(sf->GetPropertyAsBool(propertyName))
+    if(tsFlags.PrivateHeader && (propName == "PRIVATE_HEADER") ||
+      tsFlags.PublicHeader && (propName == "PUBLIC_HEADER") ||
+      tsFlags.Resource && (propName == "RESOURCE"))
       {
       cmCustomCommandLine line;
       std::string dest = outpath + subdir + "/";
@@ -318,8 +320,7 @@ void cmMakefileLibraryTargetGenerator::CopyFrameworkSources(
       line.push_back(dest);
       commandLines.push_back(line);
       // make sure the target gets rebuilt if any of the headers is removed
-      this->GenerateExtraOutput(dest.c_str(),
-                                fullOutput.c_str());
+      this->GenerateExtraOutput(dest.c_str(), fullOutput.c_str());
       }
     }
 
@@ -343,14 +344,13 @@ void cmMakefileLibraryTargetGenerator::CreateFramework(
 {
   std::string macdir = outpath;
   const char* version = this->Target->GetProperty("FRAMEWORK_VERSION");
+  if(!version)
+    {
+    version = this->Target->GetProperty("VERSION");
+    }
   if(!version)
     {
     version = "A";
-    //std::string message = 
-    //  "Warning: FRAMEWORK_VERSION property not found on ";
-    //message += targetName;
-    //message += ".  Default to version A.";
-    //cmSystemTools::Message(message.c_str());
     }
   // create the symbolic links and directories
   this->CreateFrameworkLinksAndDirs(targetName,
@@ -383,13 +383,13 @@ void cmMakefileLibraryTargetGenerator::CreateFramework(
                                 false, false, false);
 
   this->CopyFrameworkSources(targetName, outpath, version,
-    "FRAMEWORK_PRIVATE_HEADER", "PrivateHeaders");
+    "PRIVATE_HEADER", "PrivateHeaders");
 
   this->CopyFrameworkSources(targetName, outpath, version,
-    "FRAMEWORK_PUBLIC_HEADER", "Headers");
+    "PUBLIC_HEADER", "Headers");
 
   this->CopyFrameworkSources(targetName, outpath, version,
-    "FRAMEWORK_RESOURCE", "Resources");
+    "RESOURCE", "Resources");
 }
 
 //----------------------------------------------------------------------------

+ 1 - 1
Source/cmMakefileTargetGenerator.cxx

@@ -1170,7 +1170,7 @@ std::string cmMakefileTargetGenerator::GetFrameworkFlags()
   // will already have added a -F for the framework
   for(i = includes.begin(); i != includes.end(); ++i)
     {
-    if(cmSystemTools::IsPathToFramework(i->c_str()))
+    if(this->Target->NameResolvesToFramework(i->c_str()))
       {
       std::string frameworkDir = *i;
       frameworkDir += "/../";

+ 18 - 17
Source/cmOrderLinkDirectories.cxx

@@ -466,28 +466,29 @@ bool cmOrderLinkDirectories::DetermineLibraryPathOrder()
     // if it is a full path to an item then separate it from the path
     // this only works with files and paths
     cmStdString& item = this->RawLinkItems[i];
+
     if(cmSystemTools::FileIsFullPath(item.c_str()))
       {
-      if(cmSystemTools::FileIsDirectory(item.c_str()))
+      if(cmSystemTools::IsPathToFramework(item.c_str()))
         {
-        if(cmSystemTools::IsPathToFramework(item.c_str()))
+        this->SplitFramework.find(item.c_str());
+        cmStdString path = this->SplitFramework.match(1);
+        // Add the -F path if we have not yet done so
+        if(this->EmittedFrameworkPaths.insert(path).second)
           {
-          this->SplitFramework.find(item.c_str());
-          cmStdString path = this->SplitFramework.match(1);
-          // Add the -F path if we have not yet done so
-          if(this->EmittedFrameworkPaths.insert(path).second)
-            {
-            std::string fpath = "-F";
-            fpath += cmSystemTools::ConvertToOutputPath(path.c_str());
-            this->LinkItems.push_back(fpath);
-            }
-          // now add the -framework option
-          std::string frame = "-framework ";
-          frame += this->SplitFramework.match(2);
-          this->LinkItems.push_back(frame);
-          framework = true;
+          std::string fpath = "-F";
+          fpath += cmSystemTools::ConvertToOutputPath(path.c_str());
+          this->LinkItems.push_back(fpath);
           }
-        else
+        // now add the -framework option
+        std::string frame = "-framework ";
+        frame += this->SplitFramework.match(2);
+        this->LinkItems.push_back(frame);
+        framework = true;
+        }
+      if(cmSystemTools::FileIsDirectory(item.c_str()))
+        {
+        if(!framework)
           {
           // A full path to a directory was found as a link item
           // warn user 

+ 102 - 8
Source/cmTarget.cxx

@@ -687,6 +687,83 @@ cmSourceFile* cmTarget::AddSource(const char* s)
   return sf;
 }
 
+//----------------------------------------------------------------------------
+struct cmTarget::SourceFileFlags
+cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf)
+{
+  struct SourceFileFlags flags;
+  const char* files;
+  std::vector<std::string>::iterator it;
+
+  flags.PrivateHeader = false;
+  flags.PublicHeader = false;
+  flags.Resource = false;
+
+  files = this->GetProperty("PRIVATE_HEADER");
+  if ((files) && (*files))
+    {
+    std::vector<std::string> relFiles;
+    cmSystemTools::ExpandListArgument(files, relFiles);
+    for(it = relFiles.begin(); it != relFiles.end(); ++it)
+      {
+      if(sf == this->GetMakefile()->GetSource(it->c_str()))
+        {
+        flags.PrivateHeader = true;
+        break;
+        }
+      }
+    }
+
+  // Only consider marking it as a public header if it is *NOT* already marked
+  // as a private header:
+  //
+  if(!flags.PrivateHeader)
+    {
+    files = this->GetProperty("PUBLIC_HEADER");
+    if ((files) && (*files))
+      {
+      std::vector<std::string> relFiles;
+      cmSystemTools::ExpandListArgument(files, relFiles);
+      for(it = relFiles.begin(); it != relFiles.end(); ++it)
+        {
+        if(sf == this->GetMakefile()->GetSource(it->c_str()))
+          {
+          flags.PublicHeader = true;
+          break;
+          }
+        }
+      }
+    }
+
+  const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION");
+  if(location && cmStdString(location) == "Resources")
+    {
+    flags.Resource = true;
+    }
+
+  // Don't bother with the loop if it's already marked as a resource:
+  //
+  if(!flags.Resource)
+    {
+    files = this->GetProperty("RESOURCE");
+    if ((files) && (*files))
+      {
+      std::vector<std::string> relFiles;
+      cmSystemTools::ExpandListArgument(files, relFiles);
+      for(it = relFiles.begin(); it != relFiles.end(); ++it)
+        {
+        if(sf == this->GetMakefile()->GetSource(it->c_str()))
+          {
+          flags.Resource = true;
+          break;
+          }
+        }
+      }
+    }
+
+  return flags;
+}
+
 //----------------------------------------------------------------------------
 void cmTarget::MergeLinkLibraries( cmMakefile& mf,
                                    const char *selfname,
@@ -815,11 +892,18 @@ void cmTarget::AddLinkLibrary(const std::string& lib,
   this->LinkLibraries.push_back(tmp);
 }
 
+//----------------------------------------------------------------------------
+bool cmTarget::NameResolvesToFramework(const std::string& libname)
+{
+  return this->GetMakefile()->GetLocalGenerator()->GetGlobalGenerator()->
+    NameResolvesToFramework(libname);
+}
+
 //----------------------------------------------------------------------------
 bool cmTarget::AddFramework(const std::string& libname, LinkLibraryType llt)
 {
   (void)llt; // TODO: What is this?
-  if(cmSystemTools::IsPathToFramework(libname.c_str()))
+  if(this->NameResolvesToFramework(libname.c_str()))
     {
     std::string frameworkDir = libname;
     frameworkDir += "/../";
@@ -1239,7 +1323,8 @@ const char* cmTarget::NormalGetDirectory(const char* config, bool implib)
 {
   if(config && *config)
     {
-    this->Directory = this->GetOutputDir(implib);
+    // Do not create the directory when config is given:
+    this->Directory = this->GetAndCreateOutputDir(implib, false);
     // Add the configuration's subdirectory.
     this->Makefile->GetLocalGenerator()->GetGlobalGenerator()->
       AppendDirectoryForConfig("/", config, "", this->Directory);
@@ -2199,7 +2284,7 @@ std::string cmTarget::GetInstallNameDirForInstallTree(const char*)
 }
 
 //----------------------------------------------------------------------------
-const char* cmTarget::GetOutputDir(bool implib)
+const char* cmTarget::GetAndCreateOutputDir(bool implib, bool create)
 {
   // The implib option is only allowed for shared libraries, module
   // libraries, and executables.
@@ -2332,17 +2417,26 @@ const char* cmTarget::GetOutputDir(bool implib)
       }
 #endif
 
-    // Make sure the output path exists on disk.
-    if(!cmSystemTools::MakeDirectory(out.c_str()))
+    // Optionally make sure the output path exists on disk.
+    if(create)
       {
-      cmSystemTools::Error("Error failed to create output directory:",
-                           out.c_str());
+      if(!cmSystemTools::MakeDirectory(out.c_str()))
+        {
+        cmSystemTools::Error("Error failed to create output directory: ",
+                             out.c_str());
+        }
       }
-    }
+  }
 
   return out.c_str();
 }
 
+//----------------------------------------------------------------------------
+const char* cmTarget::GetOutputDir(bool implib)
+{
+  return this->GetAndCreateOutputDir(implib, true);
+}
+
 //----------------------------------------------------------------------------
 const char* cmTarget::GetExportMacro()
 {

+ 21 - 0
Source/cmTarget.h

@@ -83,6 +83,23 @@ public:
     {return this->SourceFiles;}
   void AddSourceFile(cmSourceFile* sf) { this->SourceFiles.push_back(sf); }
 
+  /**
+   * Flags for a given source file as used in this target. Typically assigned
+   * via SET_TARGET_PROPERTIES when the property is a list of source files.
+   */
+  struct SourceFileFlags
+  {
+    bool PrivateHeader; // source is in "PRIVATE_HEADER" target property
+    bool PublicHeader;  // source is in "PUBLIC_HEADER" target property
+    bool Resource;      // source is in "RESOURCE" target property *or*
+                        // source has MACOSX_PACKAGE_LOCATION=="Resources"
+  };
+
+  /**
+   * Get the flags for a given source file as used in this target
+   */
+  struct SourceFileFlags GetTargetSourceFileFlags(const cmSourceFile* sf);
+
   /**
    * Add sources to the target.
    */
@@ -109,6 +126,7 @@ public:
   void ClearDependencyInformation(cmMakefile& mf, const char* target);
 
   // Check to see if a library is a framework and treat it different on Mac
+  bool NameResolvesToFramework(const std::string& libname);
   bool AddFramework(const std::string& lib, LinkLibraryType llt);
   void AddLinkLibrary(cmMakefile& mf,
                       const char *target, const char* lib,
@@ -359,6 +377,9 @@ private:
   // If the variable is not defined use the given default instead.
   void SetPropertyDefault(const char* property, const char* default_value);
 
+  // Get the full path to the target output directory.
+  const char* GetAndCreateOutputDir(bool implib, bool create);
+
   // Get the full path to the target output directory.
   const char* GetOutputDir(bool implib);
 

+ 13 - 2
Tests/CMakeLists.txt

@@ -45,7 +45,6 @@ IF(BUILD_TESTING)
   ADD_TEST_MACRO(LoadCommand LoadedCommand)
   ADD_TEST_MACRO(LinkLine LinkLine)
   ADD_TEST_MACRO(MacroTest miniMacroTest)
-  ADD_TEST_MACRO(Framework bar)
   ADD_TEST_MACRO(Properties Properties)
   ADD_TEST_MACRO(Assembler HelloAsm)
   ADD_TEST_MACRO(SourceGroups SourceGroups)
@@ -64,8 +63,20 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=CVS -P ${CMake_SOURCE_DIR}/Utilities/Rel
     ENDIF(COMMAND SET_TESTS_PROPERTIES AND COMMAND GET_TEST_PROPERTY)
   ENDIF(CMAKE_BUILD_NIGHTLY_WINDOWS_TEST)
 
-  
+
   # add tests with more complex invocations
+  ADD_TEST(Framework ${CMAKE_CTEST_COMMAND}
+    --build-and-test
+    "${CMake_SOURCE_DIR}/Tests/Framework"
+    "${CMake_BINARY_DIR}/Tests/Framework"
+    --build-two-config
+    --build-generator ${CMAKE_TEST_GENERATOR}
+    --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
+    --build-project Framework
+    --build-options
+    "-DCMAKE_INSTALL_PREFIX:PATH=${CMake_BINARY_DIR}/Tests/Framework/Install"
+    --test-command bar)
+
   ADD_TEST(TargetName ${CMAKE_CTEST_COMMAND}
     --build-and-test
     "${CMake_SOURCE_DIR}/Tests/TargetName"

+ 24 - 14
Tests/Framework/CMakeLists.txt

@@ -10,26 +10,34 @@ add_library(foo SHARED
   fooBoth.h
   test.lua
 )
+
+set(foo_ver ver4)
+
 set_target_properties(foo PROPERTIES
   FRAMEWORK TRUE
-  FRAMEWORK_VERSION ver3
-)
-# fooNeither.h is marked neither public nor private...
-# fooBoth.h is marked both public and private... (private wins...)
-set_source_files_properties(foo.h foo2.h fooPublic.h fooBoth.h PROPERTIES
-  FRAMEWORK_PUBLIC_HEADER TRUE
-)
-set_source_files_properties(fooPrivate.h fooBoth.h PROPERTIES
-  FRAMEWORK_PRIVATE_HEADER TRUE
-)
-set_source_files_properties(test.lua PROPERTIES
-  FRAMEWORK_RESOURCE TRUE
+  FRAMEWORK_VERSION ${foo_ver}
+  PRIVATE_HEADER "fooPrivate.h;fooBoth.h"
+  PUBLIC_HEADER "foo.h;foo2.h;fooPublic.h;fooBoth.h"
+  RESOURCE "test.lua"
 )
+# fooBoth.h is listed as both public and private... (private wins...)
+# fooNeither.h is listed as neither public nor private...
+
 add_executable(bar bar.cxx)
 target_link_libraries(bar foo)
 install(TARGETS foo bar
-  RUNTIME DESTINATION /Applications/CMakeTestsFramework/bin
-  FRAMEWORK DESTINATION /Library/Frameworks
+  RUNTIME DESTINATION Applications/CMakeTestsFramework/bin
+  FRAMEWORK DESTINATION Library/Frameworks
+
+  # These are ignored on the Mac... and things are automatically placed in
+  # their appropriate Framework sub-folder at build time. (And then the built
+  # framework is copied recursively when it is installed.)
+  PRIVATE_HEADER DESTINATION share/foo-${foo_ver}/PrivateHeaders
+  PUBLIC_HEADER DESTINATION include/foo-${foo_ver}
+  RESOURCE DESTINATION share/foo-${foo_ver}/Resources
+  # But they are required to be present so that installing a framework on other
+  # other platforms will install the pieces of the framework without having to
+  # duplicate install rules for the pieces of the framework.
 )
 
 # Make a static library and apply the framework properties to it to verify
@@ -53,3 +61,5 @@ set_target_properties(fooStatic PROPERTIES
 )
 add_executable(barStatic bar.cxx)
 target_link_libraries(barStatic fooStatic)
+
+include(CPack)