فهرست منبع

ENH: Add support for adding content to bundles

Andy Cedilnik 19 سال پیش
والد
کامیت
40272a16bd

+ 2 - 0
Modules/Platform/Darwin.cmake

@@ -47,6 +47,8 @@ IF(NOT XCODE)
   SET(CMAKE_SHARED_LIBRARY_SONAME_CXX_FLAG "-install_name")
 ENDIF(NOT XCODE)
 
+SET(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
+
 SET(CMAKE_C_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS -w)
 SET(CMAKE_CXX_CREATE_SHARED_LIBRARY_FORBIDDEN_FLAGS -w)
 SET(CMAKE_C_CREATE_SHARED_LIBRARY

+ 48 - 4
Source/cmLocalUnixMakefileGenerator3.cxx

@@ -1542,15 +1542,54 @@ cmLocalUnixMakefileGenerator3
     {
     objectName = objectName.substr(0, dot_pos);
     }
-  objectName +=
-    this->GlobalGenerator->GetLanguageOutputExtensionFromExtension(
-      source.GetSourceExtension().c_str());
+  if ( source.GetPropertyAsBool("KEEP_EXTENSION") )
+    {
+    if ( !source.GetSourceExtension().empty() )
+      {
+      objectName += "." + source.GetSourceExtension();
+      }
+    }
+  else
+    {
+    objectName +=
+      this->GlobalGenerator->GetLanguageOutputExtensionFromExtension(
+        source.GetSourceExtension().c_str());
+    }
 
   // Convert to a safe name.
   objectName = this->CreateSafeUniqueObjectFileName(objectName.c_str());
 
   // Prepend the target directory.
-  std::string obj = this->GetTargetDirectory(target);
+  std::string obj;
+  const char* fileTargetDirectory = source.GetProperty("MACOSX_PACKAGE_LOCATION");
+  if ( fileTargetDirectory )
+    {
+    std::string targetName;
+    std::string targetNameReal;
+    target.GetExecutableNames(targetName, targetNameReal,
+                                   this->ConfigurationName.c_str());
+    if ( target.GetPropertyAsBool("MACOSX_BUNDLE") )
+      {
+      // Construct the full path version of the names.
+      obj = this->ExecutableOutputPath;
+      if(obj.empty())
+        {
+        obj = this->Makefile->GetStartOutputDirectory();
+        obj += "/";
+        }
+      obj += targetName + ".app/Contents/";
+      obj += fileTargetDirectory;
+      }
+    else
+      {
+      // Framework not handled yet
+      abort();
+      }
+    }
+  else
+    {
+    obj = this->GetTargetDirectory(target);
+    }
   obj += "/";
   obj += objectName;
   if(nameWithoutTargetDir)
@@ -1763,6 +1802,11 @@ const char*
 cmLocalUnixMakefileGenerator3
 ::GetSourceFileLanguage(const cmSourceFile& source)
 {
+  const char* lang = source.GetProperty("LANGUAGE");
+  if ( lang )
+    {
+    return lang;
+    }
   // Identify the language of the source file.
   return (this->GlobalGenerator
           ->GetLanguageFromExtension(source.GetSourceExtension().c_str()));

+ 32 - 13
Source/cmMakefileExecutableTargetGenerator.cxx

@@ -28,7 +28,7 @@ void cmMakefileExecutableTargetGenerator::WriteRuleFiles()
 {
   // create the build.make file and directory, put in the common blocks
   this->CreateRuleFile();
-  
+
   // Add in any rules for custom commands
   this->WriteCustomCommandsForTarget();
 
@@ -82,8 +82,8 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   // Add a dependency on the rule file itself.
   this->LocalGenerator->AppendRuleDepend(depends,
                                          this->BuildFileNameFull.c_str());
-  
-  for(std::vector<std::string>::const_iterator obj = 
+
+  for(std::vector<std::string>::const_iterator obj =
         this->ExternalObjects.begin();
       obj != this->ExternalObjects.end(); ++obj)
     {
@@ -111,13 +111,13 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
     // Make bundle directories
     outpath += targetName;
     outpath += ".app/Contents/MacOS/";
-    std::string f1 = 
+    std::string f1 =
       this->Makefile->GetModulesFile("MacOSXBundleInfo.plist.in");
     if ( f1.size() == 0 )
       {
       cmSystemTools::Error("could not find Mac OSX bundle template file.");
       }
-    std::string macdir = 
+    std::string macdir =
       this->Makefile->GetSafeDefinition("EXECUTABLE_OUTPUT_PATH");
     if ( macdir.size() == 0 )
       {
@@ -130,6 +130,25 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
     macdir += targetName;
     macdir += ".app/Contents/";
 
+    std::vector<cmSourceFile*>::iterator sourceIt;
+    for ( sourceIt = this->Target->GetSourceFiles().begin();
+      sourceIt != this->Target->GetSourceFiles().end();
+      ++ sourceIt )
+      {
+      const char* subDir = (*sourceIt)->GetProperty("MACOSX_PACKAGE_LOCATION");
+      if ( subDir )
+        {
+        std::string newDir = macdir;
+        newDir += subDir;
+        if ( !cmSystemTools::MakeDirectory(newDir.c_str()) )
+          {
+          cmSystemTools::Error("Cannot create a subdirectory for \"",
+            newDir.c_str(), "\".");
+          return;
+          }
+        }
+      }
+
     // Configure the Info.plist file.  Note that it needs the executable name
     // to be set.
     std::string f2 = macdir + "Info.plist";
@@ -232,7 +251,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
                                           cmLocalGenerator::START_OUTPUT,
                                           cmLocalGenerator::UNCHANGED));
     }
-  } 
+  }
 
   // Add a command to remove any existing files for this executable.
   std::vector<std::string> commands1;
@@ -240,7 +259,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
                                            *this->Target, "target");
   this->LocalGenerator->CreateCDCommand(commands1,
                                         this->Makefile->GetStartOutputDirectory(),
-                                        this->Makefile->GetHomeOutputDirectory()); 
+                                        this->Makefile->GetHomeOutputDirectory());
   commands.insert(commands.end(), commands1.begin(), commands1.end());
   commands1.clear();
 
@@ -257,7 +276,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   std::string linkRuleVar = "CMAKE_";
   linkRuleVar += linkLanguage;
   linkRuleVar += "_LINK_EXECUTABLE";
-  std::string linkRule = 
+  std::string linkRule =
     this->Makefile->GetRequiredDefinition(linkRuleVar.c_str());
   cmSystemTools::ExpandListArgument(linkRule, commands1);
   this->LocalGenerator->CreateCDCommand
@@ -317,9 +336,9 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
     }
 
   // Write the build rule.
-  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 
+  this->LocalGenerator->WriteMakeRule(*this->BuildFileStream,
                                       0,
-                                      targetFullPathReal.c_str(), 
+                                      targetFullPathReal.c_str(),
                                       depends, commands, false);
 
   // The symlink name for the target should depend on the real target
@@ -331,7 +350,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
     commands.clear();
     depends.push_back(targetFullPathReal.c_str());
     this->LocalGenerator->WriteMakeRule(*this->BuildFileStream, 0,
-                                        targetFullPath.c_str(), 
+                                        targetFullPath.c_str(),
                                         depends, commands, false);
     }
 
@@ -341,11 +360,11 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink)
   dir += this->LocalGenerator->GetTargetDirectory(*this->Target);
   std::string buildTargetRuleName = dir;
   buildTargetRuleName += relink?"/preinstall":"/build";
-  buildTargetRuleName = 
+  buildTargetRuleName =
     this->Convert(buildTargetRuleName.c_str(),
                   cmLocalGenerator::HOME_OUTPUT,
                   cmLocalGenerator::MAKEFILE);
-  this->LocalGenerator->WriteConvenienceRule(*this->BuildFileStream, 
+  this->LocalGenerator->WriteConvenienceRule(*this->BuildFileStream,
                                              targetFullPath.c_str(),
                                              buildTargetRuleName.c_str());
 

+ 9 - 2
Source/cmMakefileTargetGenerator.cxx

@@ -237,8 +237,6 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules()
     }
 }
 
-
-
 //----------------------------------------------------------------------------
 void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source)
 {
@@ -282,6 +280,10 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source)
     (this->LocalGenerator->ConvertToFullPath(dir).c_str());
   
   // Save this in the target's list of object files.
+  if ( source.GetPropertyAsBool("EXTRA_CONTENT") )
+    {
+    this->ExtraContent.insert(obj);
+    }
   this->Objects.push_back(obj);
   std::string relativeObj = this->LocalGenerator->GetHomeRelativeOutputPath();
   relativeObj += obj;
@@ -587,6 +589,7 @@ void cmMakefileTargetGenerator
     }
 }
 
+//----------------------------------------------------------------------------
 void cmMakefileTargetGenerator::WriteCustomCommands()
 {
   // add custom commands to the clean rules?
@@ -667,6 +670,10 @@ cmMakefileTargetGenerator
   for(std::vector<std::string>::const_iterator i = this->Objects.begin();
       i != this->Objects.end(); ++i)
     {
+    if ( this->ExtraContent.find(i->c_str()) != this->ExtraContent.end() )
+      {
+      continue;
+      }
     *this->BuildFileStream << " " << lineContinue << "\n";
     if(objName)
       {

+ 17 - 16
Source/cmMakefileTargetGenerator.h

@@ -34,7 +34,7 @@ class cmSourceFile;
  * \brief Support Routines for writing makefiles
  *
  */
-class cmMakefileTargetGenerator 
+class cmMakefileTargetGenerator
 {
 public:
   // constructor to set the ivars
@@ -49,12 +49,12 @@ public:
   /* the main entry point for this class. Writes the Makefiles associated
      with this target */
   virtual void WriteRuleFiles() = 0;
-  
+
 protected:
 
   // create the file and directory etc
   void CreateRuleFile();
-  
+
   // outputs the rules for any custom commands used by this target
   void WriteCustomCommandsForTarget();
 
@@ -75,38 +75,38 @@ protected:
 
   // write the build rule for an object
   void WriteObjectBuildFile(std::string &obj,
-                            const char *lang, 
+                            const char *lang,
                             cmSourceFile& source,
                             std::vector<std::string>& depends);
-  
+
   // write the depend.make file for an object
   void WriteObjectDependRules(cmSourceFile& source,
                               std::vector<std::string>& depends);
-  
+
   // this is responsible for writing all of the rules for all this
   // directories custom commands (but not utility targets)
   void WriteCustomCommands();
   void GenerateCustomRuleFile(const cmCustomCommand& cc);
-  
+
   // write out the variable that lists the objects for this target
   void WriteObjectsVariable(std::string& variableName,
                             std::string& variableNameExternal);
-  
+
   // Return the a string with -F flags on apple
   std::string GetFrameworkFlags();
-  
+
   // append intertarget dependencies
   void AppendTargetDepends(std::vector<std::string>& depends);
 
   virtual void CloseFileStreams();
-  void RemoveForbiddenFlags(const char* flagVar, const char* linkLang, 
+  void RemoveForbiddenFlags(const char* flagVar, const char* linkLang,
                             std::string& linkFlags);
   cmStdString TargetName;
   cmTarget *Target;
   cmLocalUnixMakefileGenerator3 *LocalGenerator;
   cmGlobalGenerator *GlobalGenerator;
   cmMakefile *Makefile;
-  
+
   // the full path to the build file
   std::string BuildFileName;
   std::string BuildFileNameFull;
@@ -132,19 +132,20 @@ protected:
   // objects used by this target
   std::vector<std::string> Objects;
   std::vector<std::string> ExternalObjects;
+  std::set<std::string> ExtraContent;
 
   // Set of object file names that will be built in this directory.
   std::set<cmStdString> ObjectFiles;
 
 
   //==================================================================
-  // Convenience routines that do nothing more than forward to 
+  // Convenience routines that do nothing more than forward to
   // implementaitons
-  std::string Convert(const char* source, 
-                      cmLocalGenerator::RelativeRoot relative, 
-                      cmLocalGenerator::OutputFormat output = 
+  std::string Convert(const char* source,
+                      cmLocalGenerator::RelativeRoot relative,
+                      cmLocalGenerator::OutputFormat output =
                       cmLocalGenerator::UNCHANGED,
-                      bool optional = false) 
+                      bool optional = false)
   {
     return this->LocalGenerator->Convert(source, relative, output, optional);
   }

+ 33 - 7
Source/cmSetSourceFilesPropertiesCommand.cxx

@@ -9,8 +9,8 @@
   Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
   See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
 
-     This software is distributed WITHOUT ANY WARRANTY; without even 
-     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
      PURPOSE.  See the above copyright notices for more information.
 
 =========================================================================*/
@@ -63,7 +63,8 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass(
       ++j;
       if(j == args.end())
         {
-        this->SetError("called with incorrect number of arguments COMPILE_FLAGS with no flags");
+        this->SetError("called with incorrect number of arguments "
+          "COMPILE_FLAGS with no flags");
         return false;
         }
       propertyPairs.push_back(*j);
@@ -85,6 +86,7 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass(
       {
       // now loop through the rest of the arguments, new style
       ++j;
+      bool dontPush = false;
       while (j != args.end())
         {
         propertyPairs.push_back(*j);
@@ -96,6 +98,25 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass(
             generated = true;
             }
           }
+        else if(*j == "MACOSX_PACKAGE_LOCATION")
+          {
+          doingFiles = false;
+          ++j;
+          if(j == args.end())
+            {
+            this->SetError("called with incorrect number of arguments "
+              "MACOSX_PACKAGE_LOCATION with no flags");
+            return false;
+            }
+          propertyPairs.push_back(*j);
+          propertyPairs.push_back("EXTRA_CONTENT");
+          propertyPairs.push_back("1");
+          propertyPairs.push_back("KEEP_EXTENSION");
+          propertyPairs.push_back("1");
+          propertyPairs.push_back("LANGUAGE");
+          propertyPairs.push_back("MacOSX_Content");
+          dontPush = true;
+          }
         else
           {
           ++j;
@@ -105,8 +126,12 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass(
           this->SetError("called with incorrect number of arguments.");
           return false;
           }
-        propertyPairs.push_back(*j);
+        if ( !dontPush )
+          {
+          propertyPairs.push_back(*j);
+          }
         ++j;
+        dontPush = false;
         }
       // break out of the loop because j is already == end
       break;
@@ -117,16 +142,17 @@ bool cmSetSourceFilesPropertiesCommand::InitialPass(
       }
     else
       {
-      this->SetError("called with illegal arguments, maybe missing a PROPERTIES specifier?");
+      this->SetError("called with illegal arguments, maybe missing a "
+        "PROPERTIES specifier?");
       return false;
       }
     }
-  
+
   // now loop over all the files
   int i;
   unsigned int k;
   for(i = 0; i < numFiles; ++i)
-    {   
+    {
     // get the source file
     cmSourceFile* sf =
       this->Makefile->GetOrCreateSource(args[i].c_str(), generated);

+ 28 - 1
Tests/BundleTest/CMakeLists.txt

@@ -1,9 +1,36 @@
 PROJECT(BundleTest)
 SET(MACOSX_BUNDLE_INFO_STRING "bundle_info_string")
+SET(CMAKE_MacOSX_Content_COMPILE_OBJECT "\"${CMAKE_COMMAND}\" -E copy_if_different <SOURCE> <OBJECT>")
+
+ADD_CUSTOM_COMMAND(
+  OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+  COMMAND /bin/cp
+  ARGS "${CMAKE_CURRENT_SOURCE_DIR}/randomResourceFile.plist.in"
+  "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist")
+
+SET_SOURCE_FILES_PROPERTIES(
+  "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+  PROPERTIES
+  MACOSX_PACKAGE_LOCATION Resources
+  )
+
+SET_SOURCE_FILES_PROPERTIES(
+  SomeRandomFile.txt
+  PROPERTIES
+  MACOSX_PACKAGE_LOCATION MacOS
+  )
+
+SET(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/foobar")
 
 # Test building a bundle linking to a shared library.
 ADD_LIBRARY(BundleTestLib SHARED BundleLib.cxx)
-ADD_EXECUTABLE(BundleTest MACOSX_BUNDLE BundleTest.cxx)
+ADD_EXECUTABLE(BundleTest
+  MACOSX_BUNDLE
+  BundleTest.cxx
+  SomeRandomFile.txt
+  "${CMAKE_CURRENT_BINARY_DIR}/randomResourceFile.plist"
+  )
+
 TARGET_LINK_LIBRARIES(BundleTest BundleTestLib)
 
 # Test bundle installation.

+ 0 - 0
Tests/BundleTest/SomeRandomFile.txt


+ 9 - 0
Tests/BundleTest/randomResourceFile.plist.in

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>Package</key>
+	<string>CMake</string>
+</dict>
+</plist>
+