View Issue Details [ Jump to Notes ] | [ Print ] | ||||||||
ID | Project | Category | View Status | Date Submitted | Last Update | ||||
0011793 | CMake | CMake | public | 2011-02-03 11:10 | 2014-06-02 08:37 | ||||
Reporter | Peter Kuemmel | ||||||||
Assigned To | Peter Kuemmel | ||||||||
Priority | normal | Severity | feature | Reproducibility | always | ||||
Status | closed | Resolution | won't fix | ||||||
Platform | All platforms | OS | OS Version | ||||||
Product Version | |||||||||
Target Version | Fixed in Version | ||||||||
Summary | 0011793: namespace support | ||||||||
Description | Several commands have the directory as scope, for instance add_definitions: add_definitions(-DX) add_library(X x.cpp) add_library(antiX antiX.cpp) When antiX.cpp doesn't compile with the definition X set then it is not possible to write such a cmake file. Support of namespace could fix this: namespace(x) add_definitions(-DX) add_library(X x.cpp) endnamespace() add_library/antiX antiX.cpp) Attached a patch which adds this feature. The only critical part is the usage of the new member variables current*, otherwise not using namespace() is 100% backward compatible when no variable with that name is used. | ||||||||
Tags | No tags attached. | ||||||||
Attached Files | namespace.patch [^] (33,452 bytes) 2011-02-03 11:10 [Show Content] [Hide Content]diff --git a/Source/cmBootstrapCommands.cxx b/Source/cmBootstrapCommands.cxx index 554f452..809cff4 100644 --- a/Source/cmBootstrapCommands.cxx +++ b/Source/cmBootstrapCommands.cxx @@ -56,40 +56,41 @@ #include "cmGetFilenameComponentCommand.cxx" #include "cmGetPropertyCommand.cxx" #include "cmGetSourceFilePropertyCommand.cxx" #include "cmGetTargetPropertyCommand.cxx" #include "cmHexFileConverter.cxx" #include "cmIfCommand.cxx" #include "cmIncludeCommand.cxx" #include "cmIncludeDirectoryCommand.cxx" #include "cmIncludeRegularExpressionCommand.cxx" #include "cmInstallFilesCommand.cxx" #include "cmInstallCommandArguments.cxx" #include "cmInstallCommand.cxx" #include "cmInstallTargetsCommand.cxx" #include "cmLinkDirectoriesCommand.cxx" #include "cmListCommand.cxx" #include "cmMacroCommand.cxx" #include "cmMakeDirectoryCommand.cxx" #include "cmMarkAsAdvancedCommand.cxx" #include "cmMathCommand.cxx" #include "cmMessageCommand.cxx" +#include "cmNamespaceCommand.cxx" #include "cmOptionCommand.cxx" #include "cmProjectCommand.cxx" #include "cmReturnCommand.cxx" #include "cmSeparateArgumentsCommand.cxx" #include "cmSetCommand.cxx" #include "cmSetDirectoryPropertiesCommand.cxx" #include "cmSetPropertyCommand.cxx" #include "cmSetSourceFilesPropertiesCommand.cxx" #include "cmSetTargetPropertiesCommand.cxx" #include "cmSetTestsPropertiesCommand.cxx" #include "cmGetTestPropertyCommand.cxx" #include "cmSiteNameCommand.cxx" #include "cmStringCommand.cxx" #include "cmSubdirCommand.cxx" #include "cmTargetLinkLibrariesCommand.cxx" #include "cmTryCompileCommand.cxx" #include "cmTryRunCommand.cxx" #include "cmUnsetCommand.cxx" void GetBootstrapCommands(std::list<cmCommand*>& commands) @@ -129,39 +130,40 @@ void GetBootstrapCommands(std::list<cmCommand*>& commands) commands.push_back(new cmGetCMakePropertyCommand); commands.push_back(new cmGetDirectoryPropertyCommand); commands.push_back(new cmGetFilenameComponentCommand); commands.push_back(new cmGetPropertyCommand); commands.push_back(new cmGetSourceFilePropertyCommand); commands.push_back(new cmGetTargetPropertyCommand); commands.push_back(new cmIfCommand); commands.push_back(new cmIncludeCommand); commands.push_back(new cmIncludeDirectoryCommand); commands.push_back(new cmIncludeRegularExpressionCommand); commands.push_back(new cmInstallCommand); commands.push_back(new cmInstallFilesCommand); commands.push_back(new cmInstallTargetsCommand); commands.push_back(new cmLinkDirectoriesCommand); commands.push_back(new cmListCommand); commands.push_back(new cmMacroCommand); commands.push_back(new cmMakeDirectoryCommand); commands.push_back(new cmMarkAsAdvancedCommand); commands.push_back(new cmMathCommand); commands.push_back(new cmMessageCommand); + commands.push_back(new cmNamespaceCommand); commands.push_back(new cmOptionCommand); commands.push_back(new cmProjectCommand); commands.push_back(new cmReturnCommand); commands.push_back(new cmSeparateArgumentsCommand); commands.push_back(new cmSetCommand); commands.push_back(new cmSetDirectoryPropertiesCommand); commands.push_back(new cmSetPropertyCommand); commands.push_back(new cmSetSourceFilesPropertiesCommand); commands.push_back(new cmSetTargetPropertiesCommand); commands.push_back(new cmGetTestPropertyCommand); commands.push_back(new cmSetTestsPropertiesCommand); commands.push_back(new cmSiteNameCommand); commands.push_back(new cmStringCommand); commands.push_back(new cmSubdirCommand); commands.push_back(new cmTargetLinkLibrariesCommand); commands.push_back(new cmTryCompileCommand); commands.push_back(new cmTryRunCommand); commands.push_back(new cmUnsetCommand); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index d3cbc1f..5be3f5a 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -43,40 +43,41 @@ cmLocalGenerator::cmLocalGenerator() { this->Makefile = 0; // moved to after set on global this->Parent = 0; this->WindowsShell = false; this->WindowsVSIDE = false; this->WatcomWMake = false; this->MinGWMake = false; this->NMake = false; this->MSYSShell = false; this->LinkScriptShell = false; this->IgnoreLibPrefix = false; this->UseRelativePaths = false; this->Configured = false; this->EmitUniversalBinaryFlags = true; this->IsMakefileGenerator = false; this->RelativePathsConfigured = false; this->PathConversionsSetup = false; this->BackwardsCompatibility = 0; this->BackwardsCompatibilityFinal = false; + this->IsDirectoryVirtual = false; } cmLocalGenerator::~cmLocalGenerator() { delete this->Makefile; } //---------------------------------------------------------------------------- class cmLocalGeneratorCurrent { cmGlobalGenerator* GG; cmLocalGenerator* LG; public: cmLocalGeneratorCurrent(cmLocalGenerator* lg) { this->GG = lg->GetGlobalGenerator(); this->LG = this->GG->GetCurrentLocalGenerator(); this->GG->SetCurrentLocalGenerator(lg); } ~cmLocalGeneratorCurrent() @@ -147,46 +148,58 @@ void cmLocalGenerator::ComputeObjectMaxPath() cmOStringStream w; w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax << ", which is less than the minimum of 128. " << "The value will be ignored."; this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); } } else { cmOStringStream w; w << "CMAKE_OBJECT_PATH_MAX is set to \"" << plen << "\", which fails to parse as a positive integer. " << "The value will be ignored."; this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); } } this->ObjectMaxPathViolations.clear(); } //---------------------------------------------------------------------------- +void cmLocalGenerator::SetIsDirectoryVirtual(bool val) +{ + IsDirectoryVirtual = val; +} + +//---------------------------------------------------------------------------- +bool cmLocalGenerator::IsDirectoryVirtual() const +{ + return IsDirectoryVirtual; +} + +//---------------------------------------------------------------------------- void cmLocalGenerator::ReadInputFile() { // Look for the CMakeLists.txt file. std::string currentStart = this->Makefile->GetStartDirectory(); currentStart += "/CMakeLists.txt"; - if(cmSystemTools::FileExists(currentStart.c_str(), true)) + if(cmSystemTools::FileExists(currentStart.c_str(), true) || IsDirectoryVirtual) { this->Makefile->ReadListFile(currentStart.c_str()); return; } if(!this->Parent) { return; } // The file is missing. Check policy CMP0014. cmMakefile* mf = this->Parent->GetMakefile(); cmOStringStream e; e << "The source directory\n" << " " << this->Makefile->GetStartDirectory() << "\n" << "does not contain a CMakeLists.txt file."; switch (mf->GetPolicyStatus(cmPolicies::CMP0014)) { case cmPolicies::WARN: // Print the warning. diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 35aab99..6ab0ca3 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -289,40 +289,43 @@ public: /** * Generate a Mac OS X application bundle Info.plist file. */ void GenerateAppleInfoPList(cmTarget* target, const char* targetName, const char* fname); /** * Generate a Mac OS X framework Info.plist file. */ void GenerateFrameworkInfoPList(cmTarget* target, const char* targetName, const char* fname); /** Construct a comment for a custom command. */ std::string ConstructComment(const cmCustomCommand& cc, const char* default_comment = ""); // Compute object file names. std::string GetObjectFileNameWithoutTarget(const cmSourceFile& source, std::string const& dir_max, bool* hasSourceExtension = 0); + void SetIsDirectoryVirtual(bool); + bool GetDirectoryVirtual() const; + protected: /** Fill out these strings for the given target. Libraries to link, * flags, and linkflags. */ void GetTargetFlags(std::string& linkLibs, std::string& flags, std::string& linkFlags, cmTarget&target); ///! put all the libraries for a target on into the given stream virtual void OutputLinkLibraries(std::ostream&, cmTarget&, bool relink); // Expand rule variables in CMake of the type found in language rules void ExpandRuleVariables(std::string& string, const RuleVariables& replaceValues); // Expand rule variables in a single string std::string ExpandRuleVariable(std::string const& variable, const RuleVariables& replaceValues); const char* GetRuleLauncher(cmTarget* target, const char* prop); void InsertRuleLauncher(std::string& s, cmTarget* target, @@ -395,26 +398,29 @@ protected: bool Configured; bool EmitUniversalBinaryFlags; // A type flag is not nice. It's used only in TraceDependencies(). bool IsMakefileGenerator; // Hack for ExpandRuleVariable until object-oriented version is // committed. std::string TargetImplib; // The top-most directories for relative path conversion. Both the // source and destination location of a relative path conversion // must be underneath one of these directories (both under source or // both under binary) in order for the relative path to be evaluated // safely by the build tools. std::string RelativePathTopSource; std::string RelativePathTopBinary; bool RelativePathsConfigured; bool PathConversionsSetup; unsigned int BackwardsCompatibility; bool BackwardsCompatibilityFinal; + + private: + bool IsDirectoryVirtual; std::string ConvertToOutputForExistingCommon(const char* remote, std::string const& result); }; #endif diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index e14e44d..c3b8c86 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -561,46 +561,46 @@ void cmMakefile::IncludeScope::EnforceCMP0011() << "The included script\n " << this->File << "\n" << "affects policy settings, so it requires this policy to be set."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } break; case cmPolicies::OLD: case cmPolicies::NEW: // The script set this policy. We assume the purpose of the // script is to initialize policies for its includer, and since // the policy is now set for later scripts, we do not warn. break; } } //---------------------------------------------------------------------------- // Parse the given CMakeLists.txt file executing all commands // bool cmMakefile::ReadListFile(const char* filename_in, const char *external_in, std::string* fullPath, - bool noPolicyScope) + bool noPolicyScope, + bool isDirectoryVirtual) { - std::string currentParentFile - = this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE"); - std::string currentFile - = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE"); + currentParentFile = this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE"); + currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE"); + this->AddDefinition("CMAKE_PARENT_LIST_FILE", filename_in); this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE"); const char* external = 0; std::string external_abs; const char* filename = filename_in; std::string filename_abs; if (external_in) { external_abs = cmSystemTools::CollapseFullPath(external_in, this->cmStartDirectory.c_str()); external = external_abs.c_str(); if (filename_in) { filename_abs = cmSystemTools::CollapseFullPath(filename_in, this->cmStartDirectory.c_str()); @@ -629,42 +629,49 @@ bool cmMakefile::ReadListFile(const char* filename_in, this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_DIR", cmSystemTools::GetFilenamePath(filenametoread).c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR"); // try to see if the list file is the top most // list file for a project, and if it is, then it // must have a project command. If there is not // one, then cmake will provide one via the // cmListFileCache class. bool requireProjectCommand = false; if(!external && this->cmStartDirectory == this->cmHomeDirectory) { if(cmSystemTools::LowerCase( cmSystemTools::GetFilenameName(filename)) == "cmakelists.txt") { requireProjectCommand = true; } } + + if(isDirectoryVirtual) { + // leave the directory "open" + return true; + } + // push the listfile onto the stack this->ListFileStack.push_back(filenametoread); + if(fullPath!=0) { *fullPath=filenametoread; } cmListFile cacheFile; if( !cacheFile.ParseFile(filenametoread, requireProjectCommand, this) ) { // pop the listfile off the stack this->ListFileStack.pop_back(); if(fullPath!=0) { *fullPath = ""; } this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str()); this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_DIR", cmSystemTools::GetFilenamePath(currentFile).c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR"); @@ -682,62 +689,69 @@ bool cmMakefile::ReadListFile(const char* filename_in, const size_t numberFunctions = cacheFile.Functions.size(); for(size_t i =0; i < numberFunctions; ++i) { cmExecutionStatus status; this->ExecuteCommand(cacheFile.Functions[i],status); if(cmSystemTools::GetFatalErrorOccured()) { // Exit early due to error. lexScope.Quiet(); incScope.Quiet(); break; } if(status.GetReturnInvoked()) { // Exit early due to return command. break; } } } + CleanupReadListFile(); + + // pop the listfile off the stack + this->ListFileStack.pop_back(); + + return true; +} + +//---------------------------------------------------------------------------- +void cmMakefile::CleanupReadListFile() +{ // If this is the directory-level CMakeLists.txt file then perform // some extra checks. if(this->ListFileStack.size() == 1) { this->EnforceDirectoryLevelRules(); } this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str()); this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_DIR", cmSystemTools::GetFilenamePath(currentFile).c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR"); - // pop the listfile off the stack - this->ListFileStack.pop_back(); // Check for unused variables this->CheckForUnusedVariables(); - - return true; } //---------------------------------------------------------------------------- void cmMakefile::EnforceDirectoryLevelRules() { // Diagnose a violation of CMP0000 if necessary. if(this->CheckCMP0000) { cmOStringStream msg; msg << "No cmake_minimum_required command is present. " << "A line of code such as\n" << " cmake_minimum_required(VERSION " << cmVersion::GetMajorVersion() << "." << cmVersion::GetMinorVersion() << ")\n" << "should be added at the top of the file. " << "The version specified may be lower if you wish to " << "support older CMake versions for this project. " << "For more information run " << "\"cmake --help-policy CMP0000\"."; @@ -1570,40 +1584,99 @@ void cmMakefile::AddSubDirectory(const char* srcPath, const char *binPath, cmLocalGenerator *lg2 = this->LocalGenerator->GetGlobalGenerator()->CreateLocalGenerator(); lg2->SetParent(this->LocalGenerator); this->LocalGenerator->GetGlobalGenerator()->AddLocalGenerator(lg2); // set the subdirs start dirs lg2->GetMakefile()->SetStartDirectory(srcPath); lg2->GetMakefile()->SetStartOutputDirectory(binPath); if(excludeFromAll) { lg2->GetMakefile()->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); } lg2->GetMakefile()->SetPreOrder(preorder); if (immediate) { this->ConfigureSubDirectory(lg2); } } +void cmMakefile::AddNamespace(const std::string& srcPathIn, const char* nspace, + bool excludeFromAll, bool preorder) +{ + std::string srcPath = srcPathIn; + // the source path must be made full if it isn't already + if (!cmSystemTools::FileIsFullPath(srcPathIn.c_str())) + { + srcPath = this->GetCurrentDirectory(); + } + + // binary path must be made full if it isn't already + std::string binPath = nspace; + if (!cmSystemTools::FileIsFullPath(binPath.c_str())) + { + binPath = this->GetCurrentOutputDirectory(); + binPath += "/"; + binPath += nspace; + } + + + this->AddNamespace(srcPath.c_str(), binPath.c_str(), + excludeFromAll, preorder, false); +} + + +cmMakefile* cmMakefile::AddNamespace(const char* srcPath, const char *binPath, + bool excludeFromAll, bool preorder, + bool immediate) +{ + // Make sure the binary directory is unique. + if(!this->EnforceUniqueDir(srcPath, binPath)) + { + return 0; + } + + // create a new local generator and set its parent + cmLocalGenerator *lg2 = + this->LocalGenerator->GetGlobalGenerator()->CreateLocalGenerator(); + lg2->SetIsDirectoryVirtual(true); + lg2->SetParent(this->LocalGenerator); + this->LocalGenerator->GetGlobalGenerator()->AddLocalGenerator(lg2); + + // set the subdirs start dirs + lg2->GetMakefile()->SetStartDirectory(srcPath); + lg2->GetMakefile()->SetStartOutputDirectory(binPath); + if(excludeFromAll) + { + lg2->GetMakefile()->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); + } + lg2->GetMakefile()->SetPreOrder(preorder); + + if (immediate) + { + this->ConfigureSubDirectory(lg2); + } + + return lg2->GetMakefile(); +} + void cmMakefile::AddIncludeDirectory(const char* inc, bool before) { // if there is a newline then break it into multiple arguments if (!inc) { return; } // Don't add an include directory that is already present. Yes, // this linear search results in n^2 behavior, but n won't be // getting much bigger than 20. We cannot use a set because of // order dependency of the include path. std::vector<std::string>::iterator i = std::find(this->IncludeDirectories.begin(), this->IncludeDirectories.end(), inc); if(i == this->IncludeDirectories.end()) { if (before) { // WARNING: this *is* expensive (linear time) since it's a vector diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 837a352..1de8ca4 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -73,41 +73,44 @@ public: the cache or lower should be enabled. */ bool NeedCacheCompatibility(int major, int minor); /** * Construct an empty makefile. */ cmMakefile(); cmMakefile(const cmMakefile& mf); /** * Destructor. */ ~cmMakefile(); /** * Read and parse a CMakeLists.txt file. */ bool ReadListFile(const char* listfile, const char* external= 0, std::string* fullPath= 0, - bool noPolicyScope = true); + bool noPolicyScope = true, + bool isDirectoryVirtual = false); + + void CleanupReadListFile(); /** * Add a function blocker to this makefile */ void AddFunctionBlocker(cmFunctionBlocker* fb); /** * Remove the function blocker whose scope ends with the given command. * This returns ownership of the function blocker object. */ cmsys::auto_ptr<cmFunctionBlocker> RemoveFunctionBlocker(cmFunctionBlocker* fb, const cmListFileFunction& lff); /** Push/pop a lexical (function blocker) barrier automatically. */ class LexicalPushPop { public: LexicalPushPop(cmMakefile* mf); ~LexicalPushPop(); void Quiet() { this->ReportError = false; } @@ -254,40 +257,51 @@ public: return this->LinkDirectories; } const std::vector<std::string>& GetLinkDirectories() const { return this->LinkDirectories; } void SetLinkDirectories(const std::vector<std::string>& vec) { this->LinkDirectories = vec; } /** * Add a subdirectory to the build. */ void AddSubDirectory(const char*, bool excludeFromAll=false, bool preorder = false); void AddSubDirectory(const char* fullSrcDir,const char *fullBinDir, bool excludeFromAll, bool preorder, bool immediate); + + /** + * Add a namespace to the build. + */ + void AddNamespace(const std::string& srcPath, const char* nspace, bool excludeFromAll=false, + bool preorder = false); + cmMakefile* AddNamespace(const char* fullSrcDir,const char *fullBinDir, + bool excludeFromAll, bool preorder, + bool immediate); + + /** * Configure a subdirectory */ void ConfigureSubDirectory(cmLocalGenerator *); /** * Add an include directory to the build. */ void AddIncludeDirectory(const char*, bool before = false); /** * Add a variable definition to the build. This variable * can be used in CMake to refer to lists, directories, etc. */ void AddDefinition(const char* name, const char* value); ///! Add a definition to this makefile and the global cmake cache. void AddCacheDefinition(const char* name, const char* value, const char* doc, cmCacheManager::CacheEntryType type, bool force = false); @@ -972,40 +986,43 @@ private: friend class IncludeScope; // stack of policy settings struct PolicyStackEntry: public cmPolicies::PolicyMap { typedef cmPolicies::PolicyMap derived; PolicyStackEntry(bool w = false): derived(), Weak(w) {} PolicyStackEntry(derived const& d, bool w = false): derived(d), Weak(w) {} PolicyStackEntry(PolicyStackEntry const& r): derived(r), Weak(r.Weak) {} bool Weak; }; typedef std::vector<PolicyStackEntry> PolicyStackType; PolicyStackType PolicyStack; std::vector<PolicyStackType::size_type> PolicyBarriers; cmPolicies::PolicyStatus GetPolicyStatusInternal(cmPolicies::PolicyID id); bool CheckCMP0000; // Enforce rules about CMakeLists.txt files. void EnforceDirectoryLevelRules(); + + std::string currentFile; + std::string currentParentFile; }; //---------------------------------------------------------------------------- // Helper class to make sure the call stack is valid. class cmMakefileCall { public: cmMakefileCall(cmMakefile* mf, cmListFileContext const& lfc, cmExecutionStatus& status): Makefile(mf) { cmMakefile::CallStackEntry entry = {&lfc, &status}; this->Makefile->CallStack.push_back(entry); } ~cmMakefileCall() { this->Makefile->CallStack.pop_back(); } private: cmMakefile* Makefile; diff --git a/Source/cmNamespaceCommand.cxx b/Source/cmNamespaceCommand.cxx new file mode 100644 index 0000000..57776b4 --- /dev/null +++ b/Source/cmNamespaceCommand.cxx @@ -0,0 +1,209 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmNamespaceCommand.h" + + + + +#include <cmsys/auto_ptr.hxx> + +bool cmNamespaceFunctionBlocker:: +IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &callingMf, + cmExecutionStatus &inStatus) +{ + if (!cmSystemTools::Strucmp(lff.Name.c_str(),"namespace")) + { + // record the number of nested foreach commands + this->Depth++; + } + else if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endnamespace")) + { + // if this is the endofreach for this statement + if (!this->Depth) + { + // Remove the function blocker for this scope or bail. + cmsys::auto_ptr<cmFunctionBlocker> + fb(callingMf.RemoveFunctionBlocker(this, lff)); + if(!fb.get()) { return false; } + + + // Add the virtual subdirectory using the computed full paths. + cmMakefile* makefile = callingMf.AddNamespace(srcPath.c_str(), binPath.c_str(), + excludeFromAll, false, true); + //std::string tmps; + //cmListFileArgument arg; + // Enforce balanced blocks (if/endif, function/endfunction, etc.). + { + cmMakefile::LexicalPushPop lexScope(makefile); + + // set the variable to the loop value + // Invoke all the functions that were collected in the block. + cmExecutionStatus status; + for(unsigned int c = 0; c < this->Functions.size(); ++c) + { + status.Clear(); + makefile->ExecuteCommand(this->Functions[c],status); + if (status.GetReturnInvoked()) + { + inStatus.SetReturnInvoked(true); + // restore the variable to its prior value + return true; + } + if (status.GetBreakInvoked()) + { + // restore the variable to its prior value + return true; + } + if(cmSystemTools::GetFatalErrorOccured() ) + { + return true; + } + } + + // close virtual subdirecrory + makefile->CleanupReadListFile(); + + } + // restore the variable to its prior value + return true; + } + else + { + // close out a nested foreach + this->Depth--; + } + } + + // record the command + this->Functions.push_back(lff); + + // always return true + return true; +} + +bool cmNamespaceFunctionBlocker:: +ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) +{ + if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endnamespace")) + { + std::vector<std::string> expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments); + // if the endforeach has arguments then make sure + // they match the begin foreach arguments + if (expandedArguments.empty()) + { + return true; + } + } + return false; +} + +cmNamespaceCommand::cmNamespaceCommand() +{ +} + +//--------------------------------------------------------------------------- +bool cmNamespaceCommand::InitialPass +(std::vector<std::string> const& args, cmExecutionStatus &) +{ + if(args.size() < 1 ) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + + // store the binpath + std::string namespaceArg = args[0]; + std::string binArg; + + bool excludeFromAll = false; + + // process the rest of the arguments looking for optional args + std::vector<std::string>::const_iterator i = args.begin(); + ++i; + for(;i != args.end(); ++i) + { + if(*i == "EXCLUDE_FROM_ALL") + { + excludeFromAll = true; + continue; + } + else if (!binArg.size()) + { + binArg = *i; + } + else + { + this->SetError("called with incorrect number of arguments"); + return false; + } + } + + + std::string srcPath = this->Makefile->GetCurrentDirectory(); + srcPath = srcPath + "/" + namespaceArg; + + // Compute the full path to the binary directory. + std::string binPath; + if(binArg.empty()) + { + // No binary directory was specified. If the source directory is + // not a subdirectory of the current directory then it is an + // error. + if(!cmSystemTools::FindLastString(srcPath.c_str(), + this->Makefile->GetCurrentDirectory())) + { + cmOStringStream e; + e << "not given a binary directory but the given source directory " + << "\"" << srcPath << "\" is not a subdirectory of \"" + << this->Makefile->GetCurrentDirectory() << "\". " + << "When specifying an out-of-tree source a binary directory " + << "must be explicitly specified."; + this->SetError(e.str().c_str()); + return false; + } + + // Remove the CurrentDirectory from the srcPath and replace it + // with the CurrentOutputDirectory. + binPath = srcPath; + cmSystemTools::ReplaceString(binPath, + this->Makefile->GetCurrentDirectory(), + this->Makefile->GetCurrentOutputDirectory()); + //binPath = binPath + "/" + namespaceArg; + } + else + { + // Use the binary directory specified. + // Interpret a relative path with respect to the current binary directory. + if(cmSystemTools::FileIsFullPath(binArg.c_str())) + { + binPath = binArg; + } + else + { + binPath = this->Makefile->GetCurrentOutputDirectory(); + binPath += "/"; + binPath += binArg; + } + } + binPath = cmSystemTools::CollapseFullPath(binPath.c_str()); + + + // create a function blocker + cmNamespaceFunctionBlocker *f = new cmNamespaceFunctionBlocker(); + f->srcPath= srcPath;; + f->binPath = binPath; + f->excludeFromAll = excludeFromAll; + this->Makefile->AddFunctionBlocker(f); + + return true; +} diff --git a/Source/cmNamespaceCommand.h b/Source/cmNamespaceCommand.h new file mode 100644 index 0000000..27cd2a6 --- /dev/null +++ b/Source/cmNamespaceCommand.h @@ -0,0 +1,91 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmAddNamespace_h +#define cmAddNamespace_h + +#include "cmCommand.h" + +class cmNamespaceFunctionBlocker : public cmFunctionBlocker +{ +public: + cmNamespaceFunctionBlocker() {this->Depth=0;} + virtual ~cmNamespaceFunctionBlocker() {} + virtual bool IsFunctionBlocked(const cmListFileFunction&, + cmMakefile &mf, + cmExecutionStatus &); + virtual bool ShouldRemove(const cmListFileFunction&, cmMakefile &mf); + + std::vector<cmListFileFunction> Functions; + int Depth; + + std::string srcPath; + std::string binPath; + bool excludeFromAll; + +}; + + + +/** \class cmNamespaceCommand + * \brief Specify a namespace to build + * + */ +class cmNamespaceCommand : public cmCommand +{ +public: + cmNamespaceCommand(); + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmNamespaceCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &status); + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() { return "namespace";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() + { + return "Add a subdirectory to the build."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() + { + return + " namespace(name [binary_dir] \n" + " [EXCLUDE_FROM_ALL])\n" + "Add a namespace to the build." + ; + } + + cmTypeMacro(cmNamespaceCommand, cmCommand); +}; + + + +#endif namespace-2.patch [^] (33,457 bytes) 2011-02-03 11:43 [Show Content] [Hide Content] diff --git a/Source/cmBootstrapCommands.cxx b/Source/cmBootstrapCommands.cxx index 554f452..809cff4 100644 --- a/Source/cmBootstrapCommands.cxx +++ b/Source/cmBootstrapCommands.cxx @@ -56,40 +56,41 @@ #include "cmGetFilenameComponentCommand.cxx" #include "cmGetPropertyCommand.cxx" #include "cmGetSourceFilePropertyCommand.cxx" #include "cmGetTargetPropertyCommand.cxx" #include "cmHexFileConverter.cxx" #include "cmIfCommand.cxx" #include "cmIncludeCommand.cxx" #include "cmIncludeDirectoryCommand.cxx" #include "cmIncludeRegularExpressionCommand.cxx" #include "cmInstallFilesCommand.cxx" #include "cmInstallCommandArguments.cxx" #include "cmInstallCommand.cxx" #include "cmInstallTargetsCommand.cxx" #include "cmLinkDirectoriesCommand.cxx" #include "cmListCommand.cxx" #include "cmMacroCommand.cxx" #include "cmMakeDirectoryCommand.cxx" #include "cmMarkAsAdvancedCommand.cxx" #include "cmMathCommand.cxx" #include "cmMessageCommand.cxx" +#include "cmNamespaceCommand.cxx" #include "cmOptionCommand.cxx" #include "cmProjectCommand.cxx" #include "cmReturnCommand.cxx" #include "cmSeparateArgumentsCommand.cxx" #include "cmSetCommand.cxx" #include "cmSetDirectoryPropertiesCommand.cxx" #include "cmSetPropertyCommand.cxx" #include "cmSetSourceFilesPropertiesCommand.cxx" #include "cmSetTargetPropertiesCommand.cxx" #include "cmSetTestsPropertiesCommand.cxx" #include "cmGetTestPropertyCommand.cxx" #include "cmSiteNameCommand.cxx" #include "cmStringCommand.cxx" #include "cmSubdirCommand.cxx" #include "cmTargetLinkLibrariesCommand.cxx" #include "cmTryCompileCommand.cxx" #include "cmTryRunCommand.cxx" #include "cmUnsetCommand.cxx" void GetBootstrapCommands(std::list<cmCommand*>& commands) @@ -129,39 +130,40 @@ void GetBootstrapCommands(std::list<cmCommand*>& commands) commands.push_back(new cmGetCMakePropertyCommand); commands.push_back(new cmGetDirectoryPropertyCommand); commands.push_back(new cmGetFilenameComponentCommand); commands.push_back(new cmGetPropertyCommand); commands.push_back(new cmGetSourceFilePropertyCommand); commands.push_back(new cmGetTargetPropertyCommand); commands.push_back(new cmIfCommand); commands.push_back(new cmIncludeCommand); commands.push_back(new cmIncludeDirectoryCommand); commands.push_back(new cmIncludeRegularExpressionCommand); commands.push_back(new cmInstallCommand); commands.push_back(new cmInstallFilesCommand); commands.push_back(new cmInstallTargetsCommand); commands.push_back(new cmLinkDirectoriesCommand); commands.push_back(new cmListCommand); commands.push_back(new cmMacroCommand); commands.push_back(new cmMakeDirectoryCommand); commands.push_back(new cmMarkAsAdvancedCommand); commands.push_back(new cmMathCommand); commands.push_back(new cmMessageCommand); + commands.push_back(new cmNamespaceCommand); commands.push_back(new cmOptionCommand); commands.push_back(new cmProjectCommand); commands.push_back(new cmReturnCommand); commands.push_back(new cmSeparateArgumentsCommand); commands.push_back(new cmSetCommand); commands.push_back(new cmSetDirectoryPropertiesCommand); commands.push_back(new cmSetPropertyCommand); commands.push_back(new cmSetSourceFilesPropertiesCommand); commands.push_back(new cmSetTargetPropertiesCommand); commands.push_back(new cmGetTestPropertyCommand); commands.push_back(new cmSetTestsPropertiesCommand); commands.push_back(new cmSiteNameCommand); commands.push_back(new cmStringCommand); commands.push_back(new cmSubdirCommand); commands.push_back(new cmTargetLinkLibrariesCommand); commands.push_back(new cmTryCompileCommand); commands.push_back(new cmTryRunCommand); commands.push_back(new cmUnsetCommand); } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index d3cbc1f..e4f1dcc 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -43,40 +43,41 @@ cmLocalGenerator::cmLocalGenerator() { this->Makefile = 0; // moved to after set on global this->Parent = 0; this->WindowsShell = false; this->WindowsVSIDE = false; this->WatcomWMake = false; this->MinGWMake = false; this->NMake = false; this->MSYSShell = false; this->LinkScriptShell = false; this->IgnoreLibPrefix = false; this->UseRelativePaths = false; this->Configured = false; this->EmitUniversalBinaryFlags = true; this->IsMakefileGenerator = false; this->RelativePathsConfigured = false; this->PathConversionsSetup = false; this->BackwardsCompatibility = 0; this->BackwardsCompatibilityFinal = false; + this->IsDirectoryVirtual = false; } cmLocalGenerator::~cmLocalGenerator() { delete this->Makefile; } //---------------------------------------------------------------------------- class cmLocalGeneratorCurrent { cmGlobalGenerator* GG; cmLocalGenerator* LG; public: cmLocalGeneratorCurrent(cmLocalGenerator* lg) { this->GG = lg->GetGlobalGenerator(); this->LG = this->GG->GetCurrentLocalGenerator(); this->GG->SetCurrentLocalGenerator(lg); } ~cmLocalGeneratorCurrent() @@ -147,46 +148,58 @@ void cmLocalGenerator::ComputeObjectMaxPath() cmOStringStream w; w << "CMAKE_OBJECT_PATH_MAX is set to " << pmax << ", which is less than the minimum of 128. " << "The value will be ignored."; this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); } } else { cmOStringStream w; w << "CMAKE_OBJECT_PATH_MAX is set to \"" << plen << "\", which fails to parse as a positive integer. " << "The value will be ignored."; this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); } } this->ObjectMaxPathViolations.clear(); } //---------------------------------------------------------------------------- +void cmLocalGenerator::SetIsDirectoryVirtual(bool val) +{ + IsDirectoryVirtual = val; +} + +//---------------------------------------------------------------------------- +bool cmLocalGenerator::GetIsDirectoryVirtual() const +{ + return IsDirectoryVirtual; +} + +//---------------------------------------------------------------------------- void cmLocalGenerator::ReadInputFile() { // Look for the CMakeLists.txt file. std::string currentStart = this->Makefile->GetStartDirectory(); currentStart += "/CMakeLists.txt"; - if(cmSystemTools::FileExists(currentStart.c_str(), true)) + if(cmSystemTools::FileExists(currentStart.c_str(), true) || IsDirectoryVirtual) { this->Makefile->ReadListFile(currentStart.c_str()); return; } if(!this->Parent) { return; } // The file is missing. Check policy CMP0014. cmMakefile* mf = this->Parent->GetMakefile(); cmOStringStream e; e << "The source directory\n" << " " << this->Makefile->GetStartDirectory() << "\n" << "does not contain a CMakeLists.txt file."; switch (mf->GetPolicyStatus(cmPolicies::CMP0014)) { case cmPolicies::WARN: // Print the warning. diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index 35aab99..4b51e26 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -289,40 +289,43 @@ public: /** * Generate a Mac OS X application bundle Info.plist file. */ void GenerateAppleInfoPList(cmTarget* target, const char* targetName, const char* fname); /** * Generate a Mac OS X framework Info.plist file. */ void GenerateFrameworkInfoPList(cmTarget* target, const char* targetName, const char* fname); /** Construct a comment for a custom command. */ std::string ConstructComment(const cmCustomCommand& cc, const char* default_comment = ""); // Compute object file names. std::string GetObjectFileNameWithoutTarget(const cmSourceFile& source, std::string const& dir_max, bool* hasSourceExtension = 0); + void SetIsDirectoryVirtual(bool); + bool GetIsDirectoryVirtual() const; + protected: /** Fill out these strings for the given target. Libraries to link, * flags, and linkflags. */ void GetTargetFlags(std::string& linkLibs, std::string& flags, std::string& linkFlags, cmTarget&target); ///! put all the libraries for a target on into the given stream virtual void OutputLinkLibraries(std::ostream&, cmTarget&, bool relink); // Expand rule variables in CMake of the type found in language rules void ExpandRuleVariables(std::string& string, const RuleVariables& replaceValues); // Expand rule variables in a single string std::string ExpandRuleVariable(std::string const& variable, const RuleVariables& replaceValues); const char* GetRuleLauncher(cmTarget* target, const char* prop); void InsertRuleLauncher(std::string& s, cmTarget* target, @@ -395,26 +398,29 @@ protected: bool Configured; bool EmitUniversalBinaryFlags; // A type flag is not nice. It's used only in TraceDependencies(). bool IsMakefileGenerator; // Hack for ExpandRuleVariable until object-oriented version is // committed. std::string TargetImplib; // The top-most directories for relative path conversion. Both the // source and destination location of a relative path conversion // must be underneath one of these directories (both under source or // both under binary) in order for the relative path to be evaluated // safely by the build tools. std::string RelativePathTopSource; std::string RelativePathTopBinary; bool RelativePathsConfigured; bool PathConversionsSetup; unsigned int BackwardsCompatibility; bool BackwardsCompatibilityFinal; + + private: + bool IsDirectoryVirtual; std::string ConvertToOutputForExistingCommon(const char* remote, std::string const& result); }; #endif diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index e14e44d..c3b8c86 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -561,46 +561,46 @@ void cmMakefile::IncludeScope::EnforceCMP0011() << "The included script\n " << this->File << "\n" << "affects policy settings, so it requires this policy to be set."; this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); } break; case cmPolicies::OLD: case cmPolicies::NEW: // The script set this policy. We assume the purpose of the // script is to initialize policies for its includer, and since // the policy is now set for later scripts, we do not warn. break; } } //---------------------------------------------------------------------------- // Parse the given CMakeLists.txt file executing all commands // bool cmMakefile::ReadListFile(const char* filename_in, const char *external_in, std::string* fullPath, - bool noPolicyScope) + bool noPolicyScope, + bool isDirectoryVirtual) { - std::string currentParentFile - = this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE"); - std::string currentFile - = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE"); + currentParentFile = this->GetSafeDefinition("CMAKE_PARENT_LIST_FILE"); + currentFile = this->GetSafeDefinition("CMAKE_CURRENT_LIST_FILE"); + this->AddDefinition("CMAKE_PARENT_LIST_FILE", filename_in); this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE"); const char* external = 0; std::string external_abs; const char* filename = filename_in; std::string filename_abs; if (external_in) { external_abs = cmSystemTools::CollapseFullPath(external_in, this->cmStartDirectory.c_str()); external = external_abs.c_str(); if (filename_in) { filename_abs = cmSystemTools::CollapseFullPath(filename_in, this->cmStartDirectory.c_str()); @@ -629,42 +629,49 @@ bool cmMakefile::ReadListFile(const char* filename_in, this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_DIR", cmSystemTools::GetFilenamePath(filenametoread).c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR"); // try to see if the list file is the top most // list file for a project, and if it is, then it // must have a project command. If there is not // one, then cmake will provide one via the // cmListFileCache class. bool requireProjectCommand = false; if(!external && this->cmStartDirectory == this->cmHomeDirectory) { if(cmSystemTools::LowerCase( cmSystemTools::GetFilenameName(filename)) == "cmakelists.txt") { requireProjectCommand = true; } } + + if(isDirectoryVirtual) { + // leave the directory "open" + return true; + } + // push the listfile onto the stack this->ListFileStack.push_back(filenametoread); + if(fullPath!=0) { *fullPath=filenametoread; } cmListFile cacheFile; if( !cacheFile.ParseFile(filenametoread, requireProjectCommand, this) ) { // pop the listfile off the stack this->ListFileStack.pop_back(); if(fullPath!=0) { *fullPath = ""; } this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str()); this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_DIR", cmSystemTools::GetFilenamePath(currentFile).c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR"); @@ -682,62 +689,69 @@ bool cmMakefile::ReadListFile(const char* filename_in, const size_t numberFunctions = cacheFile.Functions.size(); for(size_t i =0; i < numberFunctions; ++i) { cmExecutionStatus status; this->ExecuteCommand(cacheFile.Functions[i],status); if(cmSystemTools::GetFatalErrorOccured()) { // Exit early due to error. lexScope.Quiet(); incScope.Quiet(); break; } if(status.GetReturnInvoked()) { // Exit early due to return command. break; } } } + CleanupReadListFile(); + + // pop the listfile off the stack + this->ListFileStack.pop_back(); + + return true; +} + +//---------------------------------------------------------------------------- +void cmMakefile::CleanupReadListFile() +{ // If this is the directory-level CMakeLists.txt file then perform // some extra checks. if(this->ListFileStack.size() == 1) { this->EnforceDirectoryLevelRules(); } this->AddDefinition("CMAKE_PARENT_LIST_FILE", currentParentFile.c_str()); this->MarkVariableAsUsed("CMAKE_PARENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_FILE", currentFile.c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_FILE"); this->AddDefinition("CMAKE_CURRENT_LIST_DIR", cmSystemTools::GetFilenamePath(currentFile).c_str()); this->MarkVariableAsUsed("CMAKE_CURRENT_LIST_DIR"); - // pop the listfile off the stack - this->ListFileStack.pop_back(); // Check for unused variables this->CheckForUnusedVariables(); - - return true; } //---------------------------------------------------------------------------- void cmMakefile::EnforceDirectoryLevelRules() { // Diagnose a violation of CMP0000 if necessary. if(this->CheckCMP0000) { cmOStringStream msg; msg << "No cmake_minimum_required command is present. " << "A line of code such as\n" << " cmake_minimum_required(VERSION " << cmVersion::GetMajorVersion() << "." << cmVersion::GetMinorVersion() << ")\n" << "should be added at the top of the file. " << "The version specified may be lower if you wish to " << "support older CMake versions for this project. " << "For more information run " << "\"cmake --help-policy CMP0000\"."; @@ -1570,40 +1584,99 @@ void cmMakefile::AddSubDirectory(const char* srcPath, const char *binPath, cmLocalGenerator *lg2 = this->LocalGenerator->GetGlobalGenerator()->CreateLocalGenerator(); lg2->SetParent(this->LocalGenerator); this->LocalGenerator->GetGlobalGenerator()->AddLocalGenerator(lg2); // set the subdirs start dirs lg2->GetMakefile()->SetStartDirectory(srcPath); lg2->GetMakefile()->SetStartOutputDirectory(binPath); if(excludeFromAll) { lg2->GetMakefile()->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); } lg2->GetMakefile()->SetPreOrder(preorder); if (immediate) { this->ConfigureSubDirectory(lg2); } } +void cmMakefile::AddNamespace(const std::string& srcPathIn, const char* nspace, + bool excludeFromAll, bool preorder) +{ + std::string srcPath = srcPathIn; + // the source path must be made full if it isn't already + if (!cmSystemTools::FileIsFullPath(srcPathIn.c_str())) + { + srcPath = this->GetCurrentDirectory(); + } + + // binary path must be made full if it isn't already + std::string binPath = nspace; + if (!cmSystemTools::FileIsFullPath(binPath.c_str())) + { + binPath = this->GetCurrentOutputDirectory(); + binPath += "/"; + binPath += nspace; + } + + + this->AddNamespace(srcPath.c_str(), binPath.c_str(), + excludeFromAll, preorder, false); +} + + +cmMakefile* cmMakefile::AddNamespace(const char* srcPath, const char *binPath, + bool excludeFromAll, bool preorder, + bool immediate) +{ + // Make sure the binary directory is unique. + if(!this->EnforceUniqueDir(srcPath, binPath)) + { + return 0; + } + + // create a new local generator and set its parent + cmLocalGenerator *lg2 = + this->LocalGenerator->GetGlobalGenerator()->CreateLocalGenerator(); + lg2->SetIsDirectoryVirtual(true); + lg2->SetParent(this->LocalGenerator); + this->LocalGenerator->GetGlobalGenerator()->AddLocalGenerator(lg2); + + // set the subdirs start dirs + lg2->GetMakefile()->SetStartDirectory(srcPath); + lg2->GetMakefile()->SetStartOutputDirectory(binPath); + if(excludeFromAll) + { + lg2->GetMakefile()->SetProperty("EXCLUDE_FROM_ALL", "TRUE"); + } + lg2->GetMakefile()->SetPreOrder(preorder); + + if (immediate) + { + this->ConfigureSubDirectory(lg2); + } + + return lg2->GetMakefile(); +} + void cmMakefile::AddIncludeDirectory(const char* inc, bool before) { // if there is a newline then break it into multiple arguments if (!inc) { return; } // Don't add an include directory that is already present. Yes, // this linear search results in n^2 behavior, but n won't be // getting much bigger than 20. We cannot use a set because of // order dependency of the include path. std::vector<std::string>::iterator i = std::find(this->IncludeDirectories.begin(), this->IncludeDirectories.end(), inc); if(i == this->IncludeDirectories.end()) { if (before) { // WARNING: this *is* expensive (linear time) since it's a vector diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 837a352..1de8ca4 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -73,41 +73,44 @@ public: the cache or lower should be enabled. */ bool NeedCacheCompatibility(int major, int minor); /** * Construct an empty makefile. */ cmMakefile(); cmMakefile(const cmMakefile& mf); /** * Destructor. */ ~cmMakefile(); /** * Read and parse a CMakeLists.txt file. */ bool ReadListFile(const char* listfile, const char* external= 0, std::string* fullPath= 0, - bool noPolicyScope = true); + bool noPolicyScope = true, + bool isDirectoryVirtual = false); + + void CleanupReadListFile(); /** * Add a function blocker to this makefile */ void AddFunctionBlocker(cmFunctionBlocker* fb); /** * Remove the function blocker whose scope ends with the given command. * This returns ownership of the function blocker object. */ cmsys::auto_ptr<cmFunctionBlocker> RemoveFunctionBlocker(cmFunctionBlocker* fb, const cmListFileFunction& lff); /** Push/pop a lexical (function blocker) barrier automatically. */ class LexicalPushPop { public: LexicalPushPop(cmMakefile* mf); ~LexicalPushPop(); void Quiet() { this->ReportError = false; } @@ -254,40 +257,51 @@ public: return this->LinkDirectories; } const std::vector<std::string>& GetLinkDirectories() const { return this->LinkDirectories; } void SetLinkDirectories(const std::vector<std::string>& vec) { this->LinkDirectories = vec; } /** * Add a subdirectory to the build. */ void AddSubDirectory(const char*, bool excludeFromAll=false, bool preorder = false); void AddSubDirectory(const char* fullSrcDir,const char *fullBinDir, bool excludeFromAll, bool preorder, bool immediate); + + /** + * Add a namespace to the build. + */ + void AddNamespace(const std::string& srcPath, const char* nspace, bool excludeFromAll=false, + bool preorder = false); + cmMakefile* AddNamespace(const char* fullSrcDir,const char *fullBinDir, + bool excludeFromAll, bool preorder, + bool immediate); + + /** * Configure a subdirectory */ void ConfigureSubDirectory(cmLocalGenerator *); /** * Add an include directory to the build. */ void AddIncludeDirectory(const char*, bool before = false); /** * Add a variable definition to the build. This variable * can be used in CMake to refer to lists, directories, etc. */ void AddDefinition(const char* name, const char* value); ///! Add a definition to this makefile and the global cmake cache. void AddCacheDefinition(const char* name, const char* value, const char* doc, cmCacheManager::CacheEntryType type, bool force = false); @@ -972,40 +986,43 @@ private: friend class IncludeScope; // stack of policy settings struct PolicyStackEntry: public cmPolicies::PolicyMap { typedef cmPolicies::PolicyMap derived; PolicyStackEntry(bool w = false): derived(), Weak(w) {} PolicyStackEntry(derived const& d, bool w = false): derived(d), Weak(w) {} PolicyStackEntry(PolicyStackEntry const& r): derived(r), Weak(r.Weak) {} bool Weak; }; typedef std::vector<PolicyStackEntry> PolicyStackType; PolicyStackType PolicyStack; std::vector<PolicyStackType::size_type> PolicyBarriers; cmPolicies::PolicyStatus GetPolicyStatusInternal(cmPolicies::PolicyID id); bool CheckCMP0000; // Enforce rules about CMakeLists.txt files. void EnforceDirectoryLevelRules(); + + std::string currentFile; + std::string currentParentFile; }; //---------------------------------------------------------------------------- // Helper class to make sure the call stack is valid. class cmMakefileCall { public: cmMakefileCall(cmMakefile* mf, cmListFileContext const& lfc, cmExecutionStatus& status): Makefile(mf) { cmMakefile::CallStackEntry entry = {&lfc, &status}; this->Makefile->CallStack.push_back(entry); } ~cmMakefileCall() { this->Makefile->CallStack.pop_back(); } private: cmMakefile* Makefile; diff --git a/Source/cmNamespaceCommand.cxx b/Source/cmNamespaceCommand.cxx new file mode 100644 index 0000000..57776b4 --- /dev/null +++ b/Source/cmNamespaceCommand.cxx @@ -0,0 +1,209 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmNamespaceCommand.h" + + + + +#include <cmsys/auto_ptr.hxx> + +bool cmNamespaceFunctionBlocker:: +IsFunctionBlocked(const cmListFileFunction& lff, cmMakefile &callingMf, + cmExecutionStatus &inStatus) +{ + if (!cmSystemTools::Strucmp(lff.Name.c_str(),"namespace")) + { + // record the number of nested foreach commands + this->Depth++; + } + else if (!cmSystemTools::Strucmp(lff.Name.c_str(),"endnamespace")) + { + // if this is the endofreach for this statement + if (!this->Depth) + { + // Remove the function blocker for this scope or bail. + cmsys::auto_ptr<cmFunctionBlocker> + fb(callingMf.RemoveFunctionBlocker(this, lff)); + if(!fb.get()) { return false; } + + + // Add the virtual subdirectory using the computed full paths. + cmMakefile* makefile = callingMf.AddNamespace(srcPath.c_str(), binPath.c_str(), + excludeFromAll, false, true); + //std::string tmps; + //cmListFileArgument arg; + // Enforce balanced blocks (if/endif, function/endfunction, etc.). + { + cmMakefile::LexicalPushPop lexScope(makefile); + + // set the variable to the loop value + // Invoke all the functions that were collected in the block. + cmExecutionStatus status; + for(unsigned int c = 0; c < this->Functions.size(); ++c) + { + status.Clear(); + makefile->ExecuteCommand(this->Functions[c],status); + if (status.GetReturnInvoked()) + { + inStatus.SetReturnInvoked(true); + // restore the variable to its prior value + return true; + } + if (status.GetBreakInvoked()) + { + // restore the variable to its prior value + return true; + } + if(cmSystemTools::GetFatalErrorOccured() ) + { + return true; + } + } + + // close virtual subdirecrory + makefile->CleanupReadListFile(); + + } + // restore the variable to its prior value + return true; + } + else + { + // close out a nested foreach + this->Depth--; + } + } + + // record the command + this->Functions.push_back(lff); + + // always return true + return true; +} + +bool cmNamespaceFunctionBlocker:: +ShouldRemove(const cmListFileFunction& lff, cmMakefile& mf) +{ + if(!cmSystemTools::Strucmp(lff.Name.c_str(),"endnamespace")) + { + std::vector<std::string> expandedArguments; + mf.ExpandArguments(lff.Arguments, expandedArguments); + // if the endforeach has arguments then make sure + // they match the begin foreach arguments + if (expandedArguments.empty()) + { + return true; + } + } + return false; +} + +cmNamespaceCommand::cmNamespaceCommand() +{ +} + +//--------------------------------------------------------------------------- +bool cmNamespaceCommand::InitialPass +(std::vector<std::string> const& args, cmExecutionStatus &) +{ + if(args.size() < 1 ) + { + this->SetError("called with incorrect number of arguments"); + return false; + } + + // store the binpath + std::string namespaceArg = args[0]; + std::string binArg; + + bool excludeFromAll = false; + + // process the rest of the arguments looking for optional args + std::vector<std::string>::const_iterator i = args.begin(); + ++i; + for(;i != args.end(); ++i) + { + if(*i == "EXCLUDE_FROM_ALL") + { + excludeFromAll = true; + continue; + } + else if (!binArg.size()) + { + binArg = *i; + } + else + { + this->SetError("called with incorrect number of arguments"); + return false; + } + } + + + std::string srcPath = this->Makefile->GetCurrentDirectory(); + srcPath = srcPath + "/" + namespaceArg; + + // Compute the full path to the binary directory. + std::string binPath; + if(binArg.empty()) + { + // No binary directory was specified. If the source directory is + // not a subdirectory of the current directory then it is an + // error. + if(!cmSystemTools::FindLastString(srcPath.c_str(), + this->Makefile->GetCurrentDirectory())) + { + cmOStringStream e; + e << "not given a binary directory but the given source directory " + << "\"" << srcPath << "\" is not a subdirectory of \"" + << this->Makefile->GetCurrentDirectory() << "\". " + << "When specifying an out-of-tree source a binary directory " + << "must be explicitly specified."; + this->SetError(e.str().c_str()); + return false; + } + + // Remove the CurrentDirectory from the srcPath and replace it + // with the CurrentOutputDirectory. + binPath = srcPath; + cmSystemTools::ReplaceString(binPath, + this->Makefile->GetCurrentDirectory(), + this->Makefile->GetCurrentOutputDirectory()); + //binPath = binPath + "/" + namespaceArg; + } + else + { + // Use the binary directory specified. + // Interpret a relative path with respect to the current binary directory. + if(cmSystemTools::FileIsFullPath(binArg.c_str())) + { + binPath = binArg; + } + else + { + binPath = this->Makefile->GetCurrentOutputDirectory(); + binPath += "/"; + binPath += binArg; + } + } + binPath = cmSystemTools::CollapseFullPath(binPath.c_str()); + + + // create a function blocker + cmNamespaceFunctionBlocker *f = new cmNamespaceFunctionBlocker(); + f->srcPath= srcPath;; + f->binPath = binPath; + f->excludeFromAll = excludeFromAll; + this->Makefile->AddFunctionBlocker(f); + + return true; +} diff --git a/Source/cmNamespaceCommand.h b/Source/cmNamespaceCommand.h new file mode 100644 index 0000000..27cd2a6 --- /dev/null +++ b/Source/cmNamespaceCommand.h @@ -0,0 +1,91 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmAddNamespace_h +#define cmAddNamespace_h + +#include "cmCommand.h" + +class cmNamespaceFunctionBlocker : public cmFunctionBlocker +{ +public: + cmNamespaceFunctionBlocker() {this->Depth=0;} + virtual ~cmNamespaceFunctionBlocker() {} + virtual bool IsFunctionBlocked(const cmListFileFunction&, + cmMakefile &mf, + cmExecutionStatus &); + virtual bool ShouldRemove(const cmListFileFunction&, cmMakefile &mf); + + std::vector<cmListFileFunction> Functions; + int Depth; + + std::string srcPath; + std::string binPath; + bool excludeFromAll; + +}; + + + +/** \class cmNamespaceCommand + * \brief Specify a namespace to build + * + */ +class cmNamespaceCommand : public cmCommand +{ +public: + cmNamespaceCommand(); + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + return new cmNamespaceCommand; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &status); + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() { return "namespace";} + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() + { + return "Add a subdirectory to the build."; + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() + { + return + " namespace(name [binary_dir] \n" + " [EXCLUDE_FROM_ALL])\n" + "Add a namespace to the build." + ; + } + + cmTypeMacro(cmNamespaceCommand, cmCommand); +}; + + + +#endif | ||||||||
Relationships | |
Relationships |
Notes | |
(0025236) Peter Kuemmel (developer) 2011-02-03 11:44 |
namespace.patch is buggy use namespace-2.patch. |
(0025247) Brad King (manager) 2011-02-03 13:50 |
Instead of add_definitions(-DX) add_library(X x.cpp) add_library(antiX antiX.cpp) use add_library(X x.cpp) set_property(TARGET X PROPERTY COMPILE_DEFINITIONS X) add_library(antiX antiX.cpp) |
(0025252) Peter Kuemmel (developer) 2011-02-03 15:48 |
> set_property(TARGET X PROPERTY COMPILE_DEFINITIONS X) add_definitions was an example only. What about include_directories? Even adding a INCLUDE_DIRECTORIES property wouldn't do the same: set(x x1) message(STATUS "x = ${x}") namespace(nx) set(x x2) message(STATUS "x = ${x}") endnamespace() message(STATUS "x = ${x}") Output: -- x = x1 -- x = x2 -- x = x1 The patch isn't perfect, it's a proposal to see if there is any chance to get it upstream. E.g.'namespace' as command name is misleading because entering the namespace again wouldn't make previously settings available. A better name must be found. And cmMakefile::AddNamespace could be merged with cmMakefile::AddSubDirectory. |
(0025253) Brad King (manager) 2011-02-03 15:56 |
Why not just organize your project with an actual subdirectory? I think the scoping rules are complicated enough. |
(0025254) Peter Kuemmel (developer) 2011-02-03 16:08 |
I already have subdirectories but I find it much more elegant and simpler to maintain if I could write all the identical build rules in one file. And the scoping rule are so complicated that I (as normal user) only know that all the settings done in a subdirectory are only visible in this directory or below. Adding something like namespace would simplify the scoping rules because everybody understands the concept of namespaces. |
(0030228) David Cole (manager) 2012-08-11 11:09 |
Sending old, never assigned issues to the backlog. (The age of the bug, plus the fact that it's never been assigned to anyone means that nobody is actively working on it...) If an issue you care about is sent to the backlog when you feel it should have been addressed in a different manner, please bring it up on the CMake mailing list for discussion. Sign up for the mailing list here, if you're not already on it: http://www.cmake.org/mailman/listinfo/cmake [^] It's easy to re-activate a bug here if you can find a CMake developer who has the bandwidth to take it on, and ferry a fix through to our 'next' branch for dashboard testing. |
(0030467) Peter Kuemmel (developer) 2012-08-13 08:41 |
postpone |
(0030773) Stephen Kelly (developer) 2012-08-27 07:04 |
Is this still needed? We have target-scoped include directories since CMake 2.8.8. Are there other commands where directory-scoping is a problem but there is no target-scoped property? We can fill those gaps. |
(0034318) Stephen Kelly (developer) 2013-11-02 09:45 |
We have target_compile_options, target_compile_definitions, and target_include_directories now. I'm sure this is not needed. |
(0034337) Peter Kuemmel (developer) 2013-11-03 02:44 |
I still like this feature. Especially when using only one CMake file for several directories the namespace is very comfortable, for instance just use add_definitions() like before. But it seems all love it to pollute the directory tree CMakeLists.txt file. So the status is "won't fix", or similar, decided by others. |
(0035996) Robert Maynard (manager) 2014-06-02 08:37 |
Closing resolved issues that have not been updated in more than 4 months. |
Notes |
Issue History | |||
Date Modified | Username | Field | Change |
2011-02-03 11:10 | Peter Kuemmel | New Issue | |
2011-02-03 11:10 | Peter Kuemmel | File Added: namespace.patch | |
2011-02-03 11:43 | Peter Kuemmel | File Added: namespace-2.patch | |
2011-02-03 11:44 | Peter Kuemmel | Note Added: 0025236 | |
2011-02-03 13:50 | Brad King | Note Added: 0025247 | |
2011-02-03 15:48 | Peter Kuemmel | Note Added: 0025252 | |
2011-02-03 15:56 | Brad King | Note Added: 0025253 | |
2011-02-03 16:08 | Peter Kuemmel | Note Added: 0025254 | |
2012-08-11 11:09 | David Cole | Status | new => backlog |
2012-08-11 11:09 | David Cole | Note Added: 0030228 | |
2012-08-13 08:40 | Peter Kuemmel | Assigned To | => Peter Kuemmel |
2012-08-13 08:40 | Peter Kuemmel | Status | backlog => assigned |
2012-08-13 08:41 | Peter Kuemmel | Note Added: 0030467 | |
2012-08-13 08:41 | Peter Kuemmel | Status | assigned => backlog |
2012-08-27 07:04 | Stephen Kelly | Note Added: 0030773 | |
2013-11-02 09:45 | Stephen Kelly | Note Added: 0034318 | |
2013-11-02 09:45 | Stephen Kelly | Status | backlog => resolved |
2013-11-02 09:45 | Stephen Kelly | Resolution | open => fixed |
2013-11-03 02:44 | Peter Kuemmel | Note Added: 0034337 | |
2013-11-03 02:44 | Peter Kuemmel | Status | resolved => feedback |
2013-11-03 02:44 | Peter Kuemmel | Resolution | fixed => reopened |
2013-11-03 02:45 | Peter Kuemmel | Status | feedback => resolved |
2013-11-03 02:45 | Peter Kuemmel | Resolution | reopened => won't fix |
2014-06-02 08:37 | Robert Maynard | Note Added: 0035996 | |
2014-06-02 08:37 | Robert Maynard | Status | resolved => closed |
Issue History |
Copyright © 2000 - 2018 MantisBT Team |