From d44bd1c25f3a1cba977eee5a6b2f5bd14c46c73d Mon Sep 17 00:00:00 2001 From: Pavel Solodovnikov Date: Thu, 22 Jun 2017 10:53:42 +0300 Subject: include_guard: implement new command --- Source/CMakeLists.txt | 2 + Source/cmCommands.cxx | 2 + Source/cmIncludeGuardCommand.cxx | 108 +++++++++++++++++++++++++++++++++++++++ Source/cmIncludeGuardCommand.h | 37 ++++++++++++++ bootstrap | 1 + 5 files changed, 150 insertions(+) create mode 100644 Source/cmIncludeGuardCommand.cxx create mode 100644 Source/cmIncludeGuardCommand.h diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 1878b8a..660d632 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -469,6 +469,8 @@ set(SRCS cmIncludeDirectoryCommand.h cmIncludeExternalMSProjectCommand.cxx cmIncludeExternalMSProjectCommand.h + cmIncludeGuardCommand.cxx + cmIncludeGuardCommand.h cmIncludeRegularExpressionCommand.cxx cmIncludeRegularExpressionCommand.h cmInstallCommand.cxx diff --git a/Source/cmCommands.cxx b/Source/cmCommands.cxx index e1d8ef1..485dd50 100644 --- a/Source/cmCommands.cxx +++ b/Source/cmCommands.cxx @@ -42,6 +42,7 @@ #include "cmIfCommand.h" #include "cmIncludeCommand.h" #include "cmIncludeDirectoryCommand.h" +#include "cmIncludeGuardCommand.h" #include "cmIncludeRegularExpressionCommand.h" #include "cmInstallCommand.h" #include "cmInstallFilesCommand.h" @@ -132,6 +133,7 @@ void GetScriptingCommands(cmState* state) state->AddBuiltinCommand("get_property", new cmGetPropertyCommand); state->AddBuiltinCommand("if", new cmIfCommand); state->AddBuiltinCommand("include", new cmIncludeCommand); + state->AddBuiltinCommand("include_guard", new cmIncludeGuardCommand); state->AddBuiltinCommand("list", new cmListCommand); state->AddBuiltinCommand("macro", new cmMacroCommand); state->AddBuiltinCommand("make_directory", new cmMakeDirectoryCommand); diff --git a/Source/cmIncludeGuardCommand.cxx b/Source/cmIncludeGuardCommand.cxx new file mode 100644 index 0000000..505b07c --- /dev/null +++ b/Source/cmIncludeGuardCommand.cxx @@ -0,0 +1,108 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmIncludeGuardCommand.h" + +#include "cmExecutionStatus.h" +#include "cmMakefile.h" +#include "cmStateDirectory.h" +#include "cmStateSnapshot.h" +#include "cmSystemTools.h" +#include "cmake.h" + +namespace { + +enum IncludeGuardScope +{ + VARIABLE, + DIRECTORY, + GLOBAL +}; + +std::string GetIncludeGuardVariableName(std::string const& filePath) +{ + std::string result = "__INCGUARD_"; +#ifdef CMAKE_BUILD_WITH_CMAKE + result += cmSystemTools::ComputeStringMD5(filePath); +#else + result += cmSystemTools::MakeCidentifier(filePath); +#endif + result += "__"; + return result; +} + +bool CheckIncludeGuardIsSet(cmMakefile* mf, std::string const& includeGuardVar) +{ + if (mf->GetProperty(includeGuardVar)) { + return true; + } + cmStateSnapshot dirSnapshot = + mf->GetStateSnapshot().GetBuildsystemDirectoryParent(); + while (dirSnapshot.GetState()) { + cmStateDirectory stateDir = dirSnapshot.GetDirectory(); + if (stateDir.GetProperty(includeGuardVar)) { + return true; + } + dirSnapshot = dirSnapshot.GetBuildsystemDirectoryParent(); + } + return false; +} + +} // anonymous namespace + +// cmIncludeGuardCommand +bool cmIncludeGuardCommand::InitialPass(std::vector const& args, + cmExecutionStatus& status) +{ + if (args.size() > 1) { + this->SetError( + "given an invalid number of arguments. The command takes at " + "most 1 argument."); + return false; + } + + IncludeGuardScope scope = VARIABLE; + + if (!args.empty()) { + std::string const& arg = args[0]; + if (arg == "DIRECTORY") { + scope = DIRECTORY; + } else if (arg == "GLOBAL") { + scope = GLOBAL; + } else { + this->SetError("given an invalid scope: " + arg); + return false; + } + } + + std::string includeGuardVar = GetIncludeGuardVariableName( + this->Makefile->GetDefinition("CMAKE_CURRENT_LIST_FILE")); + + cmMakefile* const mf = this->Makefile; + + switch (scope) { + case VARIABLE: + if (mf->IsDefinitionSet(includeGuardVar)) { + status.SetReturnInvoked(); + return true; + } + mf->AddDefinition(includeGuardVar, true); + break; + case DIRECTORY: + if (CheckIncludeGuardIsSet(mf, includeGuardVar)) { + status.SetReturnInvoked(); + return true; + } + mf->SetProperty(includeGuardVar, "TRUE"); + break; + case GLOBAL: + cmake* const cm = mf->GetCMakeInstance(); + if (cm->GetProperty(includeGuardVar)) { + status.SetReturnInvoked(); + return true; + } + cm->SetProperty(includeGuardVar, "TRUE"); + break; + } + + return true; +} diff --git a/Source/cmIncludeGuardCommand.h b/Source/cmIncludeGuardCommand.h new file mode 100644 index 0000000..140c04f --- /dev/null +++ b/Source/cmIncludeGuardCommand.h @@ -0,0 +1,37 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmIncludeGuardCommand_h +#define cmIncludeGuardCommand_h + +#include "cmConfigure.h" + +#include +#include + +#include "cmCommand.h" + +class cmExecutionStatus; + +/** \class cmIncludeGuardCommand + * \brief cmIncludeGuardCommand identical to C++ #pragma_once command + * Can work in 3 modes: GLOBAL (works on global properties), + * DIRECTORY(use directory property), VARIABLE(unnamed overload without + * arguments) define an ordinary variable to be used as include guard checker + */ +class cmIncludeGuardCommand : public cmCommand +{ +public: + /** + * This is a virtual constructor for the command. + */ + cmCommand* Clone() CM_OVERRIDE { return new cmIncludeGuardCommand; } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + bool InitialPass(std::vector const& args, + cmExecutionStatus& status) CM_OVERRIDE; +}; + +#endif diff --git a/bootstrap b/bootstrap index ba2a5f3..83e67c5 100755 --- a/bootstrap +++ b/bootstrap @@ -330,6 +330,7 @@ CMAKE_CXX_SOURCES="\ cmHexFileConverter \ cmIfCommand \ cmIncludeCommand \ + cmIncludeGuardCommand \ cmIncludeDirectoryCommand \ cmIncludeRegularExpressionCommand \ cmInstallCommand \ -- cgit v0.12