1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmSourceFile.cxx,v $
6 Date: $Date: 2009-06-24 13:36:29 $
7 Version: $Revision: 1.57 $
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 // Try to identify the source file language from the extension.
250 if(this->Language
.empty())
252 this->CheckLanguage(this->Extension
);
256 //----------------------------------------------------------------------------
257 void cmSourceFile::CheckLanguage(std::string
const& ext
)
259 // Try to identify the source file language from the extension.
260 cmMakefile
* mf
= this->Location
.GetMakefile();
261 cmGlobalGenerator
* gg
= mf
->GetLocalGenerator()->GetGlobalGenerator();
262 if(const char* l
= gg
->GetLanguageFromExtension(ext
.c_str()))
268 //----------------------------------------------------------------------------
269 bool cmSourceFile::Matches(cmSourceFileLocation
const& loc
)
271 return this->Location
.Matches(loc
);
274 //----------------------------------------------------------------------------
275 void cmSourceFile::SetProperty(const char* prop
, const char* value
)
282 this->Properties
.SetProperty(prop
, value
, cmProperty::SOURCE_FILE
);
285 //----------------------------------------------------------------------------
286 void cmSourceFile::AppendProperty(const char* prop
, const char* value
)
292 this->Properties
.AppendProperty(prop
, value
, cmProperty::SOURCE_FILE
);
295 //----------------------------------------------------------------------------
296 const char* cmSourceFile::GetPropertyForUser(const char *prop
)
298 // This method is a consequence of design history and backwards
299 // compatibility. GetProperty is (and should be) a const method.
300 // Computed properties should not be stored back in the property map
301 // but instead reference information already known. If they need to
302 // cache information in a mutable ivar to provide the return string
303 // safely then so be it.
305 // The LOCATION property is particularly problematic. The CMake
306 // language has very loose restrictions on the names that will match
307 // a given source file (for historical reasons). Implementing
308 // lookups correctly with such loose naming requires the
309 // cmSourceFileLocation class to commit to a particular full path to
310 // the source file as late as possible. If the users requests the
311 // LOCATION property we must commit now.
312 if(strcmp(prop
, "LOCATION") == 0)
314 // Commit to a location.
318 // Perform the normal property lookup.
319 return this->GetProperty(prop
);
322 //----------------------------------------------------------------------------
323 const char* cmSourceFile::GetProperty(const char* prop
) const
325 // Check for computed properties.
326 if(strcmp(prop
, "LOCATION") == 0)
328 if(this->FullPath
.empty())
334 return this->FullPath
.c_str();
340 this->Properties
.GetPropertyValue(prop
, cmProperty::SOURCE_FILE
, chain
);
343 cmMakefile
* mf
= this->Location
.GetMakefile();
344 return mf
->GetProperty(prop
,cmProperty::SOURCE_FILE
);
350 //----------------------------------------------------------------------------
351 bool cmSourceFile::GetPropertyAsBool(const char* prop
) const
353 return cmSystemTools::IsOn(this->GetProperty(prop
));
356 //----------------------------------------------------------------------------
357 cmCustomCommand
* cmSourceFile::GetCustomCommand()
359 return this->CustomCommand
;
362 //----------------------------------------------------------------------------
363 cmCustomCommand
const* cmSourceFile::GetCustomCommand() const
365 return this->CustomCommand
;
368 //----------------------------------------------------------------------------
369 void cmSourceFile::SetCustomCommand(cmCustomCommand
* cc
)
371 cmCustomCommand
* old
= this->CustomCommand
;
372 this->CustomCommand
= cc
;
376 //----------------------------------------------------------------------------
377 void cmSourceFile::DefineProperties(cmake
*cm
)
381 ("ABSTRACT", cmProperty::SOURCE_FILE
,
382 "Is this source file an abstract class.",
383 "A property on a source file that indicates if the source file "
384 "represents a class that is abstract. This only makes sense for "
385 "languages that have a notion of an abstract class and it is "
386 "only used by some tools that wrap classes into other languages.");
389 ("COMPILE_FLAGS", cmProperty::SOURCE_FILE
,
390 "Additional flags to be added when compiling this source file.",
391 "These flags will be added to the list of compile flags when "
392 "this source file builds. Use COMPILE_DEFINITIONS to pass additional "
393 "preprocessor definitions.");
396 ("COMPILE_DEFINITIONS", cmProperty::SOURCE_FILE
,
397 "Preprocessor definitions for compiling a source file.",
398 "The COMPILE_DEFINITIONS property may be set to a "
399 "semicolon-separated list of preprocessor "
400 "definitions using the syntax VAR or VAR=value. Function-style "
401 "definitions are not supported. CMake will automatically escape "
402 "the value correctly for the native build system (note that CMake "
403 "language syntax may require escapes to specify some values). "
404 "This property may be set on a per-configuration basis using the name "
405 "COMPILE_DEFINITIONS_<CONFIG> where <CONFIG> is an upper-case name "
406 "(ex. \"COMPILE_DEFINITIONS_DEBUG\").\n"
407 "CMake will automatically drop some definitions that "
408 "are not supported by the native build tool. "
409 "The VS6 IDE does not support definition values with spaces "
410 "(but NMake does). Xcode does not support per-configuration "
411 "definitions on source files.\n"
412 "Dislaimer: Most native build tools have poor support for escaping "
413 "certain values. CMake has work-arounds for many cases but some "
414 "values may just not be possible to pass correctly. If a value "
415 "does not seem to be escaped correctly, do not attempt to "
416 "work-around the problem by adding escape sequences to the value. "
417 "Your work-around may break in a future version of CMake that "
418 "has improved escape support. Instead consider defining the macro "
419 "in a (configured) header file. Then report the limitation.");
423 ("COMPILE_DEFINITIONS_<CONFIG>", cmProperty::SOURCE_FILE
,
424 "Per-configuration preprocessor definitions on a source file.",
425 "This is the configuration-specific version of "
426 "COMPILE_DEFINITIONS. Note that Xcode does not support "
427 "per-configuration source file flags so this property will "
428 "be ignored by the Xcode generator.");
431 ("EXTERNAL_OBJECT", cmProperty::SOURCE_FILE
,
432 "If set to true then this is an object file.",
433 "If this property is set to true then the source file "
434 "is really an object file and should not be compiled. "
435 "It will still be linked into the target though.");
438 ("GENERATED", cmProperty::SOURCE_FILE
,
439 "Is this source file generated as part of the build process.",
440 "If a source file is generated by the build process CMake will "
441 "handle it differently in temrs of dependency checking etc. "
442 "Otherwise having a non-existent source file could create problems.");
445 ("HEADER_FILE_ONLY", cmProperty::SOURCE_FILE
,
446 "Is this source file only a header file.",
447 "A property on a source file that indicates if the source file "
448 "is a header file with no associated implementation. This is "
449 "set automatically based on the file extension and is used by "
450 "CMake to determine is certain dependency information should be "
454 ("KEEP_EXTENSION", cmProperty::SOURCE_FILE
,
455 "Make the output file have the same extension as the source file.",
456 "If this property is set then the file extension of the output "
457 "file will be the same as that of the source file. Normally "
458 "the output file extension is computed based on the language "
459 "of the source file, for example .cxx will go to a .o extension.");
462 ("LABELS", cmProperty::SOURCE_FILE
,
463 "Specify a list of text labels associated with a source file.",
464 "This property has meaning only when the source file is listed in "
465 "a target whose LABELS property is also set. "
466 "No other semantics are currently specified.");
469 ("LANGUAGE", cmProperty::SOURCE_FILE
,
470 "What programming language is the file.",
471 "A property that can be set to indicate what programming language "
472 "the source file is. If it is not set the language is determined "
473 "based on the file extension. Typical values are CXX C etc.");
476 ("LOCATION", cmProperty::SOURCE_FILE
,
477 "The full path to a source file.",
478 "A read only property on a SOURCE FILE that contains the full path "
479 "to the source file.");
482 ("MACOSX_PACKAGE_LOCATION", cmProperty::SOURCE_FILE
,
483 "Place a source file inside a Mac OS X bundle or framework.",
484 "Executable targets with the MACOSX_BUNDLE property set are built "
485 "as Mac OS X application bundles on Apple platforms. "
486 "Shared library targets with the FRAMEWORK property set are built "
487 "as Mac OS X frameworks on Apple platforms. "
488 "Source files listed in the target with this property set will "
489 "be copied to a directory inside the bundle or framework content "
490 "folder specified by the property value. "
491 "For bundles the content folder is \"<name>.app/Contents\". "
492 "For frameworks the content folder is "
493 "\"<name>.framework/Versions/<version>\". "
494 "See the PUBLIC_HEADER, PRIVATE_HEADER, and RESOURCE target "
495 "properties for specifying files meant for Headers, PrivateHeadres, "
496 "or Resources directories.");
499 ("OBJECT_DEPENDS", cmProperty::SOURCE_FILE
,
500 "Additional files on which a compiled object file depends.",
501 "Specifies a semicolon-separated list of full-paths to files on which "
502 "any object files compiled from this source file depend. "
503 "An object file will be recompiled if any of the named files is newer "
505 "This property need not be used to specify the dependency of a "
506 "source file on a generated header file that it includes. "
507 "Although the property was originally introduced for this purpose, it "
508 "is no longer necessary. "
509 "If the generated header file is created by a custom command in the "
510 "same target as the source file, the automatic dependency scanning "
511 "process will recognize the dependency. "
512 "If the generated header file is created by another target, an "
513 "inter-target dependency should be created with the add_dependencies "
514 "command (if one does not already exist due to linking relationships).");
517 ("OBJECT_OUTPUTS", cmProperty::SOURCE_FILE
,
518 "Additional outputs for a Makefile rule.",
519 "Additional outputs created by compilation of this source file. "
520 "If any of these outputs is missing the object will be recompiled. "
521 "This is supported only on Makefile generators and will be ignored "
522 "on other generators.");
525 ("SYMBOLIC", cmProperty::SOURCE_FILE
,
526 "Is this just a name for a rule.",
527 "If SYMBOLIC (boolean) is set to true the build system will be "
528 "informed that the source file is not actually created on disk but "
529 "instead used as a symbolic name for a build rule.");
532 ("WRAP_EXCLUDE", cmProperty::SOURCE_FILE
,
533 "Exclude this source file from any code wrapping techniques.",
534 "Some packages can wrap source files into alternate languages "
535 "to provide additional functionality. For example, C++ code "
536 "can be wrapped into Java or Python etc using SWIG etc. "
537 "If WRAP_EXCLUDE is set to true (1 etc) that indicates then "
538 "this source file should not be wrapped.");