| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
- file Copyright.txt or https://cmake.org/licensing for details. */
- #include "cmSourceFile.h"
- #include <utility>
- #include "cmGlobalGenerator.h"
- #include "cmListFileCache.h"
- #include "cmMakefile.h"
- #include "cmMessageType.h"
- #include "cmPolicies.h"
- #include "cmProperty.h"
- #include "cmState.h"
- #include "cmStringAlgorithms.h"
- #include "cmSystemTools.h"
- #include "cmake.h"
- cmSourceFile::cmSourceFile(cmMakefile* mf, const std::string& name,
- bool generated, cmSourceFileLocationKind kind)
- : Location(mf, name, (!generated) ? kind : cmSourceFileLocationKind::Known)
- {
- if (generated) {
- this->MarkAsGenerated();
- }
- }
- std::string const& cmSourceFile::GetExtension() const
- {
- return this->Extension;
- }
- const std::string propTRUE = "1";
- const std::string propFALSE = "0";
- const std::string cmSourceFile::propLANGUAGE = "LANGUAGE";
- const std::string cmSourceFile::propLOCATION = "LOCATION";
- const std::string cmSourceFile::propGENERATED = "GENERATED";
- const std::string cmSourceFile::propCOMPILE_DEFINITIONS =
- "COMPILE_DEFINITIONS";
- const std::string cmSourceFile::propCOMPILE_OPTIONS = "COMPILE_OPTIONS";
- const std::string cmSourceFile::propINCLUDE_DIRECTORIES =
- "INCLUDE_DIRECTORIES";
- void cmSourceFile::SetObjectLibrary(std::string const& objlib)
- {
- this->ObjectLibrary = objlib;
- }
- std::string cmSourceFile::GetObjectLibrary() const
- {
- return this->ObjectLibrary;
- }
- std::string const& cmSourceFile::GetOrDetermineLanguage()
- {
- // If the language was set explicitly by the user then use it.
- if (cmProp lang = this->GetProperty(propLANGUAGE)) {
- // Assign to member in order to return a reference.
- this->Language = *lang;
- return this->Language;
- }
- // Perform computation needed to get the language if necessary.
- if (this->Language.empty()) {
- // If a known extension is given or a known full path is given then trust
- // that the current extension is sufficient to determine the language. This
- // will fail only if the user specifies a full path to the source but
- // leaves off the extension, which is kind of weird.
- if (this->FullPath.empty() && this->Location.ExtensionIsAmbiguous() &&
- this->Location.DirectoryIsAmbiguous()) {
- // Finalize the file location to get the extension and set the language.
- this->ResolveFullPath();
- } else {
- // Use the known extension to get the language if possible.
- std::string ext =
- cmSystemTools::GetFilenameLastExtension(this->Location.GetName());
- this->CheckLanguage(ext);
- }
- }
- // Use the language determined from the file extension.
- return this->Language;
- }
- std::string cmSourceFile::GetLanguage() const
- {
- // If the language was set explicitly by the user then use it.
- if (cmProp lang = this->GetProperty(propLANGUAGE)) {
- return *lang;
- }
- // Use the language determined from the file extension.
- return this->Language;
- }
- cmSourceFileLocation const& cmSourceFile::GetLocation() const
- {
- return this->Location;
- }
- std::string const& cmSourceFile::ResolveFullPath(std::string* error,
- std::string* cmp0115Warning)
- {
- if (this->FullPath.empty()) {
- if (this->FindFullPath(error, cmp0115Warning)) {
- this->CheckExtension();
- }
- }
- return this->FullPath;
- }
- std::string const& cmSourceFile::GetFullPath() const
- {
- return this->FullPath;
- }
- bool cmSourceFile::FindFullPath(std::string* error,
- std::string* cmp0115Warning)
- {
- // If the file is generated compute the location without checking on disk.
- // Note: We also check for a locally set GENERATED property, because
- // it might have been set before policy CMP0118 was set to NEW.
- if (this->GetIsGenerated(CheckScope::GlobalAndLocal)) {
- // The file is either already a full path or is relative to the
- // build directory for the target.
- this->Location.DirectoryUseBinary();
- this->FullPath = this->Location.GetFullPath();
- this->FindFullPathFailed = false;
- return true;
- }
- // If this method has already failed once do not try again.
- if (this->FindFullPathFailed) {
- return false;
- }
- // The file is not generated. It must exist on disk.
- cmMakefile const* makefile = this->Location.GetMakefile();
- // Location path
- std::string const& lPath = this->Location.GetFullPath();
- // List of extension lists
- std::vector<std::string> exts =
- makefile->GetCMakeInstance()->GetAllExtensions();
- auto cmp0115 = makefile->GetPolicyStatus(cmPolicies::CMP0115);
- auto cmp0118 = makefile->GetPolicyStatus(cmPolicies::CMP0118);
- bool const cmp0118new =
- cmp0118 != cmPolicies::OLD && cmp0118 != cmPolicies::WARN;
- // Tries to find the file in a given directory
- auto findInDir = [this, &exts, &lPath, cmp0115, cmp0115Warning, cmp0118new,
- makefile](std::string const& dir) -> bool {
- // Compute full path
- std::string const fullPath = cmSystemTools::CollapseFullPath(lPath, dir);
- // Try full path
- if (cmp0118new &&
- makefile->GetGlobalGenerator()->IsGeneratedFile(fullPath)) {
- this->IsGenerated = true;
- }
- if (this->IsGenerated || cmSystemTools::FileExists(fullPath)) {
- this->FullPath = fullPath;
- return true;
- }
- // This has to be an if statement due to a bug in Oracle Developer Studio.
- // See https://community.oracle.com/tech/developers/discussion/4476246/
- // for details.
- if (cmp0115 == cmPolicies::OLD || cmp0115 == cmPolicies::WARN) {
- // Try full path with extension
- for (std::string const& ext : exts) {
- if (!ext.empty()) {
- std::string extPath = cmStrCat(fullPath, '.', ext);
- if (cmp0118new &&
- makefile->GetGlobalGenerator()->IsGeneratedFile(extPath)) {
- this->IsGenerated = true;
- }
- if (this->IsGenerated || cmSystemTools::FileExists(extPath)) {
- this->FullPath = extPath;
- if (cmp0115 == cmPolicies::WARN) {
- std::string warning =
- cmStrCat(cmPolicies::GetPolicyWarning(cmPolicies::CMP0115),
- "\nFile:\n ", extPath);
- if (cmp0115Warning) {
- *cmp0115Warning = std::move(warning);
- } else {
- makefile->GetCMakeInstance()->IssueMessage(
- MessageType::AUTHOR_WARNING, warning);
- }
- }
- return true;
- }
- }
- }
- }
- // File not found
- return false;
- };
- // Try to find the file in various directories
- if (this->Location.DirectoryIsAmbiguous()) {
- if (findInDir(makefile->GetCurrentSourceDirectory()) ||
- findInDir(makefile->GetCurrentBinaryDirectory())) {
- return true;
- }
- } else {
- if (findInDir({})) {
- return true;
- }
- }
- // Compose error
- std::string err = cmStrCat("Cannot find source file:\n ", lPath);
- switch (cmp0115) {
- case cmPolicies::OLD:
- case cmPolicies::WARN:
- err = cmStrCat(err, "\nTried extensions");
- for (auto const& ext : exts) {
- err = cmStrCat(err, " .", ext);
- }
- break;
- case cmPolicies::REQUIRED_IF_USED:
- case cmPolicies::REQUIRED_ALWAYS:
- case cmPolicies::NEW:
- break;
- }
- if (error != nullptr) {
- *error = std::move(err);
- } else {
- makefile->IssueMessage(MessageType::FATAL_ERROR, err);
- }
- this->FindFullPathFailed = true;
- // File not found
- return false;
- }
- void cmSourceFile::CheckExtension()
- {
- // Compute the extension.
- std::string realExt =
- cmSystemTools::GetFilenameLastExtension(this->FullPath);
- if (!realExt.empty()) {
- // Store the extension without the leading '.'.
- this->Extension = realExt.substr(1);
- }
- // Look for object files.
- if (this->Extension == "obj" || this->Extension == "o" ||
- this->Extension == "lo") {
- this->SetProperty("EXTERNAL_OBJECT", "1");
- }
- // Try to identify the source file language from the extension.
- if (this->Language.empty()) {
- this->CheckLanguage(this->Extension);
- }
- }
- void cmSourceFile::CheckLanguage(std::string const& ext)
- {
- // Try to identify the source file language from the extension.
- cmMakefile const* mf = this->Location.GetMakefile();
- cmGlobalGenerator* gg = mf->GetGlobalGenerator();
- std::string l = gg->GetLanguageFromExtension(ext.c_str());
- if (!l.empty()) {
- this->Language = l;
- }
- }
- bool cmSourceFile::Matches(cmSourceFileLocation const& loc)
- {
- return this->Location.Matches(loc);
- }
- void cmSourceFile::SetProperty(const std::string& prop, const char* value)
- {
- if (prop == propINCLUDE_DIRECTORIES) {
- this->IncludeDirectories.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
- this->IncludeDirectories.emplace_back(value, lfbt);
- }
- } else if (prop == propCOMPILE_OPTIONS) {
- this->CompileOptions.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
- this->CompileOptions.emplace_back(value, lfbt);
- }
- } else if (prop == propCOMPILE_DEFINITIONS) {
- this->CompileDefinitions.clear();
- if (value) {
- cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
- this->CompileDefinitions.emplace_back(value, lfbt);
- }
- } else {
- this->Properties.SetProperty(prop, value);
- }
- }
- void cmSourceFile::AppendProperty(const std::string& prop,
- const std::string& value, bool asString)
- {
- if (prop == propINCLUDE_DIRECTORIES) {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
- this->IncludeDirectories.emplace_back(value, lfbt);
- }
- } else if (prop == propCOMPILE_OPTIONS) {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
- this->CompileOptions.emplace_back(value, lfbt);
- }
- } else if (prop == propCOMPILE_DEFINITIONS) {
- if (!value.empty()) {
- cmListFileBacktrace lfbt = this->Location.GetMakefile()->GetBacktrace();
- this->CompileDefinitions.emplace_back(value, lfbt);
- }
- } else {
- this->Properties.AppendProperty(prop, value, asString);
- }
- }
- cmProp cmSourceFile::GetPropertyForUser(const std::string& prop)
- {
- // This method is a consequence of design history and backwards
- // compatibility. GetProperty is (and should be) a const method.
- // Computed properties should not be stored back in the property map
- // but instead reference information already known. If they need to
- // cache information in a mutable ivar to provide the return string
- // safely then so be it.
- //
- // The LOCATION property is particularly problematic. The CMake
- // language has very loose restrictions on the names that will match
- // a given source file (for historical reasons). Implementing
- // lookups correctly with such loose naming requires the
- // cmSourceFileLocation class to commit to a particular full path to
- // the source file as late as possible. If the users requests the
- // LOCATION property we must commit now.
- if (prop == propLOCATION) {
- // Commit to a location.
- this->ResolveFullPath();
- }
- // Similarly, LANGUAGE can be determined by the file extension
- // if it is requested by the user.
- if (prop == propLANGUAGE) {
- // The pointer is valid until `this->Language` is modified.
- return cmProp(this->GetOrDetermineLanguage());
- }
- // Special handling for GENERATED property.
- if (prop == propGENERATED) {
- // We need to check policy CMP0118 in order to determine if we need to
- // possibly consider the value of a locally set GENERATED property, too.
- auto policyStatus =
- this->Location.GetMakefile()->GetPolicyStatus(cmPolicies::CMP0118);
- if (this->GetIsGenerated(
- (policyStatus == cmPolicies::WARN || policyStatus == cmPolicies::OLD)
- ? CheckScope::GlobalAndLocal
- : CheckScope::Global)) {
- return cmProp(propTRUE);
- }
- return cmProp(propFALSE);
- }
- // Perform the normal property lookup.
- return this->GetProperty(prop);
- }
- cmProp cmSourceFile::GetProperty(const std::string& prop) const
- {
- // Check for computed properties.
- if (prop == propLOCATION) {
- if (this->FullPath.empty()) {
- return nullptr;
- }
- return cmProp(this->FullPath);
- }
- // Check for the properties with backtraces.
- if (prop == propINCLUDE_DIRECTORIES) {
- if (this->IncludeDirectories.empty()) {
- return nullptr;
- }
- static std::string output;
- output = cmJoin(this->IncludeDirectories, ";");
- return cmProp(output);
- }
- if (prop == propCOMPILE_OPTIONS) {
- if (this->CompileOptions.empty()) {
- return nullptr;
- }
- static std::string output;
- output = cmJoin(this->CompileOptions, ";");
- return cmProp(output);
- }
- if (prop == propCOMPILE_DEFINITIONS) {
- if (this->CompileDefinitions.empty()) {
- return nullptr;
- }
- static std::string output;
- output = cmJoin(this->CompileDefinitions, ";");
- return cmProp(output);
- }
- cmProp retVal = this->Properties.GetPropertyValue(prop);
- if (!retVal) {
- cmMakefile const* mf = this->Location.GetMakefile();
- const bool chain =
- mf->GetState()->IsPropertyChained(prop, cmProperty::SOURCE_FILE);
- if (chain) {
- return mf->GetProperty(prop, chain);
- }
- return nullptr;
- }
- return retVal;
- }
- const std::string& cmSourceFile::GetSafeProperty(const std::string& prop) const
- {
- cmProp ret = this->GetProperty(prop);
- if (ret) {
- return *ret;
- }
- static std::string const s_empty;
- return s_empty;
- }
- bool cmSourceFile::GetPropertyAsBool(const std::string& prop) const
- {
- return cmIsOn(this->GetProperty(prop));
- }
- void cmSourceFile::MarkAsGenerated()
- {
- this->IsGenerated = true;
- const auto& mf = *this->Location.GetMakefile();
- mf.GetGlobalGenerator()->MarkAsGeneratedFile(this->ResolveFullPath());
- }
- bool cmSourceFile::GetIsGenerated(CheckScope checkScope) const
- {
- if (this->IsGenerated) {
- // Globally marked as generated!
- return true;
- }
- if (checkScope == CheckScope::GlobalAndLocal) {
- // Check locally stored properties.
- return this->GetPropertyAsBool(propGENERATED);
- }
- return false;
- }
- void cmSourceFile::SetProperties(cmPropertyMap properties)
- {
- this->Properties = std::move(properties);
- }
- cmCustomCommand* cmSourceFile::GetCustomCommand() const
- {
- return this->CustomCommand.get();
- }
- void cmSourceFile::SetCustomCommand(std::unique_ptr<cmCustomCommand> cc)
- {
- this->CustomCommand = std::move(cc);
- }
|