/*============================================================================ CMake - Cross Platform Makefile Generator Copyright 2012 Nicolas Despres 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 //---------------------------------------------------------------------------- cmOSXBundleGenerator:: cmOSXBundleGenerator(cmGeneratorTarget* target, const char* configName) : Target(target->Target) , Makefile(target->Target->GetMakefile()) , LocalGenerator(Makefile->GetLocalGenerator()) , ConfigName(configName) , MacContentFolders(0) { if (this->MustSkip()) return; } //---------------------------------------------------------------------------- bool cmOSXBundleGenerator::MustSkip() { return !this->Target->HaveWellDefinedOutputFiles(); } //---------------------------------------------------------------------------- void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName, std::string& outpath) { if (this->MustSkip()) return; // Compute bundle directory names. std::string out = outpath; out += "/"; out += this->Target->GetAppBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); std::string newoutpath = out; // Configure the Info.plist file. Note that it needs the executable name // to be set. std::string plist = outpath; plist += "/"; plist += this->Target->GetAppBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; this->LocalGenerator->GenerateAppleInfoPList(this->Target, targetName.c_str(), plist.c_str()); this->Makefile->AddCMakeOutputFile(plist); outpath = newoutpath; } //---------------------------------------------------------------------------- void cmOSXBundleGenerator::CreateFramework( const std::string& targetName, const std::string& outpath) { if (this->MustSkip()) return; assert(this->MacContentFolders); // Compute the location of the top-level foo.framework directory. std::string contentdir = outpath + "/" + this->Target->GetFrameworkDirectory(this->ConfigName, true); contentdir += "/"; std::string newoutpath = outpath + "/" + this->Target->GetFrameworkDirectory(this->ConfigName, false); std::string frameworkVersion = this->Target->GetFrameworkVersion(); // Configure the Info.plist file into the Resources directory. this->MacContentFolders->insert("Resources"); std::string plist = newoutpath; plist += "/Resources/Info.plist"; std::string name = cmSystemTools::GetFilenameName(targetName); this->LocalGenerator->GenerateFrameworkInfoPList(this->Target, name.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; // Make foo.framework/Versions std::string versions = contentdir; versions += "Versions"; cmSystemTools::MakeDirectory(versions.c_str()); // Make foo.framework/Versions/version cmSystemTools::MakeDirectory(newoutpath.c_str()); // Current -> version oldName = frameworkVersion; newName = versions; newName += "/Current"; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); this->Makefile->AddCMakeOutputFile(newName); // foo -> Versions/Current/foo oldName = "Versions/Current/"; oldName += name; newName = contentdir; newName += name; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); this->Makefile->AddCMakeOutputFile(newName); // Resources -> Versions/Current/Resources if(this->MacContentFolders->find("Resources") != this->MacContentFolders->end()) { oldName = "Versions/Current/Resources"; newName = contentdir; newName += "Resources"; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); this->Makefile->AddCMakeOutputFile(newName); } // Headers -> Versions/Current/Headers if(this->MacContentFolders->find("Headers") != this->MacContentFolders->end()) { oldName = "Versions/Current/Headers"; newName = contentdir; newName += "Headers"; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); this->Makefile->AddCMakeOutputFile(newName); } // PrivateHeaders -> Versions/Current/PrivateHeaders if(this->MacContentFolders->find("PrivateHeaders") != this->MacContentFolders->end()) { oldName = "Versions/Current/PrivateHeaders"; newName = contentdir; newName += "PrivateHeaders"; cmSystemTools::RemoveFile(newName.c_str()); cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str()); this->Makefile->AddCMakeOutputFile(newName); } } //---------------------------------------------------------------------------- void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName, const std::string& root) { if (this->MustSkip()) return; // Compute bundle directory names. std::string out = root; out += "/"; out += this->Target->GetCFBundleDirectory(this->ConfigName, false); cmSystemTools::MakeDirectory(out.c_str()); this->Makefile->AddCMakeOutputFile(out); // Configure the Info.plist file. Note that it needs the executable name // to be set. std::string plist = root + "/" + this->Target->GetCFBundleDirectory(this->ConfigName, true); plist += "/Info.plist"; this->LocalGenerator->GenerateAppleInfoPList(this->Target, targetName.c_str(), plist.c_str()); this->Makefile->AddCMakeOutputFile(plist); } //---------------------------------------------------------------------------- void cmOSXBundleGenerator:: GenerateMacOSXContentStatements(std::vector const& sources, MacOSXContentGeneratorType* generator) { if (this->MustSkip()) return; for(std::vector::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->Target->GetMacContentDirectory(this->ConfigName, /*implib*/ false); macdir += "/"; 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; }