Browse Source

Merge topic 'ninja-fix-macosx'

1fc8df9 Add missing this->.
7a3ecf5 Fix memory leak in Makefile generator.
9f7dc83 Ninja: also bootstrap ninja files
5d365b2 Ninja: enable ninja support everywhere
d569f3e Ninja: void function can't return a value
52160bf Ninja: enable ninja on Mac so all Mac CDash-builds are tested, cleanup later
56aeac6 Ninja: fixes for bcc
7a6bc9e Ninja: remove 'this' from member initializer list
44ba4cf Ninja: remove warnings
7751966 Ninja: remove 'friend' in ninja code
c3988ee Re-factor OS X content generator start up.
f8e0a51 Re-factor framework directory computation.
f36c7b0 Re-factor Mac OS X content directory computation.
5d885db Re-factor bundle content copying rules generation.
3b2a01e Ninja: Use same echo message as makefiles.
7bb56c5 Re-factor CFBundle generation.
...
David Cole 13 years ago
parent
commit
a51e1529e7

+ 21 - 34
Source/CMakeLists.txt

@@ -219,6 +219,8 @@ SET(SRCS
   cmMakefileExecutableTargetGenerator.cxx
   cmMakefileLibraryTargetGenerator.cxx
   cmMakefileUtilityTargetGenerator.cxx
+  cmOSXBundleGenerator.cxx
+  cmOSXBundleGenerator.h
   cmNewLineStyle.h
   cmNewLineStyle.cxx
   cmOrderDirectories.cxx
@@ -357,40 +359,25 @@ IF (WIN32)
   ENDIF(NOT UNIX)
 ENDIF (WIN32)
 
-# Turn on Ninja by default, but disable it
-# on platforms where it does not pass all tests.
-# Enforce Ninja support by setting CMAKE_USE_NINJA
-set(_CMAKE_DEFAULT_NINJA_VALUE TRUE)
-if(APPLE)
-  SET(_CMAKE_DEFAULT_NINJA_VALUE FALSE)
-endif()
-SET(CMAKE_ENABLE_NINJA ${_CMAKE_DEFAULT_NINJA_VALUE} CACHE BOOL
-    "Enable the ninja generator for CMake. When enabled, some CMake tests still fail on OSX")
-MARK_AS_ADVANCED(CMAKE_ENABLE_NINJA)
-IF(CMAKE_ENABLE_NINJA)
-  MESSAGE(STATUS "Ninja generator enabled.")
-  SET(SRCS ${SRCS}
-    cmGlobalNinjaGenerator.cxx
-    cmGlobalNinjaGenerator.h
-    cmNinjaTypes.h
-    cmLocalNinjaGenerator.cxx
-    cmLocalNinjaGenerator.h
-    cmNinjaTargetGenerator.cxx
-    cmNinjaTargetGenerator.h
-    cmNinjaNormalTargetGenerator.cxx
-    cmNinjaNormalTargetGenerator.h
-    cmNinjaUtilityTargetGenerator.cxx
-    cmNinjaUtilityTargetGenerator.h
-    )
-  ADD_DEFINITIONS(-DCMAKE_USE_NINJA)
-  IF(WIN32 AND NOT CYGWIN AND NOT BORLAND)
-    SET_SOURCE_FILES_PROPERTIES(cmcldeps.cxx PROPERTIES COMPILE_DEFINITIONS _WIN32_WINNT=0x0501)
-    ADD_EXECUTABLE(cmcldeps cmcldeps.cxx)
-    TARGET_LINK_LIBRARIES(cmcldeps CMakeLib)
-    INSTALL_TARGETS(/bin cmcldeps)
-  ENDIF()
-ELSE()
-  MESSAGE(STATUS "Ninja generator disabled, enable it with -DCMAKE_ENABLE_NINJA=ON")
+# Ninja support
+SET(SRCS ${SRCS}
+  cmGlobalNinjaGenerator.cxx
+  cmGlobalNinjaGenerator.h
+  cmNinjaTypes.h
+  cmLocalNinjaGenerator.cxx
+  cmLocalNinjaGenerator.h
+  cmNinjaTargetGenerator.cxx
+  cmNinjaTargetGenerator.h
+  cmNinjaNormalTargetGenerator.cxx
+  cmNinjaNormalTargetGenerator.h
+  cmNinjaUtilityTargetGenerator.cxx
+  cmNinjaUtilityTargetGenerator.h
+  )
+IF(WIN32 AND NOT CYGWIN AND NOT BORLAND)
+  SET_SOURCE_FILES_PROPERTIES(cmcldeps.cxx PROPERTIES COMPILE_DEFINITIONS _WIN32_WINNT=0x0501)
+  ADD_EXECUTABLE(cmcldeps cmcldeps.cxx)
+  TARGET_LINK_LIBRARIES(cmcldeps CMakeLib)
+  INSTALL_TARGETS(/bin cmcldeps)
 ENDIF()
 
 # create a library used by the command line and the GUI

+ 5 - 4
Source/QtDialog/CMakeLists.txt

@@ -36,14 +36,14 @@ ELSE(NOT QT4_FOUND)
     QMacInstallDialog.cxx
     QMacInstallDialog.h
     )
-  QT4_WRAP_UI(UI_SRCS 
+  QT4_WRAP_UI(UI_SRCS
     CMakeSetupDialog.ui
     Compilers.ui
     CrossCompiler.ui
     AddCacheEntry.ui
     MacInstallDialog.ui
     )
-  QT4_WRAP_CPP(MOC_SRCS 
+  QT4_WRAP_CPP(MOC_SRCS
     AddCacheEntry.h
     Compilers.h
     CMakeSetupDialog.h
@@ -76,7 +76,7 @@ ELSE(NOT QT4_FOUND)
       SET_TARGET_PROPERTIES(cmake-gui PROPERTIES
        OUTPUT_NAME ${CMAKE_BUNDLE_NAME})
     ENDIF(APPLE)
-    SET(CMAKE_INSTALL_DESTINATION_ARGS 
+    SET(CMAKE_INSTALL_DESTINATION_ARGS
       BUNDLE DESTINATION "${CMAKE_BUNDLE_LOCATION}")
   ENDIF(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.4)
 
@@ -112,11 +112,12 @@ ELSE(NOT QT4_FOUND)
     endif(APPLE)
     install(CODE "
       include(\"${CMake_SOURCE_DIR}/Modules/BundleUtilities.cmake\")
+      set(BU_CHMOD_BUNDLE_ITEMS ON)
       fixup_bundle(\"${fixup_exe}\" \"\" \"${QT_LIBRARY_DIR};${QT_BINARY_DIR}\")
     ")
   endif(APPLE OR WIN32)
 
   CONFIGURE_FILE("${QtDialog_SOURCE_DIR}/QtDialogCPack.cmake.in"
-    "${QtDialog_BINARY_DIR}/QtDialogCPack.cmake" @ONLY)    
+    "${QtDialog_BINARY_DIR}/QtDialogCPack.cmake" @ONLY)
 ENDIF(NOT QT4_FOUND)
 

+ 0 - 2
Source/cmExtraCodeBlocksGenerator.cxx

@@ -60,9 +60,7 @@ cmExtraCodeBlocksGenerator::cmExtraCodeBlocksGenerator()
 // disable until somebody actually tests it:
 //  this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
 #endif
-#ifdef CMAKE_USE_NINJA
   this->SupportedGlobalGenerators.push_back("Ninja");
-#endif
   this->SupportedGlobalGenerators.push_back("Unix Makefiles");
 }
 

+ 0 - 2
Source/cmExtraEclipseCDT4Generator.cxx

@@ -34,9 +34,7 @@ cmExtraEclipseCDT4Generator
   this->SupportedGlobalGenerators.push_back("MinGW Makefiles");
 //  this->SupportedGlobalGenerators.push_back("MSYS Makefiles");
 #endif
-#ifdef CMAKE_USE_NINJA
   this->SupportedGlobalGenerators.push_back("Ninja");
-#endif
   this->SupportedGlobalGenerators.push_back("Unix Makefiles");
 
   this->SupportsVirtualFolders = true;

+ 47 - 0
Source/cmGlobalNinjaGenerator.cxx

@@ -252,6 +252,48 @@ cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command,
                                      vars);
 }
 
+void
+cmGlobalNinjaGenerator::AddMacOSXContentRule()
+{
+  cmLocalGenerator *lg = this->LocalGenerators[0];
+  cmMakefile* mfRoot = lg->GetMakefile();
+
+  cmOStringStream cmd;
+  cmd << lg->ConvertToOutputFormat(
+           mfRoot->GetRequiredDefinition("CMAKE_COMMAND"),
+           cmLocalGenerator::SHELL)
+      << " -E copy $in $out";
+
+  this->AddRule("COPY_OSX_CONTENT",
+                cmd.str(),
+                "Copying OS X Content $out",
+                "Rule for copying OS X bundle content file."
+                /*depfile*/ "",
+                /*rspfile*/ "");
+}
+
+void
+cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input,
+                                                const std::string& output)
+{
+  this->AddMacOSXContentRule();
+
+  cmNinjaDeps outputs;
+  outputs.push_back(output);
+  cmNinjaDeps deps;
+  deps.push_back(input);
+  cmNinjaVars vars;
+
+  cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream,
+                                     "",
+                                     "COPY_OSX_CONTENT",
+                                     outputs,
+                                     deps,
+                                     cmNinjaDeps(),
+                                     cmNinjaDeps(),
+                                     cmNinjaVars());
+}
+
 void cmGlobalNinjaGenerator::WriteRule(std::ostream& os,
                                        const std::string& name,
                                        const std::string& command,
@@ -781,6 +823,11 @@ void cmGlobalNinjaGenerator::AddDependencyToAll(cmTarget* target)
   this->AppendTargetOutputs(target, this->AllDependencies);
 }
 
+void cmGlobalNinjaGenerator::AddDependencyToAll(const std::string& input)
+{
+  this->AllDependencies.push_back(input);
+}
+
 void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies()
 {
   for (std::map<std::string, std::set<std::string> >::iterator

+ 55 - 51
Source/cmGlobalNinjaGenerator.h

@@ -103,6 +103,8 @@ public:
                                const cmNinjaDeps& outputs,
                                const cmNinjaDeps& deps = cmNinjaDeps(),
                              const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps());
+  void WriteMacOSXContentBuild(const std::string& input,
+                               const std::string& output);
 
   /**
    * Write a rule statement named @a name to @a os with the @a comment,
@@ -151,6 +153,7 @@ public:
 
   static bool IsMinGW() { return UsingMinGW; }
 
+
 public:
   /// Default constructor.
   cmGlobalNinjaGenerator();
@@ -214,12 +217,12 @@ public:
   }
   virtual const char* GetCleanTargetName()         const { return "clean"; }
 
-public:
-  cmGeneratedFileStream* GetBuildFileStream() const
-  { return this->BuildFileStream; }
 
-  cmGeneratedFileStream* GetRulesFileStream() const
-  { return this->RulesFileStream; }
+  cmGeneratedFileStream* GetBuildFileStream() const {
+    return this->BuildFileStream; }
+
+  cmGeneratedFileStream* GetRulesFileStream() const {
+    return this->RulesFileStream; }
 
   void AddCXXCompileCommand(const std::string &commandLine,
                             const std::string &sourceFile);
@@ -242,6 +245,52 @@ public:
   bool HasRule(const std::string& name);
 
   void AddCustomCommandRule();
+  void AddMacOSXContentRule();
+
+  bool HasCustomCommandOutput(const std::string &output) {
+    return this->CustomCommandOutputs.find(output) !=
+           this->CustomCommandOutputs.end();
+  }
+
+  /// Called when we have seen the given custom command.  Returns true
+  /// if we has seen it before.
+  bool SeenCustomCommand(cmCustomCommand const *cc) {
+    return !this->CustomCommands.insert(cc).second;
+  }
+
+  /// Called when we have seen the given custom command output.
+  void SeenCustomCommandOutput(const std::string &output) {
+    this->CustomCommandOutputs.insert(output);
+    // We don't need the assumed dependencies anymore, because we have
+    // an output.
+    this->AssumedSourceDependencies.erase(output);
+  }
+
+  void AddAssumedSourceDependencies(const std::string &source,
+                                    const cmNinjaDeps &deps) {
+    std::set<std::string> &ASD = this->AssumedSourceDependencies[source];
+    // Because we may see the same source file multiple times (same source
+    // specified in multiple targets), compute the union of any assumed
+    // dependencies.
+    ASD.insert(deps.begin(), deps.end());
+  }
+
+  void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs);
+  void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs);
+  void AddDependencyToAll(cmTarget* target);
+  void AddDependencyToAll(const std::string& input);
+
+  const std::vector<cmLocalGenerator*>& GetLocalGenerators() const {
+    return LocalGenerators; }
+
+  bool IsExcluded(cmLocalGenerator* root, cmTarget& target) {
+    return cmGlobalGenerator::IsExcluded(root, target); }
+
+  int GetRuleCmdLength(const std::string& name) {
+    return RuleCmdLength[name]; }
+
+  void AddTargetAlias(const std::string& alias, cmTarget* target);
+
 
 protected:
 
@@ -249,21 +298,12 @@ protected:
   /// @see cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS()
   virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { return true; }
 
+
 private:
 
   /// @see cmGlobalGenerator::ComputeTargetObjects
   virtual void ComputeTargetObjects(cmGeneratorTarget* gt) const;
 
-private:
-  // In order to access the AddDependencyToAll() functions and co.
-  friend class cmLocalNinjaGenerator;
-
-  // In order to access the SeenCustomCommand() function.
-  friend class cmNinjaTargetGenerator;
-  friend class cmNinjaNormalTargetGenerator;
-  friend class cmNinjaUtilityTargetGenerator;
-
-private:
   void OpenBuildFileStream();
   void CloseBuildFileStream();
 
@@ -275,14 +315,8 @@ private:
   /// Write the common disclaimer text at the top of each build file.
   void WriteDisclaimer(std::ostream& os);
 
-  void AddDependencyToAll(cmTarget* target);
-
   void WriteAssumedSourceDependencies();
 
-  void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs);
-  void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs);
-
-  void AddTargetAlias(const std::string& alias, cmTarget* target);
   void WriteTargetAliases(std::ostream& os);
 
   void WriteBuiltinTargets(std::ostream& os);
@@ -291,39 +325,9 @@ private:
   void WriteTargetClean(std::ostream& os);
   void WriteTargetHelp(std::ostream& os);
 
-  /// Called when we have seen the given custom command.  Returns true
-  /// if we has seen it before.
-  bool SeenCustomCommand(cmCustomCommand const *cc) {
-    return !this->CustomCommands.insert(cc).second;
-  }
-
-  /// Called when we have seen the given custom command output.
-  void SeenCustomCommandOutput(const std::string &output) {
-    this->CustomCommandOutputs.insert(output);
-    // We don't need the assumed dependencies anymore, because we have
-    // an output.
-    this->AssumedSourceDependencies.erase(output);
-  }
-
-  bool HasCustomCommandOutput(const std::string &output) {
-    return this->CustomCommandOutputs.find(output) !=
-           this->CustomCommandOutputs.end();
-  }
-
-  void AddAssumedSourceDependencies(const std::string &source,
-                                    const cmNinjaDeps &deps) {
-    std::set<std::string> &ASD = this->AssumedSourceDependencies[source];
-    // Because we may see the same source file multiple times (same source
-    // specified in multiple targets), compute the union of any assumed
-    // dependencies.
-    ASD.insert(deps.begin(), deps.end());
-  }
-
   std::string ninjaCmd() const;
 
-  int GetRuleCmdLength(const std::string& name) { return RuleCmdLength[name]; }
 
-private:
   /// The file containing the build statement. (the relation ship of the
   /// compilation DAG).
   cmGeneratedFileStream* BuildFileStream;

+ 1 - 1
Source/cmLocalNinjaGenerator.cxx

@@ -61,7 +61,7 @@ void cmLocalNinjaGenerator::Generate()
       tg->Generate();
       // Add the target to "all" if required.
       if (!this->GetGlobalNinjaGenerator()->IsExcluded(
-            this->GetGlobalNinjaGenerator()->LocalGenerators[0],
+            this->GetGlobalNinjaGenerator()->GetLocalGenerators()[0],
             t->second))
         this->GetGlobalNinjaGenerator()->AddDependencyToAll(&t->second);
       delete tg;

+ 31 - 31
Source/cmLocalNinjaGenerator.h

@@ -45,7 +45,6 @@ public:
   /// Overloaded methods. @see cmLocalGenerator::GetTargetDirectory()
   virtual std::string GetTargetDirectory(cmTarget const& target) const;
 
-public:
   const cmGlobalNinjaGenerator* GetGlobalNinjaGenerator() const;
   cmGlobalNinjaGenerator* GetGlobalNinjaGenerator();
 
@@ -67,33 +66,8 @@ public:
   std::string GetHomeRelativeOutputPath() const
   { return this->HomeRelativeOutputPath; }
 
-protected:
-  virtual std::string ConvertToLinkReference(std::string const& lib);
-  virtual std::string ConvertToIncludeReference(std::string const& path);
-
-private:
-  friend class cmGlobalNinjaGenerator;
-
-  // In order to access to protected member of the local generator.
-  friend class cmNinjaTargetGenerator;
-  friend class cmNinjaNormalTargetGenerator;
-  friend class cmNinjaUtilityTargetGenerator;
-
-private:
-  cmGeneratedFileStream& GetBuildFileStream() const;
-  cmGeneratedFileStream& GetRulesFileStream() const;
-
-  void WriteBuildFileTop();
-  void WriteProjectHeader(std::ostream& os);
-  void WriteNinjaFilesInclusion(std::ostream& os);
-  void WriteProcessedMakefile(std::ostream& os);
-
-  void SetConfigName();
-
   std::string ConvertToNinjaPath(const char *path);
 
-  struct map_to_ninja_path;
-  friend struct map_to_ninja_path;
   struct map_to_ninja_path {
     cmLocalNinjaGenerator *LocalGenerator;
     map_to_ninja_path(cmLocalNinjaGenerator *LocalGen)
@@ -102,26 +76,52 @@ private:
       return LocalGenerator->ConvertToNinjaPath(path.c_str());
     }
   };
+
   map_to_ninja_path MapToNinjaPath() {
     return map_to_ninja_path(this);
   }
 
+  void ExpandRuleVariables(std::string& string,
+                           const RuleVariables& replaceValues) {
+    cmLocalGenerator::ExpandRuleVariables(string, replaceValues);
+  }
+
+  std::string BuildCommandLine(const std::vector<std::string> &cmdLines);
+
   void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs);
   void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs);
 
-  void AppendCustomCommandDeps(const cmCustomCommand *cc,
-                               cmNinjaDeps &ninjaDeps);
-  std::string BuildCommandLine(const std::vector<std::string> &cmdLines);
+  void AddCustomCommandTarget(cmCustomCommand const* cc, cmTarget* target);
   void AppendCustomCommandLines(const cmCustomCommand *cc,
                                 std::vector<std::string> &cmdLines);
+  void AppendCustomCommandDeps(const cmCustomCommand *cc,
+                               cmNinjaDeps &ninjaDeps);
+
+  virtual std::string ConvertToLinkReference(std::string const& lib);
+
+
+protected:
+  virtual std::string ConvertToIncludeReference(std::string const& path);
+
+
+private:
+  cmGeneratedFileStream& GetBuildFileStream() const;
+  cmGeneratedFileStream& GetRulesFileStream() const;
+
+  void WriteBuildFileTop();
+  void WriteProjectHeader(std::ostream& os);
+  void WriteNinjaFilesInclusion(std::ostream& os);
+  void WriteProcessedMakefile(std::ostream& os);
+
+  void SetConfigName();
+
   void WriteCustomCommandRule();
   void WriteCustomCommandBuildStatement(cmCustomCommand const *cc,
                                         const cmNinjaDeps& orderOnlyDeps);
 
-  void AddCustomCommandTarget(cmCustomCommand const* cc, cmTarget* target);
   void WriteCustomCommandBuildStatements();
 
-private:
+
   std::string ConfigName;
   std::string HomeRelativeOutputPath;
 

+ 15 - 30
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -29,13 +29,19 @@ cmMakefileExecutableTargetGenerator
     this->TargetNameOut, this->TargetNameReal, this->TargetNameImport,
     this->TargetNamePDB, this->ConfigName);
 
-  if(this->Target->IsAppBundleOnApple())
-    {
-    this->MacContentDirectory = this->Target->GetDirectory(this->ConfigName);
-    this->MacContentDirectory += "/";
-    this->MacContentDirectory += this->TargetNameOut;
-    this->MacContentDirectory += ".app/Contents/";
-    }
+  this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target,
+                                                      this->TargetNameOut,
+                                                      this->ConfigName);
+  this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+  this->MacContentDirectory =
+    this->OSXBundleGenerator->GetMacContentDirectory();
+}
+
+//----------------------------------------------------------------------------
+cmMakefileExecutableTargetGenerator
+::~cmMakefileExecutableTargetGenerator()
+{
+  delete this->OSXBundleGenerator;
 }
 
 //----------------------------------------------------------------------------
@@ -100,7 +106,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   outpath += "/";
   if(this->Target->IsAppBundleOnApple())
     {
-    this->CreateAppBundle(targetName, outpath);
+    this->OSXBundleGenerator->CreateAppBundle(targetName, outpath);
     }
   std::string outpathImp;
   if(relink)
@@ -129,7 +135,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   std::string targetFullPathReal = outpath + targetNameReal;
   std::string targetFullPathPDB = outpath + targetNamePDB;
   std::string targetFullPathImport = outpathImp + targetNameImport;
-  std::string targetOutPathPDB = 
+  std::string targetOutPathPDB =
     this->Convert(targetFullPathPDB.c_str(),
                   cmLocalGenerator::NONE,
                   cmLocalGenerator::SHELL);
@@ -440,24 +446,3 @@ 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());
-  this->Makefile->AddCMakeOutputFile(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());
-  this->Makefile->AddCMakeOutputFile(plist.c_str());
-}

+ 2 - 2
Source/cmMakefileExecutableTargetGenerator.h

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

+ 24 - 148
Source/cmMakefileLibraryTargetGenerator.cxx

@@ -26,41 +26,26 @@ cmMakefileLibraryTargetGenerator
 ::cmMakefileLibraryTargetGenerator(cmTarget* target):
   cmMakefileTargetGenerator(target)
 {
-  if(this->Target->IsCFBundleOnApple())
-    {
-    target->SetProperty("PREFIX", "");
-    target->SetProperty("SUFFIX", "");
-    }
+  cmOSXBundleGenerator::PrepareTargetProperties(this->Target);
 
   this->CustomCommandDriver = OnDepends;
   this->Target->GetLibraryNames(
     this->TargetNameOut, this->TargetNameSO, this->TargetNameReal,
     this->TargetNameImport, this->TargetNamePDB, this->ConfigName);
 
-  if(this->Target->IsFrameworkOnApple())
-    {
-    this->FrameworkVersion = this->Target->GetFrameworkVersion();
-    this->MacContentDirectory = this->Target->GetDirectory(this->ConfigName);
-    this->MacContentDirectory += "/";
-    this->MacContentDirectory += this->TargetNameOut;
-    this->MacContentDirectory += ".framework/Versions/";
-    this->MacContentDirectory += this->FrameworkVersion;
-    this->MacContentDirectory += "/";
-    }
-  else if(this->Target->IsCFBundleOnApple())
-    {
-    this->MacContentDirectory = this->Target->GetDirectory(this->ConfigName);
-    this->MacContentDirectory += "/";
-    this->MacContentDirectory += this->TargetNameOut;
-    this->MacContentDirectory += ".";
-    const char *ext = this->Target->GetProperty("BUNDLE_EXTENSION");
-    if (!ext)
-      {
-      ext = "bundle";
-      }
-    this->MacContentDirectory += ext;
-    this->MacContentDirectory += "/Contents/";
-    }
+  this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target,
+                                                      this->TargetNameOut,
+                                                      this->ConfigName);
+  this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+  this->MacContentDirectory =
+    this->OSXBundleGenerator->GetMacContentDirectory();
+}
+
+//----------------------------------------------------------------------------
+cmMakefileLibraryTargetGenerator
+::~cmMakefileLibraryTargetGenerator()
+{
+  delete this->OSXBundleGenerator;
 }
 
 //----------------------------------------------------------------------------
@@ -199,7 +184,7 @@ void cmMakefileLibraryTargetGenerator::WriteSharedLibraryRules(bool relink)
   linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
   this->LocalGenerator->AppendFlags
     (extraFlags, this->Target->GetProperty(linkFlagsConfig.c_str()));
-                                    
+
   this->LocalGenerator->AddConfigVariableFlags
     (extraFlags, "CMAKE_SHARED_LINKER_FLAGS", this->ConfigName);
   this->AddModuleDefinitionFlag(extraFlags);
@@ -220,7 +205,7 @@ void cmMakefileLibraryTargetGenerator::WriteModuleLibraryRules(bool relink)
   linkRuleVar += "_CREATE_SHARED_MODULE";
 
   std::string extraFlags;
-  this->LocalGenerator->AppendFlags(extraFlags, 
+  this->LocalGenerator->AppendFlags(extraFlags,
                                     this->Target->GetProperty("LINK_FLAGS"));
   std::string linkFlagsConfig = "LINK_FLAGS_";
   linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
@@ -246,7 +231,7 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
   linkRuleVar += "_CREATE_MACOSX_FRAMEWORK";
 
   std::string extraFlags;
-  this->LocalGenerator->AppendFlags(extraFlags, 
+  this->LocalGenerator->AppendFlags(extraFlags,
                                     this->Target->GetProperty("LINK_FLAGS"));
   std::string linkFlagsConfig = "LINK_FLAGS_";
   linkFlagsConfig += cmSystemTools::UpperCase(this->ConfigName);
@@ -258,115 +243,6 @@ void cmMakefileLibraryTargetGenerator::WriteFrameworkRules(bool relink)
   this->WriteLibraryRules(linkRuleVar.c_str(), extraFlags.c_str(), relink);
 }
 
-//----------------------------------------------------------------------------
-void
-cmMakefileLibraryTargetGenerator
-::CreateFramework(std::string const& targetName)
-{
-  // Configure the Info.plist file into the Resources directory.
-  this->MacContentFolders.insert("Resources");
-  std::string plist = this->MacContentDirectory + "Resources/Info.plist";
-  this->LocalGenerator->GenerateFrameworkInfoPList(this->Target,
-                                                   targetName.c_str(),
-                                                   plist.c_str());
-
-  // TODO: Use the cmMakefileTargetGenerator::ExtraFiles vector to
-  // drive rules to create these files at build time.
-  std::string oldName;
-  std::string newName;
-
-  // Compute the location of the top-level foo.framework directory.
-  std::string top = this->Target->GetDirectory(this->ConfigName);
-  top += "/";
-  top += this->TargetNameOut;
-  top += ".framework/";
-
-  // Make foo.framework/Versions
-  std::string versions = top;
-  versions += "Versions";
-  cmSystemTools::MakeDirectory(versions.c_str());
-
-  // Make foo.framework/Versions/version
-  std::string version = versions;
-  version += "/";
-  version += this->FrameworkVersion;
-  cmSystemTools::MakeDirectory(version.c_str());
-
-  // Current -> version
-  oldName = this->FrameworkVersion;
-  newName = versions;
-  newName += "/Current";
-  cmSystemTools::RemoveFile(newName.c_str());
-  cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
-  this->Makefile->AddCMakeOutputFile(newName.c_str());
-
-  // foo -> Versions/Current/foo
-  oldName = "Versions/Current/";
-  oldName += this->TargetNameOut;
-  newName = top;
-  newName += this->TargetNameOut;
-  cmSystemTools::RemoveFile(newName.c_str());
-  cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
-  this->Makefile->AddCMakeOutputFile(newName.c_str());
-
-  // Resources -> Versions/Current/Resources
-  if(this->MacContentFolders.find("Resources") !=
-     this->MacContentFolders.end())
-    {
-    oldName = "Versions/Current/Resources";
-    newName = top;
-    newName += "Resources";
-    cmSystemTools::RemoveFile(newName.c_str());
-    cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
-    this->Makefile->AddCMakeOutputFile(newName.c_str());
-    }
-
-  // Headers -> Versions/Current/Headers
-  if(this->MacContentFolders.find("Headers") !=
-     this->MacContentFolders.end())
-    {
-    oldName = "Versions/Current/Headers";
-    newName = top;
-    newName += "Headers";
-    cmSystemTools::RemoveFile(newName.c_str());
-    cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
-    this->Makefile->AddCMakeOutputFile(newName.c_str());
-    }
-
-  // PrivateHeaders -> Versions/Current/PrivateHeaders
-  if(this->MacContentFolders.find("PrivateHeaders") !=
-     this->MacContentFolders.end())
-    {
-    oldName = "Versions/Current/PrivateHeaders";
-    newName = top;
-    newName += "PrivateHeaders";
-    cmSystemTools::RemoveFile(newName.c_str());
-    cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
-    this->Makefile->AddCMakeOutputFile(newName.c_str());
-    }
-}
-
-//----------------------------------------------------------------------------
-void
-cmMakefileLibraryTargetGenerator::CreateCFBundle(std::string& targetName,
-                                                 std::string& outpath)
-{
-  // Compute bundle directory names.
-  outpath = this->MacContentDirectory;
-  outpath += "MacOS";
-  cmSystemTools::MakeDirectory(outpath.c_str());
-  this->Makefile->AddCMakeOutputFile(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());
-  this->Makefile->AddCMakeOutputFile(plist.c_str());
-}
-
 //----------------------------------------------------------------------------
 void cmMakefileLibraryTargetGenerator::WriteLibraryRules
 (const char* linkRuleVar, const char* extraFlags, bool relink)
@@ -419,13 +295,13 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
   if(this->Target->IsFrameworkOnApple())
     {
     outpath = this->MacContentDirectory;
-    this->CreateFramework(targetName);
+    this->OSXBundleGenerator->CreateFramework(targetName);
     }
   else if(this->Target->IsCFBundleOnApple())
     {
     outpath = this->Target->GetDirectory(this->ConfigName);
     outpath += "/";
-    this->CreateCFBundle(targetName, outpath);
+    this->OSXBundleGenerator->CreateCFBundle(targetName, outpath);
     }
   else if(relink)
     {
@@ -460,16 +336,16 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
 
   // Construct the output path version of the names for use in command
   // arguments.
-  std::string targetOutPathPDB = 
+  std::string targetOutPathPDB =
     this->Convert(targetFullPathPDB.c_str(),cmLocalGenerator::NONE,
                   cmLocalGenerator::SHELL);
-  std::string targetOutPath = 
+  std::string targetOutPath =
     this->Convert(targetFullPath.c_str(),cmLocalGenerator::START_OUTPUT,
                   cmLocalGenerator::SHELL);
-  std::string targetOutPathSO = 
+  std::string targetOutPathSO =
     this->Convert(targetFullPathSO.c_str(),cmLocalGenerator::START_OUTPUT,
                   cmLocalGenerator::SHELL);
-  std::string targetOutPathReal = 
+  std::string targetOutPathReal =
     this->Convert(targetFullPathReal.c_str(),cmLocalGenerator::START_OUTPUT,
                   cmLocalGenerator::SHELL);
   std::string targetOutPathImport =
@@ -569,7 +445,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules
 
   std::vector<std::string> commands1;
   // Add a command to remove any existing files for this library.
-  // for static libs only 
+  // for static libs only
   if(this->Target->GetType() == cmTarget::STATIC_LIBRARY)
     {
     this->LocalGenerator->AppendCleanCommand(commands1, libCleanFiles,

+ 4 - 5
Source/cmMakefileLibraryTargetGenerator.h

@@ -14,16 +14,17 @@
 
 #include "cmMakefileTargetGenerator.h"
 
-class cmMakefileLibraryTargetGenerator: 
+class cmMakefileLibraryTargetGenerator:
   public cmMakefileTargetGenerator
 {
 public:
   cmMakefileLibraryTargetGenerator(cmTarget* target);
+  virtual ~cmMakefileLibraryTargetGenerator();
 
   /* the main entry point for this class. Writes the Makefiles associated
      with this target */
-  virtual void WriteRuleFiles();  
-  
+  virtual void WriteRuleFiles();
+
 protected:
   void WriteObjectLibraryRules();
   void WriteStaticLibraryRules();
@@ -33,8 +34,6 @@ protected:
                          bool relink);
   // MacOSX Framework support methods
   void WriteFrameworkRules(bool relink);
-  void CreateFramework(std::string const& targetName);
-  void CreateCFBundle(std::string& targetName, std::string& outpath);
 
   // Store the computd framework version for OS X Frameworks.
   std::string FrameworkVersion;

+ 39 - 48
Source/cmMakefileTargetGenerator.cxx

@@ -28,6 +28,8 @@
 
 
 cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmTarget* target)
+  : OSXBundleGenerator(0)
+  , MacOSXContentGenerator(0)
 {
   this->BuildFileStream = 0;
   this->InfoFileStream = 0;
@@ -50,6 +52,12 @@ cmMakefileTargetGenerator::cmMakefileTargetGenerator(cmTarget* target)
     {
     this->NoRuleMessages = cmSystemTools::IsOff(ruleStatus);
     }
+  MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
+}
+
+cmMakefileTargetGenerator::~cmMakefileTargetGenerator()
+{
+  delete MacOSXContentGenerator;
 }
 
 cmMakefileTargetGenerator *
@@ -153,8 +161,12 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
         }
       }
     }
-  this->WriteMacOSXContentRules(this->GeneratorTarget->HeaderSources);
-  this->WriteMacOSXContentRules(this->GeneratorTarget->ExtraSources);
+  this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+    this->GeneratorTarget->HeaderSources,
+    this->MacOSXContentGenerator);
+  this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+    this->GeneratorTarget->ExtraSources,
+    this->MacOSXContentGenerator);
   for(std::vector<cmSourceFile*>::const_iterator
         si = this->GeneratorTarget->ExternalObjects.begin();
       si != this->GeneratorTarget->ExternalObjects.end(); ++si)
@@ -173,7 +185,6 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules()
   this->GeneratorTarget->UseObjectLibraries(this->ExternalObjects);
 }
 
-
 //----------------------------------------------------------------------------
 void cmMakefileTargetGenerator::WriteCommonCodeRules()
 {
@@ -343,44 +354,20 @@ void cmMakefileTargetGenerator::WriteTargetLanguageFlags()
     }
 }
 
-//----------------------------------------------------------------------------
-void cmMakefileTargetGenerator::WriteMacOSXContentRules(
-  std::vector<cmSourceFile*> const& sources)
-{
-  for(std::vector<cmSourceFile*>::const_iterator
-        si = sources.begin(); si != sources.end(); ++si)
-    {
-    cmTarget::SourceFileFlags tsFlags =
-      this->Target->GetTargetSourceFileFlags(*si);
-    if(tsFlags.Type != cmTarget::SourceFileTypeNormal)
-      {
-      this->WriteMacOSXContentRules(**si, tsFlags.MacFolder);
-      }
-    }
-}
 
 //----------------------------------------------------------------------------
-void cmMakefileTargetGenerator::WriteMacOSXContentRules(cmSourceFile& source,
-                                                        const char* pkgloc)
+void
+cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()
+  (cmSourceFile& source, const char* pkgloc)
 {
   // Skip OS X content when not building a Framework or Bundle.
-  if(this->MacContentDirectory.empty())
+  if(this->Generator->MacContentDirectory.empty())
     {
     return;
     }
 
-  // Construct the full path to the content subdirectory.
-  std::string macdir = this->MacContentDirectory;
-  macdir += pkgloc;
-  cmSystemTools::MakeDirectory(macdir.c_str());
-
-  // Record use of this content location.  Only the first level
-  // directory is needed.
-  {
-  std::string loc = pkgloc;
-  loc = loc.substr(0, loc.find('/'));
-  this->MacContentFolders.insert(loc);
-  }
+  std::string macdir =
+    this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc);
 
   // Get the input file location.
   std::string input = source.GetFullPath();
@@ -389,9 +376,11 @@ void cmMakefileTargetGenerator::WriteMacOSXContentRules(cmSourceFile& source,
   std::string output = macdir;
   output += "/";
   output += cmSystemTools::GetFilenameName(input);
-  this->CleanFiles.push_back(this->Convert(output.c_str(),
-                                           cmLocalGenerator::START_OUTPUT));
-  output = this->Convert(output.c_str(), cmLocalGenerator::HOME_OUTPUT);
+  this->Generator->CleanFiles.push_back(
+    this->Generator->Convert(output.c_str(),
+                             cmLocalGenerator::START_OUTPUT));
+  output = this->Generator->Convert(output.c_str(),
+                                    cmLocalGenerator::HOME_OUTPUT);
 
   // Create a rule to copy the content into the bundle.
   std::vector<std::string> depends;
@@ -399,21 +388,23 @@ void cmMakefileTargetGenerator::WriteMacOSXContentRules(cmSourceFile& source,
   depends.push_back(input);
   std::string copyEcho = "Copying OS X content ";
   copyEcho += output;
-  this->LocalGenerator->AppendEcho(commands, copyEcho.c_str(),
-                                   cmLocalUnixMakefileGenerator3::EchoBuild);
+  this->Generator->LocalGenerator->AppendEcho(
+    commands, copyEcho.c_str(),
+    cmLocalUnixMakefileGenerator3::EchoBuild);
   std::string copyCommand = "$(CMAKE_COMMAND) -E copy ";
-  copyCommand += this->Convert(input.c_str(),
-                               cmLocalGenerator::NONE,
-                               cmLocalGenerator::SHELL);
+  copyCommand += this->Generator->Convert(input.c_str(),
+                                          cmLocalGenerator::NONE,
+                                          cmLocalGenerator::SHELL);
   copyCommand += " ";
-  copyCommand += this->Convert(output.c_str(),
-                               cmLocalGenerator::NONE,
-                               cmLocalGenerator::SHELL);
+  copyCommand += this->Generator->Convert(output.c_str(),
+                                          cmLocalGenerator::NONE,
+                                          cmLocalGenerator::SHELL);
   commands.push_back(copyCommand);
-  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
-                                      output.c_str(),
-                                      depends, commands, false);
-  this->ExtraFiles.insert(output);
+  this->Generator->LocalGenerator->WriteMakeRule(
+    *this->Generator->BuildFileStream, 0,
+    output.c_str(),
+    depends, commands, false);
+  this->Generator->ExtraFiles.insert(output);
 }
 
 //----------------------------------------------------------------------------

+ 17 - 3
Source/cmMakefileTargetGenerator.h

@@ -13,6 +13,7 @@
 #define cmMakefileTargetGenerator_h
 
 #include "cmLocalUnixMakefileGenerator3.h"
+#include "cmOSXBundleGenerator.h"
 
 class cmCustomCommand;
 class cmDependInformation;
@@ -34,7 +35,7 @@ class cmMakefileTargetGenerator
 public:
   // constructor to set the ivars
   cmMakefileTargetGenerator(cmTarget* target);
-  virtual ~cmMakefileTargetGenerator() {};
+  virtual ~cmMakefileTargetGenerator();
 
   // construct using this factory call
   static cmMakefileTargetGenerator *New(cmTarget *tgt);
@@ -50,6 +51,7 @@ public:
     { return this->ProgressFileNameFull; }
 
   cmTarget* GetTarget() { return this->Target;}
+
 protected:
 
   // create the file and directory etc
@@ -73,8 +75,18 @@ protected:
   void WriteTargetDependRules();
 
   // write rules for Mac OS X Application Bundle content.
-  void WriteMacOSXContentRules(std::vector<cmSourceFile*> const& sources);
-  void WriteMacOSXContentRules(cmSourceFile& source, const char* pkgloc);
+  struct MacOSXContentGeneratorType :
+    cmOSXBundleGenerator::MacOSXContentGeneratorType
+  {
+    MacOSXContentGeneratorType(cmMakefileTargetGenerator* gen) :
+      Generator(gen) {}
+
+    void operator()(cmSourceFile& source, const char* pkgloc);
+
+  private:
+    cmMakefileTargetGenerator* Generator;
+  };
+  friend struct MacOSXContentGeneratorType;
 
   // write the rules for an object
   void WriteObjectRuleFiles(cmSourceFile& source);
@@ -223,6 +235,8 @@ protected:
   // Mac OS X content info.
   std::string MacContentDirectory;
   std::set<cmStdString> MacContentFolders;
+  cmOSXBundleGenerator* OSXBundleGenerator;
+  MacOSXContentGeneratorType* MacOSXContentGenerator;
 
   typedef std::map<cmStdString, cmStdString> ByLanguageMap;
   std::string GetFlags(const std::string &l);

+ 13 - 0
Source/cmMakefileUtilityTargetGenerator.cxx

@@ -24,6 +24,19 @@ cmMakefileUtilityTargetGenerator
   cmMakefileTargetGenerator(target)
 {
   this->CustomCommandDriver = OnUtility;
+  this->OSXBundleGenerator = new cmOSXBundleGenerator(this->Target,
+                                                      this->TargetNameOut,
+                                                      this->ConfigName);
+  this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
+  this->MacContentDirectory =
+    this->OSXBundleGenerator->GetMacContentDirectory();
+}
+
+//----------------------------------------------------------------------------
+cmMakefileUtilityTargetGenerator
+::~cmMakefileUtilityTargetGenerator()
+{
+  delete this->OSXBundleGenerator;
 }
 
 //----------------------------------------------------------------------------

+ 4 - 3
Source/cmMakefileUtilityTargetGenerator.h

@@ -14,16 +14,17 @@
 
 #include "cmMakefileTargetGenerator.h"
 
-class cmMakefileUtilityTargetGenerator: 
+class cmMakefileUtilityTargetGenerator:
   public cmMakefileTargetGenerator
 {
 public:
   cmMakefileUtilityTargetGenerator(cmTarget* target);
+  virtual ~cmMakefileUtilityTargetGenerator();
 
   /* the main entry point for this class. Writes the Makefiles associated
      with this target */
-  virtual void WriteRuleFiles();  
-  
+  virtual void WriteRuleFiles();
+
 protected:
 
 };

+ 48 - 11
Source/cmNinjaNormalTargetGenerator.cxx

@@ -16,6 +16,7 @@
 #include "cmSourceFile.h"
 #include "cmGeneratedFileStream.h"
 #include "cmMakefile.h"
+#include "cmOSXBundleGenerator.h"
 
 #include <assert.h>
 #include <algorithm>
@@ -33,7 +34,10 @@ cmNinjaNormalTargetGenerator(cmTarget* target)
   , TargetNameReal()
   , TargetNameImport()
   , TargetNamePDB()
+  , TargetLinkLanguage(0)
 {
+  cmOSXBundleGenerator::PrepareTargetProperties(target);
+
   this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName());
   if (target->GetType() == cmTarget::EXECUTABLE)
     target->GetExecutableNames(this->TargetNameOut,
@@ -55,10 +59,16 @@ cmNinjaNormalTargetGenerator(cmTarget* target)
     // ensure the directory exists (OutDir test)
     EnsureDirectoryExists(target->GetDirectory(this->GetConfigName()));
     }
+
+  this->OSXBundleGenerator = new cmOSXBundleGenerator(target,
+                                                      this->TargetNameOut,
+                                                      this->GetConfigName());
+  this->OSXBundleGenerator->SetMacContentFolders(&this->MacContentFolders);
 }
 
 cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator()
 {
+  delete this->OSXBundleGenerator;
 }
 
 void cmNinjaNormalTargetGenerator::Generate()
@@ -115,7 +125,10 @@ const char *cmNinjaNormalTargetGenerator::GetVisibleTypeName() const
     case cmTarget::SHARED_LIBRARY:
       return "shared library";
     case cmTarget::MODULE_LIBRARY:
-      return "shared module";
+      if (this->GetTarget()->IsCFBundleOnApple())
+        return "CFBundle shared module";
+      else
+        return "shared module";
     case cmTarget::EXECUTABLE:
       return "executable";
     default:
@@ -348,6 +361,40 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
 {
   cmTarget::TargetType targetType = this->GetTarget()->GetType();
 
+  std::string targetOutput = ConvertToNinjaPath(
+    this->GetTarget()->GetFullPath(this->GetConfigName()).c_str());
+  std::string targetOutputReal = ConvertToNinjaPath(
+    this->GetTarget()->GetFullPath(this->GetConfigName(),
+                                   /*implib=*/false,
+                                   /*realpath=*/true).c_str());
+  std::string targetOutputImplib = ConvertToNinjaPath(
+    this->GetTarget()->GetFullPath(this->GetConfigName(),
+                                   /*implib=*/true).c_str());
+
+  if (this->GetTarget()->IsAppBundleOnApple())
+    {
+    // Create the app bundle
+    std::string outpath;
+    this->OSXBundleGenerator->CreateAppBundle(this->TargetNameOut, outpath);
+
+    // Calculate the output path
+    targetOutput = outpath + this->TargetNameOut;
+    targetOutput = this->ConvertToNinjaPath(targetOutput.c_str());
+    targetOutputReal = outpath + this->TargetNameReal;
+    targetOutputReal = this->ConvertToNinjaPath(targetOutputReal.c_str());
+    }
+  else if (this->GetTarget()->IsFrameworkOnApple())
+    {
+    // Create the library framework.
+    this->OSXBundleGenerator->CreateFramework(this->TargetNameOut);
+    }
+  else if(this->GetTarget()->IsCFBundleOnApple())
+    {
+    // Create the core foundation bundle.
+    std::string outpath;
+    this->OSXBundleGenerator->CreateCFBundle(this->TargetNameOut, outpath);
+    }
+
   // Write comments.
   cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream());
   this->GetBuildFileStream()
@@ -360,16 +407,6 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement()
   cmNinjaDeps emptyDeps;
   cmNinjaVars vars;
 
-  std::string targetOutput = ConvertToNinjaPath(
-    this->GetTarget()->GetFullPath(this->GetConfigName()).c_str());
-  std::string targetOutputReal = ConvertToNinjaPath(
-    this->GetTarget()->GetFullPath(this->GetConfigName(),
-                                   /*implib=*/false,
-                                   /*realpath=*/true).c_str());
-  std::string targetOutputImplib = ConvertToNinjaPath(
-    this->GetTarget()->GetFullPath(this->GetConfigName(),
-                                   /*implib=*/true).c_str());
-
   // Compute the comment.
   cmOStringStream comment;
   comment << "Link the " << this->GetVisibleTypeName() << " "

+ 4 - 0
Source/cmNinjaNormalTargetGenerator.h

@@ -15,8 +15,12 @@
 
 #  include "cmNinjaTargetGenerator.h"
 #  include "cmNinjaTypes.h"
+#  include "cmStandardIncludes.h"
+
+#  include <set>
 
 class cmSourceFile;
+class cmOSXBundleGenerator;
 
 class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator
 {

+ 49 - 2
Source/cmNinjaTargetGenerator.cxx

@@ -56,7 +56,11 @@ cmNinjaTargetGenerator::New(cmTarget* target)
 }
 
 cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmTarget* target)
-  : Target(target),
+  :
+    MacOSXContentGenerator(0),
+    OSXBundleGenerator(0),
+    MacContentFolders(),
+    Target(target),
     Makefile(target->GetMakefile()),
     LocalGenerator(
       static_cast<cmLocalNinjaGenerator*>(Makefile->GetLocalGenerator())),
@@ -64,10 +68,12 @@ cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmTarget* target)
 {
   this->GeneratorTarget =
     this->GetGlobalGenerator()->GetGeneratorTarget(target);
+  MacOSXContentGenerator = new MacOSXContentGeneratorType(this);
 }
 
 cmNinjaTargetGenerator::~cmNinjaTargetGenerator()
 {
+  delete this->MacOSXContentGenerator;
 }
 
 cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const
@@ -87,7 +93,7 @@ cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const
 
 const char* cmNinjaTargetGenerator::GetConfigName() const
 {
-  return this->LocalGenerator->ConfigName.c_str();
+  return this->LocalGenerator->GetConfigName();
 }
 
 // TODO: Picked up from cmMakefileTargetGenerator.  Refactor it.
@@ -430,6 +436,12 @@ cmNinjaTargetGenerator
      cmCustomCommand const* cc = (*si)->GetCustomCommand();
      this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget());
      }
+  this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+    this->GeneratorTarget->HeaderSources,
+    this->MacOSXContentGenerator);
+  this->OSXBundleGenerator->GenerateMacOSXContentStatements(
+    this->GeneratorTarget->ExtraSources,
+    this->MacOSXContentGenerator);
   for(std::vector<cmSourceFile*>::const_iterator
         si = this->GeneratorTarget->ExternalObjects.begin();
       si != this->GeneratorTarget->ExternalObjects.end(); ++si)
@@ -640,3 +652,38 @@ cmNinjaTargetGenerator
 {
   EnsureDirectoryExists(cmSystemTools::GetParentDirectory(path.c_str()));
 }
+
+
+//----------------------------------------------------------------------------
+void
+cmNinjaTargetGenerator::MacOSXContentGeneratorType::operator()(
+  cmSourceFile& source, const char* pkgloc)
+{
+  // Skip OS X content when not building a Framework or Bundle.
+  if(this->Generator->OSXBundleGenerator->GetMacContentDirectory().empty())
+    {
+    return;
+    }
+
+  std::string macdir =
+    this->Generator->OSXBundleGenerator->InitMacOSXContentDirectory(pkgloc);
+
+  // Get the input file location.
+  std::string input = source.GetFullPath();
+  input =
+    this->Generator->GetLocalGenerator()->ConvertToNinjaPath(input.c_str());
+
+  // Get the output file location.
+  std::string output = macdir;
+  output += "/";
+  output += cmSystemTools::GetFilenameName(input);
+  output =
+    this->Generator->GetLocalGenerator()->ConvertToNinjaPath(output.c_str());
+
+  // Write a build statement to copy the content into the bundle.
+  this->Generator->GetGlobalGenerator()->WriteMacOSXContentBuild(input,
+                                                                 output);
+
+  // Add as a dependency of all target so that it gets called.
+  this->Generator->GetGlobalGenerator()->AddDependencyToAll(output);
+}

+ 22 - 0
Source/cmNinjaTargetGenerator.h

@@ -16,6 +16,7 @@
 #include "cmStandardIncludes.h"
 #include "cmNinjaTypes.h"
 #include "cmLocalNinjaGenerator.h"
+#include "cmOSXBundleGenerator.h"
 
 class cmTarget;
 class cmGlobalNinjaGenerator;
@@ -114,6 +115,27 @@ protected:
   void EnsureDirectoryExists(const std::string& dir);
   void EnsureParentDirectoryExists(const std::string& path);
 
+  // write rules for Mac OS X Application Bundle content.
+  struct MacOSXContentGeneratorType :
+    cmOSXBundleGenerator::MacOSXContentGeneratorType
+  {
+    MacOSXContentGeneratorType(cmNinjaTargetGenerator* g) :
+      Generator(g)  {}
+
+    void operator()(cmSourceFile& source, const char* pkgloc);
+
+  private:
+    cmNinjaTargetGenerator* Generator;
+  };
+  friend struct MacOSXContentGeneratorType;
+
+protected:
+  MacOSXContentGeneratorType* MacOSXContentGenerator;
+  // Properly initialized by sub-classes.
+  cmOSXBundleGenerator* OSXBundleGenerator;
+  std::set<cmStdString> MacContentFolders;
+
+
 private:
   cmTarget* Target;
   cmGeneratorTarget* GeneratorTarget;

+ 236 - 0
Source/cmOSXBundleGenerator.cxx

@@ -0,0 +1,236 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2012 Nicolas Despres <[email protected]>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#include "cmOSXBundleGenerator.h"
+#include "cmMakefile.h"
+#include "cmTarget.h"
+#include "cmLocalGenerator.h"
+
+#include <cassert>
+
+void cmOSXBundleGenerator::PrepareTargetProperties(cmTarget* target)
+{
+  if(target->IsCFBundleOnApple())
+    {
+    target->SetProperty("PREFIX", "");
+    target->SetProperty("SUFFIX", "");
+    }
+}
+
+//----------------------------------------------------------------------------
+cmOSXBundleGenerator::
+cmOSXBundleGenerator(cmTarget* target,
+                     std::string targetNameOut,
+                     const char* configName)
+ : Target(target)
+ , Makefile(target->GetMakefile())
+ , LocalGenerator(Makefile->GetLocalGenerator())
+ , TargetNameOut(targetNameOut)
+ , ConfigName(configName)
+ , MacContentDirectory()
+ , FrameworkVersion()
+ , MacContentFolders(0)
+{
+  if (this->MustSkip())
+    return;
+
+  this->MacContentDirectory =
+    this->Target->GetMacContentDirectory(this->ConfigName,
+                                         /*implib*/ false,
+                                         /*includeMacOS*/ false);
+  if(this->Target->IsFrameworkOnApple())
+    this->FrameworkVersion = this->Target->GetFrameworkVersion();
+}
+
+//----------------------------------------------------------------------------
+bool cmOSXBundleGenerator::MustSkip()
+{
+  return !this->Target->HaveWellDefinedOutputFiles();
+}
+
+//----------------------------------------------------------------------------
+void cmOSXBundleGenerator::CreateAppBundle(std::string& targetName,
+                                           std::string& outpath)
+{
+  if (this->MustSkip())
+    return;
+
+  // Compute bundle directory names.
+  outpath = this->MacContentDirectory;
+  outpath += "MacOS";
+  cmSystemTools::MakeDirectory(outpath.c_str());
+  outpath += "/";
+  this->Makefile->AddCMakeOutputFile(outpath.c_str());
+
+  // 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());
+  this->Makefile->AddCMakeOutputFile(plist.c_str());
+}
+
+//----------------------------------------------------------------------------
+void cmOSXBundleGenerator::CreateFramework(std::string const& targetName)
+{
+  if (this->MustSkip())
+    return;
+
+  assert(this->MacContentFolders);
+
+  // Configure the Info.plist file into the Resources directory.
+  this->MacContentFolders->insert("Resources");
+  std::string plist = this->MacContentDirectory + "Resources/Info.plist";
+  this->LocalGenerator->GenerateFrameworkInfoPList(this->Target,
+                                                   targetName.c_str(),
+                                                   plist.c_str());
+
+  // TODO: Use the cmMakefileTargetGenerator::ExtraFiles vector to
+  // drive rules to create these files at build time.
+  std::string oldName;
+  std::string newName;
+
+  // Compute the location of the top-level foo.framework directory.
+  std::string top = this->Target->GetDirectory(this->ConfigName);
+  top += "/";
+  top += this->TargetNameOut;
+  top += ".framework/";
+
+  // Make foo.framework/Versions
+  std::string versions = top;
+  versions += "Versions";
+  cmSystemTools::MakeDirectory(versions.c_str());
+
+  // Make foo.framework/Versions/version
+  std::string version = versions;
+  version += "/";
+  version += this->FrameworkVersion;
+  cmSystemTools::MakeDirectory(version.c_str());
+
+  // Current -> version
+  oldName = this->FrameworkVersion;
+  newName = versions;
+  newName += "/Current";
+  cmSystemTools::RemoveFile(newName.c_str());
+  cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
+  this->Makefile->AddCMakeOutputFile(newName.c_str());
+
+  // foo -> Versions/Current/foo
+  oldName = "Versions/Current/";
+  oldName += this->TargetNameOut;
+  newName = top;
+  newName += this->TargetNameOut;
+  cmSystemTools::RemoveFile(newName.c_str());
+  cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
+  this->Makefile->AddCMakeOutputFile(newName.c_str());
+
+  // Resources -> Versions/Current/Resources
+  if(this->MacContentFolders->find("Resources") !=
+     this->MacContentFolders->end())
+    {
+    oldName = "Versions/Current/Resources";
+    newName = top;
+    newName += "Resources";
+    cmSystemTools::RemoveFile(newName.c_str());
+    cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
+    this->Makefile->AddCMakeOutputFile(newName.c_str());
+    }
+
+  // Headers -> Versions/Current/Headers
+  if(this->MacContentFolders->find("Headers") !=
+     this->MacContentFolders->end())
+    {
+    oldName = "Versions/Current/Headers";
+    newName = top;
+    newName += "Headers";
+    cmSystemTools::RemoveFile(newName.c_str());
+    cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
+    this->Makefile->AddCMakeOutputFile(newName.c_str());
+    }
+
+  // PrivateHeaders -> Versions/Current/PrivateHeaders
+  if(this->MacContentFolders->find("PrivateHeaders") !=
+     this->MacContentFolders->end())
+    {
+    oldName = "Versions/Current/PrivateHeaders";
+    newName = top;
+    newName += "PrivateHeaders";
+    cmSystemTools::RemoveFile(newName.c_str());
+    cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
+    this->Makefile->AddCMakeOutputFile(newName.c_str());
+    }
+}
+
+//----------------------------------------------------------------------------
+void cmOSXBundleGenerator::CreateCFBundle(std::string& targetName,
+                                          std::string& outpath)
+{
+  if (this->MustSkip())
+    return;
+
+  // Compute bundle directory names.
+  outpath = this->MacContentDirectory;
+  outpath += "MacOS";
+  cmSystemTools::MakeDirectory(outpath.c_str());
+  outpath += "/";
+  this->Makefile->AddCMakeOutputFile(outpath.c_str());
+
+  // Configure the Info.plist file.  Note that it needs the executable name
+  // to be set.
+  std::string plist = this->MacContentDirectory;
+  plist += "Info.plist";
+  this->LocalGenerator->GenerateAppleInfoPList(this->Target,
+                                               targetName.c_str(),
+                                               plist.c_str());
+  this->Makefile->AddCMakeOutputFile(plist.c_str());
+}
+
+//----------------------------------------------------------------------------
+void
+cmOSXBundleGenerator::
+GenerateMacOSXContentStatements(std::vector<cmSourceFile*> const& sources,
+                                MacOSXContentGeneratorType* generator)
+{
+  if (this->MustSkip())
+    return;
+
+  for(std::vector<cmSourceFile*>::const_iterator
+        si = sources.begin(); si != sources.end(); ++si)
+    {
+    cmTarget::SourceFileFlags tsFlags =
+      this->Target->GetTargetSourceFileFlags(*si);
+    if(tsFlags.Type != cmTarget::SourceFileTypeNormal)
+      {
+      (*generator)(**si, tsFlags.MacFolder);
+      }
+    }
+}
+
+//----------------------------------------------------------------------------
+std::string
+cmOSXBundleGenerator::InitMacOSXContentDirectory(const char* pkgloc)
+{
+  // Construct the full path to the content subdirectory.
+  std::string macdir = this->MacContentDirectory;
+  macdir += pkgloc;
+  cmSystemTools::MakeDirectory(macdir.c_str());
+
+  // Record use of this content location.  Only the first level
+  // directory is needed.
+  {
+  std::string loc = pkgloc;
+  loc = loc.substr(0, loc.find('/'));
+  this->MacContentFolders->insert(loc);
+  }
+
+  return macdir;
+}

+ 71 - 0
Source/cmOSXBundleGenerator.h

@@ -0,0 +1,71 @@
+/*============================================================================
+  CMake - Cross Platform Makefile Generator
+  Copyright 2012 Nicolas Despres <[email protected]>
+
+  Distributed under the OSI-approved BSD License (the "License");
+  see accompanying file Copyright.txt for details.
+
+  This software is distributed WITHOUT ANY WARRANTY; without even the
+  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+  See the License for more information.
+============================================================================*/
+#ifndef cmOSXBundleGenerator_h
+#define cmOSXBundleGenerator_h
+
+#include "cmStandardIncludes.h"
+#include "cmSourceFile.h"
+
+#include <string>
+#include <set>
+
+class cmTarget;
+class cmMakefile;
+class cmLocalGenerator;
+
+class cmOSXBundleGenerator
+{
+public:
+  static void PrepareTargetProperties(cmTarget* target);
+
+  cmOSXBundleGenerator(cmTarget* target,
+                       std::string targetNameOut,
+                       const char* configName);
+
+  void CreateAppBundle(std::string& targetName, std::string& outpath);
+  void CreateFramework(std::string const& targetName);
+  void CreateCFBundle(std::string& targetName, std::string& outpath);
+
+  struct MacOSXContentGeneratorType
+  {
+    virtual ~MacOSXContentGeneratorType() {}
+    virtual void operator()(cmSourceFile& source, const char* pkgloc) = 0;
+  };
+
+  void GenerateMacOSXContentStatements(
+    std::vector<cmSourceFile*> const& sources,
+    MacOSXContentGeneratorType* generator);
+  std::string InitMacOSXContentDirectory(const char* pkgloc);
+
+  std::string GetMacContentDirectory() const
+  { return this->MacContentDirectory; }
+  std::string GetFrameworkVersion() const
+  { return this->FrameworkVersion; }
+  void SetMacContentFolders(std::set<cmStdString>* macContentFolders)
+  { this->MacContentFolders = macContentFolders; }
+
+private:
+  bool MustSkip();
+
+private:
+  cmTarget* Target;
+  cmMakefile* Makefile;
+  cmLocalGenerator* LocalGenerator;
+  std::string TargetNameOut;
+  const char* ConfigName;
+  std::string MacContentDirectory;
+  std::string FrameworkVersion;
+  std::set<cmStdString>* MacContentFolders;
+};
+
+
+#endif

+ 72 - 40
Source/cmTarget.cxx

@@ -2482,6 +2482,16 @@ void cmTarget::MarkAsImported()
   this->IsImportedTarget = true;
 }
 
+//----------------------------------------------------------------------------
+bool cmTarget::HaveWellDefinedOutputFiles()
+{
+  return
+    this->GetType() == cmTarget::STATIC_LIBRARY ||
+    this->GetType() == cmTarget::SHARED_LIBRARY ||
+    this->GetType() == cmTarget::MODULE_LIBRARY ||
+    this->GetType() == cmTarget::EXECUTABLE;
+}
+
 //----------------------------------------------------------------------------
 cmTarget::OutputInfo const* cmTarget::GetOutputInfo(const char* config)
 {
@@ -2492,10 +2502,7 @@ cmTarget::OutputInfo const* cmTarget::GetOutputInfo(const char* config)
     }
 
   // Only libraries and executables have well-defined output files.
-  if(this->GetType() != cmTarget::STATIC_LIBRARY &&
-     this->GetType() != cmTarget::SHARED_LIBRARY &&
-     this->GetType() != cmTarget::MODULE_LIBRARY &&
-     this->GetType() != cmTarget::EXECUTABLE)
+  if(!this->HaveWellDefinedOutputFiles())
     {
     std::string msg = "cmTarget::GetOutputInfo called for ";
     msg += this->GetName();
@@ -2586,18 +2593,7 @@ const char* cmTarget::NormalGetLocation(const char* config)
     this->Location += cfgid;
     this->Location += "/";
     }
-  if(this->IsAppBundleOnApple())
-    {
-    this->Location += this->GetFullName(config, false);
-    this->Location += ".app/Contents/MacOS/";
-    }
-   if(this->IsFrameworkOnApple())
-    {
-    this->Location += this->GetFullName(config, false);
-    this->Location += ".framework/Versions/";
-    this->Location += this->GetFrameworkVersion();
-    this->Location += "/";
-    }
+  this->Location = this->BuildMacContentDirectory(this->Location, config);
   this->Location += this->GetFullName(config, false);
   return this->Location.c_str();
 }
@@ -3169,22 +3165,7 @@ std::string cmTarget::GetFullPath(const char* config, bool implib,
 std::string cmTarget::NormalGetFullPath(const char* config, bool implib,
                                         bool realname)
 {
-  // Start with the output directory for the target.
-  std::string fpath = this->GetDirectory(config, implib);
-  fpath += "/";
-
-  if(this->IsAppBundleOnApple())
-    {
-    fpath += this->GetFullName(config, false);
-    fpath += ".app/Contents/MacOS/";
-    }
-  if(this->IsFrameworkOnApple())
-    {
-    fpath += this->GetFullName(config, false);
-    fpath += ".framework/Versions/";
-    fpath += this->GetFrameworkVersion();
-    fpath += "/";
-    }
+  std::string fpath = this->GetMacContentDirectory(config, implib);
 
   // Add the full name of the target.
   if(implib)
@@ -3707,10 +3688,7 @@ std::string cmTarget::GetInstallNameDirForBuildTree(const char* config,
     dir += "/";
     if(this->IsFrameworkOnApple() && !for_xcode)
       {
-      dir += this->GetFullName(config, false);
-      dir += ".framework/Versions/";
-      dir += this->GetFrameworkVersion();
-      dir += "/";
+      dir += this->GetFrameworkDirectory(config);
       }
     return dir;
     }
@@ -3741,10 +3719,7 @@ std::string cmTarget::GetInstallNameDirForInstallTree(const char* config,
 
     if(this->IsFrameworkOnApple() && !for_xcode)
       {
-      dir += this->GetFullName(config, false);
-      dir += ".framework/Versions/";
-      dir += this->GetFrameworkVersion();
-      dir += "/";
+      dir += this->GetFrameworkDirectory(config);
       }
 
     return dir;
@@ -4733,6 +4708,63 @@ std::vector<std::string> cmTarget::GetIncludeDirectories()
   return orderedAndUniqueIncludes;
 }
 
+//----------------------------------------------------------------------------
+std::string cmTarget::GetFrameworkDirectory(const char* config)
+{
+  std::string fpath;
+  fpath += this->GetFullName(config, false);
+  fpath += ".framework/Versions/";
+  fpath += this->GetFrameworkVersion();
+  fpath += "/";
+  return fpath;
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::BuildMacContentDirectory(const std::string& base,
+                                               const char* config,
+                                               bool includeMacOS)
+{
+  std::string fpath = base;
+  if(this->IsAppBundleOnApple())
+    {
+    fpath += this->GetFullName(config, false);
+    fpath += ".app/Contents/";
+    if(includeMacOS)
+      fpath += "MacOS/";
+    }
+  if(this->IsFrameworkOnApple())
+    {
+    fpath += this->GetFrameworkDirectory(config);
+    }
+  if(this->IsCFBundleOnApple())
+    {
+    fpath += this->GetFullName(config, false);
+    fpath += ".";
+    const char *ext = this->GetProperty("BUNDLE_EXTENSION");
+    if (!ext)
+      {
+      ext = "bundle";
+      }
+    fpath += ext;
+    fpath += "/Contents/";
+    if(includeMacOS)
+      fpath += "MacOS/";
+    }
+  return fpath;
+}
+
+//----------------------------------------------------------------------------
+std::string cmTarget::GetMacContentDirectory(const char* config,
+                                             bool implib,
+                                             bool includeMacOS)
+{
+  // Start with the output directory for the target.
+  std::string fpath = this->GetDirectory(config, implib);
+  fpath += "/";
+  fpath = this->BuildMacContentDirectory(fpath, config, includeMacOS);
+  return fpath;
+}
+
 //----------------------------------------------------------------------------
 cmTargetLinkInformationMap
 ::cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r): derived()

+ 16 - 0
Source/cmTarget.h

@@ -465,6 +465,22 @@ public:
   /** Get the include directories for this target.  */
   std::vector<std::string> GetIncludeDirectories();
 
+  /** Append to @a base the mac content directory and return it. */
+  std::string BuildMacContentDirectory(const std::string& base,
+                                       const char* config = 0,
+                                       bool includeMacOS = true);
+
+  /** @return the mac content directory for this target. */
+  std::string GetMacContentDirectory(const char* config = 0,
+                                     bool implib = false,
+                                     bool includeMacOS = true);
+
+  /** @return whether this target have a well defined output file name. */
+  bool HaveWellDefinedOutputFiles();
+
+  /** @return the Mac framework directory without the base. */
+  std::string GetFrameworkDirectory(const char* config = 0);
+
 private:
   /**
    * A list of direct dependencies. Use in conjunction with DependencyMap.

+ 1 - 5
Source/cmake.cxx

@@ -84,10 +84,8 @@
 #else
 #endif
 #include "cmGlobalUnixMakefileGenerator3.h"
+#include "cmGlobalNinjaGenerator.h"
 
-#ifdef CMAKE_USE_NINJA
-#  include "cmGlobalNinjaGenerator.h"
-#endif
 
 #if defined(CMAKE_HAVE_VS_GENERATORS)
 #include "cmCallVisualStudioMacro.h"
@@ -2600,10 +2598,8 @@ void cmake::AddDefaultGenerators()
 #endif
   this->Generators[cmGlobalUnixMakefileGenerator3::GetActualName()] =
     &cmGlobalUnixMakefileGenerator3::New;
-#ifdef CMAKE_USE_NINJA
   this->Generators[cmGlobalNinjaGenerator::GetActualName()] =
     &cmGlobalNinjaGenerator::New;
-#endif
 #ifdef CMAKE_USE_XCODE
   this->Generators[cmGlobalXCodeGenerator::GetActualName()] =
     &cmGlobalXCodeGenerator::New;

+ 34 - 32
Tests/CMakeLists.txt

@@ -1408,42 +1408,44 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/
     LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/VSMidl")
   ENDIF(${CMAKE_TEST_GENERATOR} MATCHES "Visual Studio")
 
-  IF (APPLE AND CMAKE_COMPILER_IS_GNUCXX)
-    SET(BundleTestInstallDir
-      "${CMake_BINARY_DIR}/Tests/BundleTest/InstallDirectory")
-    ADD_TEST(BundleTest ${CMAKE_CTEST_COMMAND}
-      --build-and-test
-      "${CMake_SOURCE_DIR}/Tests/BundleTest"
-      "${CMake_BINARY_DIR}/Tests/BundleTest"
-      --build-two-config
-      --build-generator ${CMAKE_TEST_GENERATOR}
-      --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
-      --build-project BundleTest
-      --build-target install
-#     --build-target package
-      --build-options "-DCMAKE_INSTALL_PREFIX:PATH=${BundleTestInstallDir}"
-       "-DCMake_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}"
-      --test-command
-      ${BundleTestInstallDir}/Applications/SecondBundleExe.app/Contents/MacOS/SecondBundleExe)
-    LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BundleTest")
-
-    ADD_TEST(CFBundleTest ${CMAKE_CTEST_COMMAND}
-      --build-and-test
-      "${CMake_SOURCE_DIR}/Tests/CFBundleTest"
-      "${CMake_BINARY_DIR}/Tests/CFBundleTest"
-      --build-two-config
-      --build-generator ${CMAKE_TEST_GENERATOR}
-      --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
-      --build-project CFBundleTest
-      --test-command
-      ${CMAKE_CMAKE_COMMAND} -DCTEST_CONFIGURATION_TYPE=\${CTEST_CONFIGURATION_TYPE}
+  IF (APPLE)
+    if (CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+      SET(BundleTestInstallDir
+        "${CMake_BINARY_DIR}/Tests/BundleTest/InstallDirectory")
+      ADD_TEST(BundleTest ${CMAKE_CTEST_COMMAND}
+        --build-and-test
+        "${CMake_SOURCE_DIR}/Tests/BundleTest"
+        "${CMake_BINARY_DIR}/Tests/BundleTest"
+        --build-two-config
+        --build-generator ${CMAKE_TEST_GENERATOR}
+        --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
+        --build-project BundleTest
+        --build-target install
+#       --build-target package
+        --build-options "-DCMAKE_INSTALL_PREFIX:PATH=${BundleTestInstallDir}"
+        "-DCMake_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}"
+        --test-command
+        ${BundleTestInstallDir}/Applications/SecondBundleExe.app/Contents/MacOS/SecondBundleExe)
+      LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BundleTest")
+
+      ADD_TEST(CFBundleTest ${CMAKE_CTEST_COMMAND}
+        --build-and-test
+        "${CMake_SOURCE_DIR}/Tests/CFBundleTest"
+        "${CMake_BINARY_DIR}/Tests/CFBundleTest"
+        --build-two-config
+        --build-generator ${CMAKE_TEST_GENERATOR}
+        --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM}
+        --build-project CFBundleTest
+        --test-command
+        ${CMAKE_CMAKE_COMMAND} -DCTEST_CONFIGURATION_TYPE=\${CTEST_CONFIGURATION_TYPE}
         -Ddir=${CMake_BINARY_DIR}/Tests/CFBundleTest
         -Dgen=${CMAKE_TEST_GENERATOR}
         -P ${CMake_SOURCE_DIR}/Tests/CFBundleTest/VerifyResult.cmake)
-    LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CFBundleTest")
+      LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CFBundleTest")
 
-    ADD_TEST_MACRO(ObjC++ ObjC++)
-  ENDIF (APPLE AND CMAKE_COMPILER_IS_GNUCXX)
+      ADD_TEST_MACRO(ObjC++ ObjC++)
+    ENDIF (CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
+  ENDIF (APPLE)
 
   IF(APPLE AND CTEST_TEST_CPACK)
     ADD_TEST(BundleGeneratorTest ${CMAKE_CTEST_COMMAND}

+ 14 - 8
bootstrap

@@ -72,14 +72,14 @@ else
   cmake_system_darwin=false
 fi
 
-# Determine whether this is BeOS 
+# Determine whether this is BeOS
 if echo "${cmake_system}" | grep BeOS >/dev/null 2>&1; then
   cmake_system_beos=true
 else
   cmake_system_beos=false
 fi
 
-# Determine whether this is Haiku 
+# Determine whether this is Haiku
 if echo "${cmake_system}" | grep Haiku >/dev/null 2>&1; then
   cmake_system_haiku=true
 else
@@ -220,6 +220,7 @@ CMAKE_CXX_SOURCES="\
   cmMakefileLibraryTargetGenerator \
   cmMakefileTargetGenerator \
   cmMakefileUtilityTargetGenerator \
+  cmOSXBundleGenerator \
   cmNewLineStyle \
   cmBootstrapCommands \
   cmCommands \
@@ -238,6 +239,11 @@ CMAKE_CXX_SOURCES="\
   cmExprLexer \
   cmExprParser \
   cmExprParserHelper \
+  cmGlobalNinjaGenerator \
+  cmLocalNinjaGenerator \
+  cmNinjaTargetGenerator \
+  cmNinjaNormalTargetGenerator \
+  cmNinjaUtilityTargetGenerator \
 "
 
 if ${cmake_system_mingw}; then
@@ -351,7 +357,7 @@ cmake_error()
   res=$1
   shift 1
   echo "---------------------------------------------"
-  echo "Error when bootstrapping CMake:" 
+  echo "Error when bootstrapping CMake:"
   echo "$*"
   echo "---------------------------------------------"
   if [ -f cmake_bootstrap.log ]; then
@@ -370,7 +376,7 @@ cmake_replace_string ()
   SEARCHFOR="$3"
   REPLACEWITH="$4"
   if [ -f "${INFILE}" ] || ${cmake_system_openvms}; then
-    cat "${INFILE}" | 
+    cat "${INFILE}" |
       sed "s/\@${SEARCHFOR}\@/${REPLACEWITH}/g" > "${OUTFILE}${_tmp}"
     if [ -f "${OUTFILE}${_tmp}" ]; then
       if "${_diff}" "${OUTFILE}" "${OUTFILE}${_tmp}" > /dev/null 2> /dev/null ; then
@@ -393,7 +399,7 @@ cmake_kwsys_config_replace_string ()
   APPEND="$*"
   if [ -f "${INFILE}" ] || ${cmake_system_openvms}; then
     echo "${APPEND}" > "${OUTFILE}${_tmp}"
-    cat "${INFILE}" | 
+    cat "${INFILE}" |
       sed "/./ {s/\@KWSYS_NAMESPACE\@/cmsys/g;
                 s/@KWSYS_BUILD_SHARED@/${KWSYS_BUILD_SHARED}/g;
                 s/@KWSYS_LFS_AVAILABLE@/${KWSYS_LFS_AVAILABLE}/g;
@@ -797,7 +803,7 @@ echo '
 # include <iostream.h>
 #endif
 
-class NeedCXX 
+class NeedCXX
 {
 public:
   NeedCXX() { this->Foo = 1; }
@@ -1387,12 +1393,12 @@ cmake_kwsys_config_replace_string \
   "${cmake_bootstrap_dir}/cmsys/Configure.h" \
   "${cmake_compiler_settings_comment}"
 
-for a in ${KWSYS_FILES}; do 
+for a in ${KWSYS_FILES}; do
   cmake_replace_string "${cmake_source_dir}/Source/kwsys/${a}.in" \
      "${cmake_bootstrap_dir}/cmsys/${a}" KWSYS_NAMESPACE cmsys
 done
 
-for a in ${KWSYS_IOS_FILES}; do 
+for a in ${KWSYS_IOS_FILES}; do
   cmake_replace_string "${cmake_source_dir}/Source/kwsys/kwsys_ios_${a}.h.in" \
      "${cmake_bootstrap_dir}/cmsys/ios/${a}" KWSYS_NAMESPACE cmsys
 done