Forráskód Böngészése

ENH: Cleanup impl of PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE properties

Brad King 17 éve
szülő
commit
9ed4266306

+ 8 - 8
Source/cmGlobalXCodeGenerator.cxx

@@ -493,21 +493,21 @@ cmGlobalXCodeGenerator::CreateXCodeSourceFile(cmLocalGenerator* lg,
   // Is this a resource file in this target? Add it to the resources group...
   //
   cmTarget::SourceFileFlags tsFlags = cmtarget.GetTargetSourceFileFlags(sf);
-  bool isResource = tsFlags.Resource;
+  bool isResource = (tsFlags.Type == cmTarget::SourceFileTypeResource);
 
   // Is this a "private" or "public" framework header file?
   // Set the ATTRIBUTES attribute appropriately...
   //
   if(cmtarget.IsFrameworkOnApple())
     {
-    if(tsFlags.PrivateHeader)
+    if(tsFlags.Type == cmTarget::SourceFileTypePrivateHeader)
       {
       cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
       attrs->AddObject(this->CreateString("Private"));
       settings->AddAttribute("ATTRIBUTES", attrs);
       isResource = true;
       }
-    else if(tsFlags.PublicHeader)
+    else if(tsFlags.Type == cmTarget::SourceFileTypePublicHeader)
       {
       cmXCodeObject* attrs = this->CreateObject(cmXCodeObject::OBJECT_LIST);
       attrs->AddObject(this->CreateString("Public"));
@@ -698,7 +698,7 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
         {
         headerFiles.push_back(xsf);
         }
-      else if(tsFlags.Resource)
+      else if(tsFlags.Type == cmTarget::SourceFileTypeResource)
         {
         resourceFiles.push_back(xsf);
         }
@@ -785,12 +785,12 @@ cmGlobalXCodeGenerator::CreateXCodeTargets(cmLocalGenerator* gen,
       for(std::vector<cmSourceFile*>::const_iterator i = classes.begin();
           i != classes.end(); ++i)
         {
-        const char* contentLoc = (*i)->GetProperty("MACOSX_PACKAGE_LOCATION");
-        if ( !contentLoc || cmStdString(contentLoc) == "Resources" )
+        cmTarget::SourceFileFlags tsFlags =
+          cmtarget.GetTargetSourceFileFlags(*i);
+        if(tsFlags.Type == cmTarget::SourceFileTypeMacContent)
           {
-          continue;
+          bundleFiles[tsFlags.MacFolder].push_back(*i);
           }
-        bundleFiles[contentLoc].push_back(*i);
         }
       mapOfVectorOfSourceFiles::iterator mit;
       for ( mit = bundleFiles.begin(); mit != bundleFiles.end(); ++ mit )

+ 3 - 3
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -128,8 +128,8 @@ void cmLocalUnixMakefileGenerator3::Generate()
   std::string empty;
   for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t)
     {
-    cmMakefileTargetGenerator *tg = 
-      cmMakefileTargetGenerator::New(this, t->first, &(t->second));
+    cmMakefileTargetGenerator *tg =
+      cmMakefileTargetGenerator::New(&(t->second));
     if (tg)
       {
       this->TargetGenerators.push_back(tg);
@@ -168,7 +168,7 @@ unsigned long cmLocalUnixMakefileGenerator3
          this->TargetGenerators.begin();
        mtgIter != this->TargetGenerators.end(); ++mtgIter)
     {
-    if (!strcmp(name,(*mtgIter)->GetTargetName()))
+    if (!strcmp(name,(*mtgIter)->GetTarget()->GetName()))
       {
       return (*mtgIter)->GetNumberOfProgressActions();
       }

+ 34 - 16
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -25,9 +25,22 @@
 #include "cmake.h"
 
 //----------------------------------------------------------------------------
-cmMakefileExecutableTargetGenerator::cmMakefileExecutableTargetGenerator()
+cmMakefileExecutableTargetGenerator
+::cmMakefileExecutableTargetGenerator(cmTarget* target):
+  cmMakefileTargetGenerator(target)
 {
   this->CustomCommandDriver = OnDepends;
+  this->Target->GetExecutableNames(
+    this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
+    this->TargetNamePDB, this->LocalGenerator->ConfigurationName.c_str());
+
+  if(this->Target->IsAppBundleOnApple())
+    {
+    this->MacContentDirectory = this->Target->GetDirectory();
+    this->MacContentDirectory += "/";
+    this->MacContentDirectory += this->TargetNameOut;
+    this->MacContentDirectory += ".app/Contents/";
+    }
 }
 
 //----------------------------------------------------------------------------
@@ -117,21 +130,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   outpath += "/";
   if(this->Target->IsAppBundleOnApple())
     {
-    // Compute bundle directory names.
-    std::string macdir = outpath;
-    macdir += targetName;
-    macdir += ".app/Contents/";
-    outpath = macdir;
-    outpath += "MacOS";
-    cmSystemTools::MakeDirectory(outpath.c_str());
-    outpath += "/";
-
-    // Configure the Info.plist file.  Note that it needs the executable name
-    // to be set.
-    std::string plist = macdir + "Info.plist";
-    this->LocalGenerator->GenerateAppleInfoPList(this->Target,
-                                                 targetName.c_str(),
-                                                 plist.c_str());
+    this->CreateAppBundle(targetName, outpath);
     }
   std::string outpathImp;
   if(relink)
@@ -469,3 +468,22 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
                           exeCleanFiles.begin(),
                           exeCleanFiles.end());
 }
+
+//----------------------------------------------------------------------------
+void
+cmMakefileExecutableTargetGenerator::CreateAppBundle(std::string& targetName,
+                                                     std::string& outpath)
+{
+  // Compute bundle directory names.
+  outpath = this->MacContentDirectory;
+  outpath += "MacOS";
+  cmSystemTools::MakeDirectory(outpath.c_str());
+  outpath += "/";
+
+  // Configure the Info.plist file.  Note that it needs the executable name
+  // to be set.
+  std::string plist = this->MacContentDirectory + "Info.plist";
+  this->LocalGenerator->GenerateAppleInfoPList(this->Target,
+                                               targetName.c_str(),
+                                               plist.c_str());
+}

+ 2 - 2
Source/cmMakefileExecutableTargetGenerator.h

@@ -22,7 +22,7 @@
 class cmMakefileExecutableTargetGenerator: public cmMakefileTargetGenerator
 {
 public:
-  cmMakefileExecutableTargetGenerator();
+  cmMakefileExecutableTargetGenerator(cmTarget* target);
 
   /* the main entry point for this class. Writes the Makefiles associated
      with this target */
@@ -30,7 +30,7 @@ public:
   
 protected:
   virtual void WriteExecutableRule(bool relink);
-  
+  void CreateAppBundle(std::string& targetName, std::string& outpath);
 };
 
 #endif

+ 30 - 115
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -27,9 +27,35 @@
 #include <memory> // auto_ptr
 
 //----------------------------------------------------------------------------
-cmMakefileLibraryTargetGenerator::cmMakefileLibraryTargetGenerator()
+cmMakefileLibraryTargetGenerator
+::cmMakefileLibraryTargetGenerator(cmTarget* target):
+  cmMakefileTargetGenerator(target)
 {
   this->CustomCommandDriver = OnDepends;
+  this->Target->GetLibraryNames(
+    this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
+    this->TargetNameImport, this->TargetNamePDB,
+    this->LocalGenerator->ConfigurationName.c_str());
+
+  if(this->Target->IsFrameworkOnApple())
+    {
+    if(const char* fversion = this->Target->GetProperty("FRAMEWORK_VERSION"))
+      {
+      this->FrameworkVersion = fversion;
+      }
+    else if(const char* tversion = this->Target->GetProperty("VERSION"))
+      {
+      this->FrameworkVersion = tversion;
+      }
+    else
+      {
+      this->FrameworkVersion = "A";
+      }
+    this->MacContentDirectory = this->Target->GetDirectory();
+    this->MacContentDirectory += "/Versions/";
+    this->MacContentDirectory += this->FrameworkVersion;
+    this->MacContentDirectory += "/";
+    }
 }
 
 //----------------------------------------------------------------------------
@@ -218,10 +244,9 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
 }
 
 //----------------------------------------------------------------------------
-void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs(
+void cmMakefileLibraryTargetGenerator::CreateFramework(
   std::string& targetName,
-  std::string& outpath,
-  const char* version)
+  std::string& outpath)
 {
   std::string symlink;
   std::string symlink2;
@@ -233,7 +258,7 @@ void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs(
   // cd foo.framework to setup symlinks with relative paths
   cmSystemTools::ChangeDirectory((outpath+"Versions").c_str());
   // Current -> version
-  symlink = version;
+  symlink = this->FrameworkVersion;
   symlink2 = "Current";
   cmSystemTools::RemoveFile("Current");
   cmSystemTools::CreateSymlink(symlink.c_str(), symlink2.c_str());
@@ -265,116 +290,6 @@ void cmMakefileLibraryTargetGenerator::CreateFrameworkLinksAndDirs(
   cmSystemTools::ChangeDirectory(cwd.c_str());
 }
 
-//----------------------------------------------------------------------------
-void cmMakefileLibraryTargetGenerator::CopyFrameworkSources(
-  std::string& targetName,
-  std::string& outpath,
-  const char* /*version*/ ,
-  const char* propertyName,
-  const char* subdir)
-{
-  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)
-    {
-    cmSourceFile* sf = *i;
-
-    if(!sf)
-      {
-      cmSystemTools::Error(
-        "could not find framework source file", "");
-      continue;
-      }
-
-    cmTarget::SourceFileFlags tsFlags =
-      this->Target->GetTargetSourceFileFlags(sf);
-
-    // If processing public headers, skip headers also marked with the private
-    // property. Private wins.
-    //
-    if(tsFlags.PrivateHeader && (propName == "PUBLIC_HEADER"))
-      {
-      continue;
-      }
-
-    if(tsFlags.PrivateHeader && (propName == "PRIVATE_HEADER") ||
-      tsFlags.PublicHeader && (propName == "PUBLIC_HEADER") ||
-      tsFlags.Resource && (propName == "RESOURCE"))
-      {
-      cmCustomCommandLine line;
-      std::string dest = outpath + subdir + "/";
-      dest += cmSystemTools::GetFilenameName(sf->GetFullPath());
-      line.push_back("$(CMAKE_COMMAND)");
-      line.push_back("-E");
-      line.push_back("copy_if_different");
-      line.push_back(sf->GetFullPath());
-      depends.push_back(sf->GetFullPath());
-      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());
-      }
-    }
-
-  // add a set of prebuild commands to run on the target
-  if(!commandLines.empty())
-    {
-    this->Makefile->
-      AddCustomCommandToTarget(this->Target->GetName(),
-                               depends,
-                               commandLines,
-                               cmTarget::PRE_BUILD,
-                               "copy files",
-                               this->Makefile->GetCurrentOutputDirectory());
-    }
-}
-
-//----------------------------------------------------------------------------
-void cmMakefileLibraryTargetGenerator::CreateFramework(
-  std::string& targetName,
-  std::string& outpath)
-{
-  std::string macdir = outpath;
-  const char* version = this->Target->GetProperty("FRAMEWORK_VERSION");
-  if(!version)
-    {
-    version = this->Target->GetProperty("VERSION");
-    }
-  if(!version)
-    {
-    version = "A";
-    }
-  // create the symbolic links and directories
-  this->CreateFrameworkLinksAndDirs(targetName,
-                                          outpath,
-                                          version);
-  macdir += "Versions/";
-  macdir += version;
-  macdir += "/";
-  outpath += "Versions/";
-  outpath += version;
-  outpath += "/";
-
-  //cmSystemTools::MakeDirectory((macdir + "Libraries").c_str());
-  cmSystemTools::MakeDirectory((macdir + "Headers").c_str());
-
-  this->CopyFrameworkSources(targetName, outpath, version,
-    "PRIVATE_HEADER", "PrivateHeaders");
-
-  this->CopyFrameworkSources(targetName, outpath, version,
-    "PUBLIC_HEADER", "Headers");
-
-  this->CopyFrameworkSources(targetName, outpath, version,
-    "RESOURCE", "Resources");
-}
-
 //----------------------------------------------------------------------------
 void cmMakefileLibraryTargetGenerator::WriteLibraryRules
 (const char* linkRuleVar, const char* extraFlags, bool relink)

+ 4 - 9
Source/cmMakefileLibraryTargetGenerator.h

@@ -23,7 +23,7 @@ class cmMakefileLibraryTargetGenerator:
   public cmMakefileTargetGenerator
 {
 public:
-  cmMakefileLibraryTargetGenerator();
+  cmMakefileLibraryTargetGenerator(cmTarget* target);
 
   /* the main entry point for this class. Writes the Makefiles associated
      with this target */
@@ -39,14 +39,9 @@ protected:
   void WriteFrameworkRules(bool relink);
   void CreateFramework(std::string& targetName,
                        std::string& outpath);
-  void CreateFrameworkLinksAndDirs(std::string& targetName,
-                                   std::string& outpath,
-                                   const char* version);
-  void CopyFrameworkSources(std::string& targetName,
-                            std::string& outpath,
-                            const char* version,
-                            const char* propertyName,
-                            const char* subdir);
+
+  // Store the computd framework version for OS X Frameworks.
+  std::string FrameworkVersion;
 };
 
 #endif

+ 26 - 32
Source/cmMakefileTargetGenerator.cxx

@@ -30,45 +30,45 @@
 #include "cmMakefileUtilityTargetGenerator.h"
 
 
-cmMakefileTargetGenerator::cmMakefileTargetGenerator()
+cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmTarget* target)
 {
   this->BuildFileStream = 0;
   this->InfoFileStream = 0;
   this->FlagFileStream = 0;
   this->CustomCommandDriver = OnBuild;
   this->FortranModuleDirectoryComputed = false;
+  this->Target = target;
+  this->Makefile = this->Target->GetMakefile();
+  this->LocalGenerator =
+    static_cast<cmLocalUnixMakefileGenerator3*>(
+      this->Makefile->GetLocalGenerator());
+  this->GlobalGenerator =
+    static_cast<cmGlobalUnixMakefileGenerator3*>(
+      this->LocalGenerator->GetGlobalGenerator());
 }
 
 cmMakefileTargetGenerator *
-cmMakefileTargetGenerator::New(cmLocalUnixMakefileGenerator3 *lg,
-                               cmStdString tgtName, cmTarget *tgt)
+cmMakefileTargetGenerator::New(cmTarget *tgt)
 {
   cmMakefileTargetGenerator *result = 0;
 
   switch (tgt->GetType())
     {
     case cmTarget::EXECUTABLE:
-      result = new cmMakefileExecutableTargetGenerator;
+      result = new cmMakefileExecutableTargetGenerator(tgt);
       break;
     case cmTarget::STATIC_LIBRARY:
     case cmTarget::SHARED_LIBRARY:
     case cmTarget::MODULE_LIBRARY:
-      result = new cmMakefileLibraryTargetGenerator;
+      result = new cmMakefileLibraryTargetGenerator(tgt);
       break;
     case cmTarget::UTILITY:
-      result = new cmMakefileUtilityTargetGenerator;
+      result = new cmMakefileUtilityTargetGenerator(tgt);
       break;
     default:
       return result;
       // break; /* unreachable */
     }
-
-  result->TargetName = tgtName;
-  result->Target = tgt;
-  result->LocalGenerator = lg;
-  result->GlobalGenerator =
-    static_cast<cmGlobalUnixMakefileGenerator3*>(lg->GetGlobalGenerator());
-  result->Makefile = lg->GetMakefile();
   return result;
 }
 
@@ -134,6 +134,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
   for(std::vector<cmSourceFile*>::const_iterator source = sources.begin();
       source != sources.end(); ++source)
     {
+    cmTarget::SourceFileFlags tsFlags =
+      this->Target->GetTargetSourceFileFlags(*source);
     if(cmCustomCommand* cc = (*source)->GetCustomCommand())
       {
       this->GenerateCustomRuleFile(*cc);
@@ -150,10 +152,9 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
           }
         }
       }
-    else if(const char* pkgloc =
-            (*source)->GetProperty("MACOSX_PACKAGE_LOCATION"))
+    else if(tsFlags.Type != cmTarget::SourceFileTypeNormal)
       {
-      this->WriteMacOSXContentRules(*(*source), pkgloc);
+      this->WriteMacOSXContentRules(*(*source), tsFlags.MacFolder);
       }
     else if(!(*source)->GetPropertyAsBool("HEADER_FILE_ONLY"))
       {
@@ -322,21 +323,14 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
 void cmMakefileTargetGenerator::WriteMacOSXContentRules(cmSourceFile& source,
                                                         const char* pkgloc)
 {
-  // Skip OS X bundle content when not building a bundle.
-  if(!this->Target->IsAppBundleOnApple()) { return; }
-
-  // Create the directory in which the content is to be placed.
-  std::string targetName;
-  std::string targetNameReal;
-  std::string targetNameImport;
-  std::string targetNamePDB;
-  this->Target->GetExecutableNames
-    (targetName, targetNameReal, targetNameImport, targetNamePDB,
-     this->LocalGenerator->ConfigurationName.c_str());
-  std::string macdir = this->Target->GetDirectory();
-  macdir += "/";
-  macdir += targetName;
-  macdir += ".app/Contents/";
+  // Skip OS X content when not building a Framework or Bundle.
+  if(this->MacContentDirectory.empty())
+    {
+    return;
+    }
+
+  // Construct the full path to the content subdirectory.
+  std::string macdir = this->MacContentDirectory;
   macdir += pkgloc;
   cmSystemTools::MakeDirectory(macdir.c_str());
 
@@ -355,7 +349,7 @@ void cmMakefileTargetGenerator::WriteMacOSXContentRules(cmSourceFile& source,
   std::vector<std::string> depends;
   std::vector<std::string> commands;
   depends.push_back(input);
-  std::string copyEcho = "Copying Bundle content ";
+  std::string copyEcho = "Copying OS X content ";
   copyEcho += output;
   this->LocalGenerator->AppendEcho(commands, copyEcho.c_str(),
                                    cmLocalUnixMakefileGenerator3::EchoBuild);

+ 12 - 6
Source/cmMakefileTargetGenerator.h

@@ -37,13 +37,11 @@ class cmMakefileTargetGenerator
 {
 public:
   // constructor to set the ivars
-  cmMakefileTargetGenerator();
+  cmMakefileTargetGenerator(cmTarget* target);
   virtual ~cmMakefileTargetGenerator() {};
 
   // construct using this factory call
-  static cmMakefileTargetGenerator *New(cmLocalUnixMakefileGenerator3 *lg,
-                                        cmStdString tgtName,
-                                        cmTarget *tgt);
+  static cmMakefileTargetGenerator *New(cmTarget *tgt);
 
   /* the main entry point for this class. Writes the Makefiles associated
      with this target */
@@ -58,7 +56,6 @@ public:
   virtual unsigned long GetNumberOfProgressActions() {
     return this->NumberOfProgressActions;}
 
-  const char *GetTargetName() { return this->TargetName.c_str(); }
   cmTarget* GetTarget() { return this->Target;}
 protected:
 
@@ -142,7 +139,6 @@ protected:
   virtual void CloseFileStreams();
   void RemoveForbiddenFlags(const char* flagVar, const char* linkLang,
                             std::string& linkFlags);
-  cmStdString TargetName;
   cmTarget *Target;
   cmLocalUnixMakefileGenerator3 *LocalGenerator;
   cmGlobalUnixMakefileGenerator3 *GlobalGenerator;
@@ -191,6 +187,16 @@ protected:
   typedef std::map<cmStdString, cmStdString> MultipleOutputPairsType;
   MultipleOutputPairsType MultipleOutputPairs;
 
+  // Target name info.
+  std::string TargetNameOut;
+  std::string TargetNameSO;
+  std::string TargetNameReal;
+  std::string TargetNameImport;
+  std::string TargetNamePDB;
+
+  // Mac OS X content info.
+  std::string MacContentDirectory;
+
   // Target-wide Fortran module output directory.
   bool FortranModuleDirectoryComputed;
   std::string FortranModuleDirectory;

+ 3 - 1
Source/cmMakefileUtilityTargetGenerator.cxx

@@ -24,7 +24,9 @@
 #include "cmTarget.h"
 
 //----------------------------------------------------------------------------
-cmMakefileUtilityTargetGenerator::cmMakefileUtilityTargetGenerator()
+cmMakefileUtilityTargetGenerator
+::cmMakefileUtilityTargetGenerator(cmTarget* target):
+  cmMakefileTargetGenerator(target)
 {
   this->CustomCommandDriver = OnUtility;
 }

+ 1 - 1
Source/cmMakefileUtilityTargetGenerator.h

@@ -23,7 +23,7 @@ class cmMakefileUtilityTargetGenerator:
   public cmMakefileTargetGenerator
 {
 public:
-  cmMakefileUtilityTargetGenerator();
+  cmMakefileUtilityTargetGenerator(cmTarget* target);
 
   /* the main entry point for this class. Writes the Makefiles associated
      with this target */

+ 12 - 7
Source/cmSourceFile.cxx

@@ -460,15 +460,20 @@ void cmSourceFile::DefineProperties(cmake *cm)
 
   cm->DefineProperty
     ("MACOSX_PACKAGE_LOCATION", cmProperty::SOURCE_FILE, 
-     "Place a source file inside a Mac OS X application bundle.",
+     "Place a source file inside a Mac OS X bundle or framework.",
      "Executable targets with the MACOSX_BUNDLE property set are built "
      "as Mac OS X application bundles on Apple platforms.  "
-     "Source files specified for the target with the "
-     "MACOSX_PACKAGE_LOCATION property set will be placed in the "
-     "application bundle Contents folder under the directory specified "
-     "by the value of the property.  "
-     "Typically this is set to \"Resources\" for icon files and other "
-     "bundle resources.");
+     "Shared library targets with the FRAMEWORK property set are built "
+     "as Mac OS X frameworks on Apple platforms.  "
+     "Source files listed in the target with this property set will "
+     "be copied to a directory inside the bundle or framework content "
+     "folder specified by the property value.  "
+     "For bundles the content folder is \"<name>.app/Contents\".  "
+     "For frameworks the content folder is "
+     "\"<name>.framework/Versions/<version>\".  "
+     "See the PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE target "
+     "properties for specifying files meant for Headers, PrivateHeadres, "
+     "or Resources directories.");
 
   cm->DefineProperty
     ("OBJECT_DEPENDS", cmProperty::SOURCE_FILE, 

+ 116 - 41
Source/cmTarget.cxx

@@ -32,6 +32,19 @@ const char* cmTarget::TargetTypeNames[] = {
   "INSTALL_FILES", "INSTALL_PROGRAMS", "INSTALL_DIRECTORY"
 };
 
+//----------------------------------------------------------------------------
+class cmTargetInternals
+{
+public:
+  cmTargetInternals()
+    {
+    this->SourceFileFlagsConstructed = false;
+    }
+  typedef cmTarget::SourceFileFlags SourceFileFlags;
+  std::map<cmSourceFile const*, SourceFileFlags> SourceFlagsMap;
+  bool SourceFileFlagsConstructed;
+};
+
 //----------------------------------------------------------------------------
 cmTarget::cmTarget()
 {
@@ -994,76 +1007,101 @@ struct cmTarget::SourceFileFlags
 cmTarget::GetTargetSourceFileFlags(const cmSourceFile* sf)
 {
   struct SourceFileFlags flags;
-  const char* files;
-  std::vector<std::string>::iterator it;
+  this->ConstructSourceFileFlags();
+  std::map<cmSourceFile const*, SourceFileFlags>::iterator si =
+    this->Internal->SourceFlagsMap.find(sf);
+  if(si != this->Internal->SourceFlagsMap.end())
+    {
+    flags = si->second;
+    }
+  return flags;
+}
 
-  flags.PrivateHeader = false;
-  flags.PublicHeader = false;
-  flags.Resource = false;
+//----------------------------------------------------------------------------
+void cmTarget::ConstructSourceFileFlags()
+{
+  if(this->Internal->SourceFileFlagsConstructed)
+    {
+    return;
+    }
+  this->Internal->SourceFileFlagsConstructed = true;
 
-  files = this->GetProperty("PRIVATE_HEADER");
-  if ((files) && (*files))
+  // Process public headers to mark the source files.
+  if(const char* files = this->GetProperty("PUBLIC_HEADER"))
     {
     std::vector<std::string> relFiles;
     cmSystemTools::ExpandListArgument(files, relFiles);
-    for(it = relFiles.begin(); it != relFiles.end(); ++it)
+    for(std::vector<std::string>::iterator it = relFiles.begin();
+        it != relFiles.end(); ++it)
       {
-      if(sf == this->GetMakefile()->GetSource(it->c_str()))
+      if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str()))
         {
-        flags.PrivateHeader = true;
-        break;
+        SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf];
+        flags.MacFolder = "Headers";
+        flags.Type = cmTarget::SourceFileTypePublicHeader;
         }
       }
     }
 
-  // Only consider marking it as a public header if it is *NOT* already marked
-  // as a private header:
-  //
-  if(!flags.PrivateHeader)
+  // Process private headers after public headers so that they take
+  // precedence if a file is listed in both.
+  if(const char* files = this->GetProperty("PRIVATE_HEADER"))
     {
-    files = this->GetProperty("PUBLIC_HEADER");
-    if ((files) && (*files))
+    std::vector<std::string> relFiles;
+    cmSystemTools::ExpandListArgument(files, relFiles);
+    for(std::vector<std::string>::iterator it = relFiles.begin();
+        it != relFiles.end(); ++it)
       {
-      std::vector<std::string> relFiles;
-      cmSystemTools::ExpandListArgument(files, relFiles);
-      for(it = relFiles.begin(); it != relFiles.end(); ++it)
+      if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str()))
         {
-        if(sf == this->GetMakefile()->GetSource(it->c_str()))
-          {
-          flags.PublicHeader = true;
-          break;
-          }
+        SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf];
+        flags.MacFolder = "PrivateHeaders";
+        flags.Type = cmTarget::SourceFileTypePrivateHeader;
         }
       }
     }
 
-  const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION");
-  if(location && cmStdString(location) == "Resources")
+  // Mark sources listed as resources.
+  if(const char* files = this->GetProperty("RESOURCE"))
     {
-    flags.Resource = true;
+    std::vector<std::string> relFiles;
+    cmSystemTools::ExpandListArgument(files, relFiles);
+    for(std::vector<std::string>::iterator it = relFiles.begin();
+        it != relFiles.end(); ++it)
+      {
+      if(cmSourceFile* sf = this->Makefile->GetSource(it->c_str()))
+        {
+        SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf];
+        flags.MacFolder = "Resources";
+        flags.Type = cmTarget::SourceFileTypeResource;
+        }
+      }
     }
 
-  // Don't bother with the loop if it's already marked as a resource:
-  //
-  if(!flags.Resource)
+  // Handle the MACOSX_PACKAGE_LOCATION property on source files that
+  // were not listed in one of the other lists.
+  std::vector<cmSourceFile*> const& sources = this->GetSourceFiles();
+  for(std::vector<cmSourceFile*>::const_iterator si = sources.begin();
+      si != sources.end(); ++si)
     {
-    files = this->GetProperty("RESOURCE");
-    if ((files) && (*files))
+    cmSourceFile* sf = *si;
+    if(const char* location = sf->GetProperty("MACOSX_PACKAGE_LOCATION"))
       {
-      std::vector<std::string> relFiles;
-      cmSystemTools::ExpandListArgument(files, relFiles);
-      for(it = relFiles.begin(); it != relFiles.end(); ++it)
+      SourceFileFlags& flags = this->Internal->SourceFlagsMap[sf];
+      if(flags.Type == cmTarget::SourceFileTypeNormal)
         {
-        if(sf == this->GetMakefile()->GetSource(it->c_str()))
+        flags.MacFolder = location;
+        if(strcmp(location, "Resources") == 0)
           {
-          flags.Resource = true;
-          break;
+          flags.Type = cmTarget::SourceFileTypeResource;
+          }
+        else
+          {
+          flags.Type = cmTarget::SourceFileTypeMacContent;
           }
         }
       }
     }
-
-  return flags;
 }
 
 //----------------------------------------------------------------------------
@@ -2872,6 +2910,10 @@ const char* cmTarget::GetAndCreateOutputDir(bool implib, bool create)
       cmSystemTools::CollapseFullPath
       (out.c_str(), this->Makefile->GetStartOutputDirectory());
 
+    // TODO: Make AppBundle and Framework directory computation in
+    // target consistent.  Why do we add the .framework part here for
+    // frameworks but not the .app part for bundles?  We should
+    // probably not add it for either.
     if(this->IsFrameworkOnApple())
       {
       out += "/";
@@ -3392,3 +3434,36 @@ cmTargetLinkInterfaceMap::~cmTargetLinkInterfaceMap()
     delete i->second;
     }
 }
+
+//----------------------------------------------------------------------------
+cmTargetInternalPointer::cmTargetInternalPointer()
+{
+  this->Pointer = new cmTargetInternals;
+}
+
+//----------------------------------------------------------------------------
+cmTargetInternalPointer
+::cmTargetInternalPointer(cmTargetInternalPointer const&)
+{
+  // Ideally cmTarget instances should never be copied.  However until
+  // we can make a sweep to remove that, this copy constructor avoids
+  // allowing the resources (Internals) to be copied.
+  this->Pointer = new cmTargetInternals;
+}
+
+//----------------------------------------------------------------------------
+cmTargetInternalPointer::~cmTargetInternalPointer()
+{
+  delete this->Pointer;
+}
+
+//----------------------------------------------------------------------------
+cmTargetInternalPointer&
+cmTargetInternalPointer::operator=(cmTargetInternalPointer const&)
+{
+  // Ideally cmTarget instances should never be copied.  However until
+  // we can make a sweep to remove that, this copy constructor avoids
+  // allowing the resources (Internals) to be copied.
+  this->Pointer = new cmTargetInternals;
+  return *this;
+}

+ 33 - 4
Source/cmTarget.h

@@ -53,6 +53,19 @@ struct cmTargetLinkInterfaceMap:
   ~cmTargetLinkInterfaceMap();
 };
 
+class cmTargetInternals;
+class cmTargetInternalPointer
+{
+public:
+  cmTargetInternalPointer();
+  cmTargetInternalPointer(cmTargetInternalPointer const& r);
+  ~cmTargetInternalPointer();
+  cmTargetInternalPointer& operator=(cmTargetInternalPointer const& r);
+  cmTargetInternals* operator->() const { return this->Pointer; }
+private:
+  cmTargetInternals* Pointer;
+};
+
 /** \class cmTarget
  * \brief Represent a library or executable target loaded from a makefile.
  *
@@ -115,12 +128,22 @@ public:
    * 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.
    */
+  enum SourceFileType
+  {
+    SourceFileTypeNormal,
+    SourceFileTypePrivateHeader, // is in "PRIVATE_HEADER" target property
+    SourceFileTypePublicHeader,  // is in "PUBLIC_HEADER" target property
+    SourceFileTypeResource,      // is in "RESOURCE" target property *or*
+                                 // has MACOSX_PACKAGE_LOCATION=="Resources"
+    SourceFileTypeMacContent     // has MACOSX_PACKAGE_LOCATION!="Resources"
+  };
   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"
+    SourceFileFlags(): Type(SourceFileTypeNormal), MacFolder(0) {}
+    SourceFileFlags(SourceFileFlags const& r):
+      Type(r.Type), MacFolder(r.MacFolder) {}
+    SourceFileType Type;
+    const char* MacFolder; // location inside Mac content folders
   };
 
   /**
@@ -497,6 +520,12 @@ private:
   // The cmMakefile instance that owns this target.  This should
   // always be set.
   cmMakefile* Makefile;
+
+  // Internal representation details.
+  friend class cmTargetInternals;
+  cmTargetInternalPointer Internal;
+
+  void ConstructSourceFileFlags();
 };
 
 typedef std::map<cmStdString,cmTarget> cmTargets;