packaging: Initial packaging
[platform/upstream/cmake.git] / Source / cmSourceFileLocation.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
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 "cmSourceFileLocation.h"
13
14 #include "cmMakefile.h"
15 #include "cmLocalGenerator.h"
16 #include "cmGlobalGenerator.h"
17 #include "cmSystemTools.h"
18
19 //----------------------------------------------------------------------------
20 cmSourceFileLocation
21 ::cmSourceFileLocation(cmMakefile* mf, const char* name): Makefile(mf)
22 {
23   this->AmbiguousDirectory = !cmSystemTools::FileIsFullPath(name);
24   this->AmbiguousExtension = true;
25   this->Directory = cmSystemTools::GetFilenamePath(name);
26   this->Name = cmSystemTools::GetFilenameName(name);
27   this->UpdateExtension(name);
28 }
29
30 //----------------------------------------------------------------------------
31 void cmSourceFileLocation::Update(const char* name)
32 {
33   if(this->AmbiguousDirectory)
34     {
35     this->UpdateDirectory(name);
36     }
37   if(this->AmbiguousExtension)
38     {
39     this->UpdateExtension(name);
40     }
41 }
42
43 //----------------------------------------------------------------------------
44 void cmSourceFileLocation::Update(cmSourceFileLocation const& loc)
45 {
46   if(this->AmbiguousDirectory && !loc.AmbiguousDirectory)
47     {
48     this->Directory = loc.Directory;
49     this->AmbiguousDirectory = false;
50     }
51   if(this->AmbiguousExtension && !loc.AmbiguousExtension)
52     {
53     this->Name = loc.Name;
54     this->AmbiguousExtension = false;
55     }
56 }
57
58 //----------------------------------------------------------------------------
59 void cmSourceFileLocation::DirectoryUseSource()
60 {
61   if(this->AmbiguousDirectory)
62     {
63     this->Directory =
64       cmSystemTools::CollapseFullPath(
65         this->Directory.c_str(), this->Makefile->GetCurrentDirectory());
66     this->AmbiguousDirectory = false;
67     }
68 }
69
70 //----------------------------------------------------------------------------
71 void cmSourceFileLocation::DirectoryUseBinary()
72 {
73   if(this->AmbiguousDirectory)
74     {
75     this->Directory =
76       cmSystemTools::CollapseFullPath(
77         this->Directory.c_str(), this->Makefile->GetCurrentOutputDirectory());
78     this->AmbiguousDirectory = false;
79     }
80 }
81
82 //----------------------------------------------------------------------------
83 void cmSourceFileLocation::UpdateExtension(const char* name)
84 {
85   // Check the extension.
86   std::string ext = cmSystemTools::GetFilenameLastExtension(name);
87   if(!ext.empty()) { ext = ext.substr(1); }
88
89   // The global generator checks extensions of enabled languages.
90   cmGlobalGenerator* gg =
91     this->Makefile->GetLocalGenerator()->GetGlobalGenerator();
92   cmMakefile* mf = this->Makefile;
93   const std::vector<std::string>& srcExts = mf->GetSourceExtensions();
94   const std::vector<std::string>& hdrExts = mf->GetHeaderExtensions();
95   if(gg->GetLanguageFromExtension(ext.c_str()) ||
96      std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end() ||
97      std::find(hdrExts.begin(), hdrExts.end(), ext) != hdrExts.end())
98     {
99     // This is a known extension.  Use the given filename with extension.
100     this->Name = cmSystemTools::GetFilenameName(name);
101     this->AmbiguousExtension = false;
102     }
103   else
104     {
105     // This is not a known extension.  See if the file exists on disk as
106     // named.
107     std::string tryPath;
108     if(this->AmbiguousDirectory)
109       {
110       // Check the source tree only because a file in the build tree should
111       // be specified by full path at least once.  We do not want this
112       // detection to depend on whether the project has already been built.
113       tryPath = this->Makefile->GetCurrentDirectory();
114       tryPath += "/";
115       }
116     if(!this->Directory.empty())
117       {
118       tryPath += this->Directory;
119       tryPath += "/";
120       }
121     tryPath += this->Name;
122     if(cmSystemTools::FileExists(tryPath.c_str(), true))
123       {
124       // We found a source file named by the user on disk.  Trust it's
125       // extension.
126       this->Name = cmSystemTools::GetFilenameName(name);
127       this->AmbiguousExtension = false;
128
129       // If the directory was ambiguous, it isn't anymore.
130       if(this->AmbiguousDirectory)
131         {
132         this->DirectoryUseSource();
133         }
134       }
135     }
136 }
137
138 //----------------------------------------------------------------------------
139 void cmSourceFileLocation::UpdateDirectory(const char* name)
140 {
141   // If a full path was given we know the directory.
142   if(cmSystemTools::FileIsFullPath(name))
143     {
144     this->Directory = cmSystemTools::GetFilenamePath(name);
145     this->AmbiguousDirectory = false;
146     }
147 }
148
149 //----------------------------------------------------------------------------
150 bool
151 cmSourceFileLocation
152 ::MatchesAmbiguousExtension(cmSourceFileLocation const& loc) const
153 {
154   // This location's extension is not ambiguous but loc's extension
155   // is.  See if the names match as-is.
156   if(this->Name == loc.Name)
157     {
158     return true;
159     }
160
161   // Check if loc's name could possibly be extended to our name by
162   // adding an extension.
163   if(!(this->Name.size() > loc.Name.size() &&
164        this->Name.substr(0, loc.Name.size()) == loc.Name &&
165        this->Name[loc.Name.size()] == '.'))
166     {
167     return false;
168     }
169
170   // Only a fixed set of extensions will be tried to match a file on
171   // disk.  One of these must match if loc refers to this source file.
172   std::string ext = this->Name.substr(loc.Name.size()+1);
173   cmMakefile* mf = this->Makefile;
174   const std::vector<std::string>& srcExts = mf->GetSourceExtensions();
175   if(std::find(srcExts.begin(), srcExts.end(), ext) != srcExts.end())
176     {
177     return true;
178     }
179   const std::vector<std::string>& hdrExts = mf->GetHeaderExtensions();
180   if(std::find(hdrExts.begin(), hdrExts.end(), ext) != hdrExts.end())
181     {
182     return true;
183     }
184   return false;
185 }
186
187 //----------------------------------------------------------------------------
188 bool cmSourceFileLocation::Matches(cmSourceFileLocation const& loc)
189 {
190   if(this->AmbiguousExtension && loc.AmbiguousExtension)
191     {
192     // Both extensions are ambiguous.  Since only the old fixed set of
193     // extensions will be tried, the names must match at this point to
194     // be the same file.
195     if(this->Name != loc.Name)
196       {
197       return false;
198       }
199     }
200   else if(this->AmbiguousExtension)
201     {
202     // Only "this" extension is ambiguous.
203     if(!loc.MatchesAmbiguousExtension(*this))
204       {
205       return false;
206       }
207     }
208   else if(loc.AmbiguousExtension)
209     {
210     // Only "loc" extension is ambiguous.
211     if(!this->MatchesAmbiguousExtension(loc))
212       {
213       return false;
214       }
215     }
216   else
217     {
218     // Neither extension is ambiguous.
219     if(this->Name != loc.Name)
220       {
221       return false;
222       }
223     }
224
225   if(!this->AmbiguousDirectory && !loc.AmbiguousDirectory)
226     {
227     // Both sides have absolute directories.
228     if(this->Directory != loc.Directory)
229       {
230       return false;
231       }
232     }
233   else if(this->AmbiguousDirectory && loc.AmbiguousDirectory &&
234           this->Makefile == loc.Makefile)
235     {
236     // Both sides have directories relative to the same location.
237     if(this->Directory != loc.Directory)
238       {
239       return false;
240       }
241     }
242   else if(this->AmbiguousDirectory && loc.AmbiguousDirectory)
243     {
244     // Each side has a directory relative to a different location.
245     // This can occur when referencing a source file from a different
246     // directory.  This is not yet allowed.
247     this->Makefile->IssueMessage(
248       cmake::INTERNAL_ERROR,
249       "Matches error: Each side has a directory relative to a different "
250       "location. This can occur when referencing a source file from a "
251       "different directory.  This is not yet allowed."
252       );
253     return false;
254     }
255   else if(this->AmbiguousDirectory)
256     {
257     // Compare possible directory combinations.
258     std::string srcDir =
259       cmSystemTools::CollapseFullPath(
260         this->Directory.c_str(), this->Makefile->GetCurrentDirectory());
261     std::string binDir =
262       cmSystemTools::CollapseFullPath(
263         this->Directory.c_str(), this->Makefile->GetCurrentOutputDirectory());
264     if(srcDir != loc.Directory &&
265        binDir != loc.Directory)
266       {
267       return false;
268       }
269     }
270   else if(loc.AmbiguousDirectory)
271     {
272     // Compare possible directory combinations.
273     std::string srcDir =
274       cmSystemTools::CollapseFullPath(
275         loc.Directory.c_str(), loc.Makefile->GetCurrentDirectory());
276     std::string binDir =
277       cmSystemTools::CollapseFullPath(
278         loc.Directory.c_str(), loc.Makefile->GetCurrentOutputDirectory());
279     if(srcDir != this->Directory &&
280        binDir != this->Directory)
281       {
282       return false;
283       }
284     }
285
286   // File locations match.
287   this->Update(loc);
288   return true;
289 }