packaging: Initial packaging
[platform/upstream/cmake.git] / Source / cmOSXBundleGenerator.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2012 Nicolas Despres <nicolas.despres@gmail.com>
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmOSXBundleGenerator.h"
13 #include "cmMakefile.h"
14 #include "cmTarget.h"
15 #include "cmLocalGenerator.h"
16
17 #include <cassert>
18
19 //----------------------------------------------------------------------------
20 cmOSXBundleGenerator::
21 cmOSXBundleGenerator(cmTarget* target,
22                      const char* configName)
23  : Target(target)
24  , Makefile(target->GetMakefile())
25  , LocalGenerator(Makefile->GetLocalGenerator())
26  , ConfigName(configName)
27  , MacContentFolders(0)
28 {
29   if (this->MustSkip())
30     return;
31
32 }
33
34 //----------------------------------------------------------------------------
35 bool cmOSXBundleGenerator::MustSkip()
36 {
37   return !this->Target->HaveWellDefinedOutputFiles();
38 }
39
40 //----------------------------------------------------------------------------
41 void cmOSXBundleGenerator::CreateAppBundle(const std::string& targetName,
42                                            std::string& outpath)
43 {
44   if (this->MustSkip())
45     return;
46
47   // Compute bundle directory names.
48   std::string out = outpath;
49   out += "/";
50   out += this->Target->GetAppBundleDirectory(this->ConfigName, false);
51   cmSystemTools::MakeDirectory(out.c_str());
52   this->Makefile->AddCMakeOutputFile(out);
53
54   std::string newoutpath = out;
55
56   // Configure the Info.plist file.  Note that it needs the executable name
57   // to be set.
58   std::string plist = outpath;
59   plist += "/";
60   plist += this->Target->GetAppBundleDirectory(this->ConfigName, true);
61   plist += "/Info.plist";
62   this->LocalGenerator->GenerateAppleInfoPList(this->Target,
63                                                targetName.c_str(),
64                                                plist.c_str());
65   this->Makefile->AddCMakeOutputFile(plist);
66   outpath = newoutpath;
67 }
68
69 //----------------------------------------------------------------------------
70 void cmOSXBundleGenerator::CreateFramework(
71   const std::string& targetName, const std::string& outpath)
72 {
73   if (this->MustSkip())
74     return;
75
76   assert(this->MacContentFolders);
77
78   // Compute the location of the top-level foo.framework directory.
79   std::string contentdir = outpath + "/" +
80     this->Target->GetFrameworkDirectory(this->ConfigName, true);
81   contentdir += "/";
82
83   std::string newoutpath = outpath + "/" +
84     this->Target->GetFrameworkDirectory(this->ConfigName, false);
85
86   std::string frameworkVersion = this->Target->GetFrameworkVersion();
87
88   // Configure the Info.plist file into the Resources directory.
89   this->MacContentFolders->insert("Resources");
90   std::string plist = newoutpath;
91   plist += "/Resources/Info.plist";
92   std::string name = cmSystemTools::GetFilenameName(targetName);
93   this->LocalGenerator->GenerateFrameworkInfoPList(this->Target,
94                                                    name.c_str(),
95                                                    plist.c_str());
96
97   // TODO: Use the cmMakefileTargetGenerator::ExtraFiles vector to
98   // drive rules to create these files at build time.
99   std::string oldName;
100   std::string newName;
101
102
103   // Make foo.framework/Versions
104   std::string versions = contentdir;
105   versions += "Versions";
106   cmSystemTools::MakeDirectory(versions.c_str());
107
108   // Make foo.framework/Versions/version
109   cmSystemTools::MakeDirectory(newoutpath.c_str());
110
111   // Current -> version
112   oldName = frameworkVersion;
113   newName = versions;
114   newName += "/Current";
115   cmSystemTools::RemoveFile(newName.c_str());
116   cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
117   this->Makefile->AddCMakeOutputFile(newName);
118
119   // foo -> Versions/Current/foo
120   oldName = "Versions/Current/";
121   oldName += name;
122   newName = contentdir;
123   newName += name;
124   cmSystemTools::RemoveFile(newName.c_str());
125   cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
126   this->Makefile->AddCMakeOutputFile(newName);
127
128   // Resources -> Versions/Current/Resources
129   if(this->MacContentFolders->find("Resources") !=
130      this->MacContentFolders->end())
131     {
132     oldName = "Versions/Current/Resources";
133     newName = contentdir;
134     newName += "Resources";
135     cmSystemTools::RemoveFile(newName.c_str());
136     cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
137     this->Makefile->AddCMakeOutputFile(newName);
138     }
139
140   // Headers -> Versions/Current/Headers
141   if(this->MacContentFolders->find("Headers") !=
142      this->MacContentFolders->end())
143     {
144     oldName = "Versions/Current/Headers";
145     newName = contentdir;
146     newName += "Headers";
147     cmSystemTools::RemoveFile(newName.c_str());
148     cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
149     this->Makefile->AddCMakeOutputFile(newName);
150     }
151
152   // PrivateHeaders -> Versions/Current/PrivateHeaders
153   if(this->MacContentFolders->find("PrivateHeaders") !=
154      this->MacContentFolders->end())
155     {
156     oldName = "Versions/Current/PrivateHeaders";
157     newName = contentdir;
158     newName += "PrivateHeaders";
159     cmSystemTools::RemoveFile(newName.c_str());
160     cmSystemTools::CreateSymlink(oldName.c_str(), newName.c_str());
161     this->Makefile->AddCMakeOutputFile(newName);
162     }
163 }
164
165 //----------------------------------------------------------------------------
166 void cmOSXBundleGenerator::CreateCFBundle(const std::string& targetName,
167                                           const std::string& root)
168 {
169   if (this->MustSkip())
170     return;
171
172   // Compute bundle directory names.
173   std::string out = root;
174   out += "/";
175   out += this->Target->GetCFBundleDirectory(this->ConfigName, false);
176   cmSystemTools::MakeDirectory(out.c_str());
177   this->Makefile->AddCMakeOutputFile(out);
178
179   // Configure the Info.plist file.  Note that it needs the executable name
180   // to be set.
181   std::string plist =
182     this->Target->GetCFBundleDirectory(this->ConfigName, true);
183   plist += "/Info.plist";
184   this->LocalGenerator->GenerateAppleInfoPList(this->Target,
185                                                targetName.c_str(),
186                                                plist.c_str());
187   this->Makefile->AddCMakeOutputFile(plist);
188 }
189
190 //----------------------------------------------------------------------------
191 void
192 cmOSXBundleGenerator::
193 GenerateMacOSXContentStatements(std::vector<cmSourceFile*> const& sources,
194                                 MacOSXContentGeneratorType* generator)
195 {
196   if (this->MustSkip())
197     return;
198
199   for(std::vector<cmSourceFile*>::const_iterator
200         si = sources.begin(); si != sources.end(); ++si)
201     {
202     cmTarget::SourceFileFlags tsFlags =
203       this->Target->GetTargetSourceFileFlags(*si);
204     if(tsFlags.Type != cmTarget::SourceFileTypeNormal)
205       {
206       (*generator)(**si, tsFlags.MacFolder);
207       }
208     }
209 }
210
211 //----------------------------------------------------------------------------
212 std::string
213 cmOSXBundleGenerator::InitMacOSXContentDirectory(const char* pkgloc)
214 {
215   // Construct the full path to the content subdirectory.
216
217   std::string macdir =
218     this->Target->GetMacContentDirectory(this->ConfigName,
219                                          /*implib*/ false);
220   macdir += "/";
221   macdir += pkgloc;
222   cmSystemTools::MakeDirectory(macdir.c_str());
223
224   // Record use of this content location.  Only the first level
225   // directory is needed.
226   {
227   std::string loc = pkgloc;
228   loc = loc.substr(0, loc.find('/'));
229   this->MacContentFolders->insert(loc);
230   }
231
232   return macdir;
233 }