1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmSourceFile.cxx,v $
6 Date: $Date: 2008-09-22 13:42:27 $
7 Version: $Revision: 1.53 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmSourceFile.h"
19 #include "cmGlobalGenerator.h"
20 #include "cmLocalGenerator.h"
21 #include "cmMakefile.h"
22 #include "cmSystemTools.h"
25 //----------------------------------------------------------------------------
26 cmSourceFile::cmSourceFile(cmMakefile
* mf
, const char* name
):
29 this->CustomCommand
= 0;
30 this->Properties
.SetCMakeInstance(mf
->GetCMakeInstance());
31 this->FindFullPathFailed
= false;
34 //----------------------------------------------------------------------------
35 cmSourceFile::~cmSourceFile()
37 this->SetCustomCommand(0);
40 //----------------------------------------------------------------------------
41 std::string
const& cmSourceFile::GetExtension() const
43 return this->Extension
;
46 //----------------------------------------------------------------------------
47 const char* cmSourceFile::GetLanguage()
49 // If the language was set explicitly by the user then use it.
50 if(const char* lang
= this->GetProperty("LANGUAGE"))
55 // Perform computation needed to get the language if necessary.
56 if(this->FullPath
.empty() && this->Language
.empty())
58 // If a known extension is given or a known full path is given
59 // then trust that the current extension is sufficient to
60 // determine the language. This will fail only if the user
61 // specifies a full path to the source but leaves off the
62 // extension, which is kind of weird.
63 if(this->Location
.ExtensionIsAmbiguous() &&
64 this->Location
.DirectoryIsAmbiguous())
66 // Finalize the file location to get the extension and set the
72 // Use the known extension to get the language if possible.
74 cmSystemTools::GetFilenameLastExtension(this->Location
.GetName());
75 this->CheckLanguage(ext
);
79 // Now try to determine the language.
80 return static_cast<cmSourceFile
const*>(this)->GetLanguage();
83 //----------------------------------------------------------------------------
84 const char* cmSourceFile::GetLanguage() const
86 // If the language was set explicitly by the user then use it.
87 if(const char* lang
= this->GetProperty("LANGUAGE"))
92 // If the language was determined from the source file extension use it.
93 if(!this->Language
.empty())
95 return this->Language
.c_str();
98 // The language is not known.
102 //----------------------------------------------------------------------------
103 cmSourceFileLocation
const& cmSourceFile::GetLocation() const
105 return this->Location
;
108 //----------------------------------------------------------------------------
109 std::string
const& cmSourceFile::GetFullPath()
111 if(this->FullPath
.empty())
113 if(this->FindFullPath())
115 this->CheckExtension();
118 return this->FullPath
;
121 //----------------------------------------------------------------------------
122 std::string
const& cmSourceFile::GetFullPath() const
124 return this->FullPath
;
127 //----------------------------------------------------------------------------
128 bool cmSourceFile::FindFullPath()
130 // If thie method has already failed once do not try again.
131 if(this->FindFullPathFailed
)
136 // If the file is generated compute the location without checking on
138 if(this->GetPropertyAsBool("GENERATED"))
140 // The file is either already a full path or is relative to the
141 // build directory for the target.
142 this->Location
.DirectoryUseBinary();
143 this->FullPath
= this->Location
.GetDirectory();
144 this->FullPath
+= "/";
145 this->FullPath
+= this->Location
.GetName();
149 // The file is not generated. It must exist on disk.
150 cmMakefile
* mf
= this->Location
.GetMakefile();
151 const char* tryDirs
[3] = {0, 0, 0};
152 if(this->Location
.DirectoryIsAmbiguous())
154 tryDirs
[0] = mf
->GetCurrentDirectory();
155 tryDirs
[1] = mf
->GetCurrentOutputDirectory();
161 const std::vector
<std::string
>& srcExts
= mf
->GetSourceExtensions();
162 const std::vector
<std::string
>& hdrExts
= mf
->GetHeaderExtensions();
163 for(const char* const* di
= tryDirs
; *di
; ++di
)
165 std::string tryPath
= this->Location
.GetDirectory();
170 tryPath
+= this->Location
.GetName();
171 tryPath
= cmSystemTools::CollapseFullPath(tryPath
.c_str(), *di
);
172 if(this->TryFullPath(tryPath
.c_str(), 0))
176 for(std::vector
<std::string
>::const_iterator ei
= srcExts
.begin();
177 ei
!= srcExts
.end(); ++ei
)
179 if(this->TryFullPath(tryPath
.c_str(), ei
->c_str()))
184 for(std::vector
<std::string
>::const_iterator ei
= hdrExts
.begin();
185 ei
!= hdrExts
.end(); ++ei
)
187 if(this->TryFullPath(tryPath
.c_str(), ei
->c_str()))
195 e
<< "Cannot find source file \"" << this->Location
.GetName() << "\"";
196 e
<< ". Tried extensions";
197 for(std::vector
<std::string
>::const_iterator ext
= srcExts
.begin();
198 ext
!= srcExts
.end(); ++ext
)
202 for(std::vector
<std::string
>::const_iterator ext
= hdrExts
.begin();
203 ext
!= hdrExts
.end(); ++ext
)
207 this->Location
.GetMakefile()->IssueMessage(cmake::FATAL_ERROR
, e
.str());
208 this->FindFullPathFailed
= true;
212 //----------------------------------------------------------------------------
213 bool cmSourceFile::TryFullPath(const char* tp
, const char* ext
)
215 std::string tryPath
= tp
;
221 if(cmSystemTools::FileExists(tryPath
.c_str()))
223 this->FullPath
= tryPath
;
229 //----------------------------------------------------------------------------
230 void cmSourceFile::CheckExtension()
232 // Compute the extension.
233 std::string realExt
=
234 cmSystemTools::GetFilenameLastExtension(this->FullPath
);
237 // Store the extension without the leading '.'.
238 this->Extension
= realExt
.substr(1);
241 // Look for object files.
242 if(this->Extension
== "obj" ||
243 this->Extension
== "o" ||
244 this->Extension
== "lo")
246 this->SetProperty("EXTERNAL_OBJECT", "1");
249 // Look for header files.
250 cmMakefile
* mf
= this->Location
.GetMakefile();
251 const std::vector
<std::string
>& hdrExts
= mf
->GetHeaderExtensions();
252 if(std::find(hdrExts
.begin(), hdrExts
.end(), this->Extension
) ==
255 // This is not a known header file extension. Mark it as not a
256 // header unless the user has already explicitly set the property.
257 if(!this->GetProperty("HEADER_FILE_ONLY"))
259 this->SetProperty("HEADER_FILE_ONLY", "0");
264 // This is a known header file extension. The source cannot be compiled.
265 this->SetProperty("HEADER_FILE_ONLY", "1");
268 // Try to identify the source file language from the extension.
269 if(this->Language
.empty())
271 this->CheckLanguage(this->Extension
);
275 //----------------------------------------------------------------------------
276 void cmSourceFile::CheckLanguage(std::string
const& ext
)
278 // Try to identify the source file language from the extension.
279 cmMakefile
* mf
= this->Location
.GetMakefile();
280 cmGlobalGenerator
* gg
= mf
->GetLocalGenerator()->GetGlobalGenerator();
281 if(const char* l
= gg
->GetLanguageFromExtension(ext
.c_str()))
287 //----------------------------------------------------------------------------
288 bool cmSourceFile::Matches(cmSourceFileLocation
const& loc
)
290 return this->Location
.Matches(loc
);
293 //----------------------------------------------------------------------------
294 void cmSourceFile::SetProperty(const char* prop
, const char* value
)
301 this->Properties
.SetProperty(prop
, value
, cmProperty::SOURCE_FILE
);
304 //----------------------------------------------------------------------------
305 void cmSourceFile::AppendProperty(const char* prop
, const char* value
)
311 this->Properties
.AppendProperty(prop
, value
, cmProperty::SOURCE_FILE
);
314 //----------------------------------------------------------------------------
315 const char* cmSourceFile::GetPropertyForUser(const char *prop
)
317 // This method is a consequence of design history and backwards
318 // compatibility. GetProperty is (and should be) a const method.
319 // Computed properties should not be stored back in the property map
320 // but instead reference information already known. If they need to
321 // cache information in a mutable ivar to provide the return string
322 // safely then so be it.
324 // The LOCATION property is particularly problematic. The CMake
325 // language has very loose restrictions on the names that will match
326 // a given source file (for historical reasons). Implementing
327 // lookups correctly with such loose naming requires the
328 // cmSourceFileLocation class to commit to a particular full path to
329 // the source file as late as possible. If the users requests the
330 // LOCATION property we must commit now.
331 if(strcmp(prop
, "LOCATION") == 0)
333 // Commit to a location.
337 // Perform the normal property lookup.
338 return this->GetProperty(prop
);
341 //----------------------------------------------------------------------------
342 const char* cmSourceFile::GetProperty(const char* prop
) const
344 // Check for computed properties.
345 if(strcmp(prop
, "LOCATION") == 0)
347 if(this->FullPath
.empty())
353 return this->FullPath
.c_str();
359 this->Properties
.GetPropertyValue(prop
, cmProperty::SOURCE_FILE
, chain
);
362 cmMakefile
* mf
= this->Location
.GetMakefile();
363 return mf
->GetProperty(prop
,cmProperty::SOURCE_FILE
);
369 //----------------------------------------------------------------------------
370 bool cmSourceFile::GetPropertyAsBool(const char* prop
) const
372 return cmSystemTools::IsOn(this->GetProperty(prop
));
375 //----------------------------------------------------------------------------
376 cmCustomCommand
* cmSourceFile::GetCustomCommand()
378 return this->CustomCommand
;
381 //----------------------------------------------------------------------------
382 cmCustomCommand
const* cmSourceFile::GetCustomCommand() const
384 return this->CustomCommand
;
387 //----------------------------------------------------------------------------
388 void cmSourceFile::SetCustomCommand(cmCustomCommand
* cc
)
390 cmCustomCommand
* old
= this->CustomCommand
;
391 this->CustomCommand
= cc
;
395 //----------------------------------------------------------------------------
396 void cmSourceFile::DefineProperties(cmake
*cm
)
400 ("ABSTRACT", cmProperty::SOURCE_FILE
,
401 "Is this source file an abstract class.",
402 "A property on a source file that indicates if the source file "
403 "represents a class that is abstract. This only makes sense for "
404 "languages that have a notion of an abstract class and it is "
405 "only used by some tools that wrap classes into other languages.");
408 ("COMPILE_FLAGS", cmProperty::SOURCE_FILE
,
409 "Additional flags to be added when compiling this source file.",
410 "These flags will be added to the list of compile flags when "
411 "this source file builds. Use COMPILE_DEFINITIONS to pass additional "
412 "preprocessor definitions.");
415 ("COMPILE_DEFINITIONS", cmProperty::SOURCE_FILE
,
416 "Preprocessor definitions for compiling a source file.",
417 "The COMPILE_DEFINITIONS property may be set to a list of preprocessor "
418 "definitions using the syntax VAR or VAR=value. Function-style "
419 "definitions are not supported. CMake will automatically escape "
420 "the value correctly for the native build system (note that CMake "
421 "language syntax may require escapes to specify some values). "
422 "This property may be set on a per-configuration basis using the name "
423 "COMPILE_DEFINITIONS_<CONFIG> where <CONFIG> is an upper-case name "
424 "(ex. \"COMPILE_DEFINITIONS_DEBUG\").\n"
425 "CMake will automatically drop some definitions that "
426 "are not supported by the native build tool. "
427 "The VS6 IDE does not support definitions with values "
428 "(but NMake does). Xcode does not support per-configuration "
429 "definitions on source files.\n"
430 "Dislaimer: Most native build tools have poor support for escaping "
431 "certain values. CMake has work-arounds for many cases but some "
432 "values may just not be possible to pass correctly. If a value "
433 "does not seem to be escaped correctly, do not attempt to "
434 "work-around the problem by adding escape sequences to the value. "
435 "Your work-around may break in a future version of CMake that "
436 "has improved escape support. Instead consider defining the macro "
437 "in a (configured) header file. Then report the limitation.");
441 ("COMPILE_DEFINITIONS_<CONFIG>", cmProperty::SOURCE_FILE
,
442 "Per-configuration preprocessor definitions on a source file.",
443 "This is the configuration-specific version of "
444 "COMPILE_DEFINITIONS. Note that Xcode does not support "
445 "per-configuration source file flags so this property will "
446 "be ignored by the Xcode generator.");
449 ("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE
,
450 "If set to true then this is an object file.",
451 "If this property is set to true then the source file "
452 "is really an object file and should not be compiled. "
453 "It will still be linked into the target though.");
456 ("GENERATED", cmProperty::SOURCE_FILE
,
457 "Is this source file generated as part of the build process.",
458 "If a source file is generated by the build process CMake will "
459 "handle it differently in temrs of dependency checking etc. "
460 "Otherwise having a non-existent source file could create problems.");
463 ("HEADER_FILE_ONLY", cmProperty::SOURCE_FILE
,
464 "Is this source file only a header file.",
465 "A property on a source file that indicates if the source file "
466 "is a header file with no associated implementation. This is "
467 "set automatically based on the file extension and is used by "
468 "CMake to determine is certain dependency information should be "
472 ("KEEP_EXTENSION", cmProperty::SOURCE_FILE
,
473 "Make the output file have the same extension as the source file.",
474 "If this property is set then the file extension of the output "
475 "file will be the same as that of the source file. Normally "
476 "the output file extension is computed based on the language "
477 "of the source file, for example .cxx will go to a .o extension.");
480 ("LANGUAGE", cmProperty::SOURCE_FILE
,
481 "What programming language is the file.",
482 "A property that can be set to indicate what programming language "
483 "the source file is. If it is not set the language is determined "
484 "based on the file extension. Typical values are CXX C etc.");
487 ("LOCATION", cmProperty::SOURCE_FILE
,
488 "The full path to a source file.",
489 "A read only property on a SOURCE FILE that contains the full path "
490 "to the source file.");
493 ("MACOSX_PACKAGE_LOCATION", cmProperty::SOURCE_FILE
,
494 "Place a source file inside a Mac OS X bundle or framework.",
495 "Executable targets with the MACOSX_BUNDLE property set are built "
496 "as Mac OS X application bundles on Apple platforms. "
497 "Shared library targets with the FRAMEWORK property set are built "
498 "as Mac OS X frameworks on Apple platforms. "
499 "Source files listed in the target with this property set will "
500 "be copied to a directory inside the bundle or framework content "
501 "folder specified by the property value. "
502 "For bundles the content folder is \"<name>.app/Contents\". "
503 "For frameworks the content folder is "
504 "\"<name>.framework/Versions/<version>\". "
505 "See the PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE target "
506 "properties for specifying files meant for Headers, PrivateHeadres, "
507 "or Resources directories.");
510 ("OBJECT_DEPENDS", cmProperty::SOURCE_FILE
,
511 "Additional files on which a compiled object file depends.",
512 "Specifies a semicolon-separated list of full-paths to files on which "
513 "any object files compiled from this source file depend. "
514 "An object file will be recompiled if any of the named files is newer "
516 "This property need not be used to specify the dependency of a "
517 "source file on a generated header file that it includes. "
518 "Although the property was originally introduced for this purpose, it "
519 "is no longer necessary. "
520 "If the generated header file is created by a custom command in the "
521 "same target as the source file, the automatic dependency scanning "
522 "process will recognize the dependency. "
523 "If the generated header file is created by another target, an "
524 "inter-target dependency should be created with the add_dependencies "
525 "command (if one does not already exist due to linking relationships).");
528 ("OBJECT_OUTPUTS", cmProperty::SOURCE_FILE
,
529 "Additional outputs for a Makefile rule.",
530 "Additional outputs created by compilation of this source file. "
531 "If any of these outputs is missing the object will be recompiled. "
532 "This is supported only on Makefile generators and will be ignored "
533 "on other generators.");
536 ("SYMBOLIC", cmProperty::SOURCE_FILE
,
537 "Is this just a name for a rule.",
538 "If SYMBOLIC (boolean) is set to true the build system will be "
539 "informed that the source file is not actually created on disk but "
540 "instead used as a symbolic name for a build rule.");
543 ("WRAP_EXCLUDE", cmProperty::SOURCE_FILE
,
544 "Exclude this source file from any code wrapping techniques.",
545 "Some packages can wrap source files into alternate languages "
546 "to provide additional functionality. For example, C++ code "
547 "can be wrapped into Java or Python etc using SWIG etc. "
548 "If WRAP_EXCLUDE is set to true (1 etc) that indicates then "
549 "this source file should not be wrapped.");