diff options
Diffstat (limited to 'Source/cmLoadCommandCommand.cxx')
-rw-r--r-- | Source/cmLoadCommandCommand.cxx | 214 |
1 files changed, 110 insertions, 104 deletions
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index 69751b6..180e65b 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -3,16 +3,21 @@ #include "cmLoadCommandCommand.h" #include <signal.h> + #include <sstream> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <utility> + +#include "cm_memory.hxx" #include "cmCPluginAPI.cxx" #include "cmCPluginAPI.h" #include "cmDynamicLoader.h" #include "cmMakefile.h" #include "cmState.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" class cmExecutionStatus; @@ -21,30 +26,98 @@ class cmExecutionStatus; # include <malloc.h> /* for malloc/free on QNX */ #endif -extern "C" void TrapsForSignalsCFunction(int sig); +namespace { + +const char* LastName = nullptr; + +extern "C" void TrapsForSignals(int sig) +{ + fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n", + LastName, sig); +} + +struct SignalHandlerGuard +{ + explicit SignalHandlerGuard(const char* name) + { + LastName = name != nullptr ? name : "????"; + + signal(SIGSEGV, TrapsForSignals); +#ifdef SIGBUS + signal(SIGBUS, TrapsForSignals); +#endif + signal(SIGILL, TrapsForSignals); + } + + ~SignalHandlerGuard() + { + signal(SIGSEGV, nullptr); +#ifdef SIGBUS + signal(SIGBUS, nullptr); +#endif + signal(SIGILL, nullptr); + } + + SignalHandlerGuard(SignalHandlerGuard const&) = delete; + SignalHandlerGuard& operator=(SignalHandlerGuard const&) = delete; +}; + +struct LoadedCommandImpl : cmLoadedCommandInfo +{ + explicit LoadedCommandImpl(CM_INIT_FUNCTION init) + : cmLoadedCommandInfo{ 0, 0, &cmStaticCAPI, 0, + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr } + { + init(this); + } + + ~LoadedCommandImpl() + { + if (this->Destructor) { + SignalHandlerGuard guard(this->Name); + this->Destructor(this); + } + if (this->Error != nullptr) { + free(this->Error); + } + } + + LoadedCommandImpl(LoadedCommandImpl const&) = delete; + LoadedCommandImpl& operator=(LoadedCommandImpl const&) = delete; + + int DoInitialPass(cmMakefile* mf, int argc, char* argv[]) + { + SignalHandlerGuard guard(this->Name); + return this->InitialPass(this, mf, argc, argv); + } + + void DoFinalPass(cmMakefile* mf) + { + SignalHandlerGuard guard(this->Name); + this->FinalPass(this, mf); + } +}; // a class for loadabple commands class cmLoadedCommand : public cmCommand { public: - cmLoadedCommand() + cmLoadedCommand() = default; + explicit cmLoadedCommand(CM_INIT_FUNCTION init) + : Impl(std::make_shared<LoadedCommandImpl>(init)) { - memset(&this->info, 0, sizeof(this->info)); - this->info.CAPI = &cmStaticCAPI; } - //! clean up any memory allocated by the plugin - ~cmLoadedCommand() override; - /** * This is a virtual constructor for the command. */ - cmCommand* Clone() override + std::unique_ptr<cmCommand> Clone() override { - cmLoadedCommand* newC = new cmLoadedCommand; + auto newC = cm::make_unique<cmLoadedCommand>(); // we must copy when we clone - memcpy(&newC->info, &this->info, sizeof(info)); - return newC; + newC->Impl = this->Impl; + return std::unique_ptr<cmCommand>(std::move(newC)); } /** @@ -54,66 +127,20 @@ public: bool InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) override; - /** - * This is called at the end after all the information - * specified by the command is accumulated. Most commands do - * not implement this method. At this point, reading and - * writing to the cache can be done. - */ - void FinalPass() override; - bool HasFinalPass() const override - { - return this->info.FinalPass != nullptr; - } - - static const char* LastName; - static void TrapsForSignals(int sig) - { - fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n", - cmLoadedCommand::LastName, sig); - } - static void InstallSignalHandlers(const char* name, int remove = 0) - { - cmLoadedCommand::LastName = name; - if (!name) { - cmLoadedCommand::LastName = "????"; - } - - if (!remove) { - signal(SIGSEGV, TrapsForSignalsCFunction); -#ifdef SIGBUS - signal(SIGBUS, TrapsForSignalsCFunction); -#endif - signal(SIGILL, TrapsForSignalsCFunction); - } else { - signal(SIGSEGV, nullptr); -#ifdef SIGBUS - signal(SIGBUS, nullptr); -#endif - signal(SIGILL, nullptr); - } - } - - cmLoadedCommandInfo info; +private: + std::shared_ptr<LoadedCommandImpl> Impl; }; -extern "C" void TrapsForSignalsCFunction(int sig) -{ - cmLoadedCommand::TrapsForSignals(sig); -} - -const char* cmLoadedCommand::LastName = nullptr; - bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (!info.InitialPass) { + if (!this->Impl->InitialPass) { return true; } // clear the error string - if (this->info.Error) { - free(this->info.Error); + if (this->Impl->Error) { + free(this->Impl->Error); } // create argc and argv and then invoke the command @@ -126,42 +153,26 @@ bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args, for (i = 0; i < argc; ++i) { argv[i] = strdup(args[i].c_str()); } - cmLoadedCommand::InstallSignalHandlers(info.Name); - int result = info.InitialPass(&info, this->Makefile, argc, argv); - cmLoadedCommand::InstallSignalHandlers(info.Name, 1); + int result = this->Impl->DoInitialPass(this->Makefile, argc, argv); cmFreeArguments(argc, argv); if (result) { + if (this->Impl->FinalPass) { + auto impl = this->Impl; + this->Makefile->AddFinalAction( + [impl](cmMakefile& makefile) { impl->DoFinalPass(&makefile); }); + } return true; } /* Initial Pass must have failed so set the error string */ - if (this->info.Error) { - this->SetError(this->info.Error); + if (this->Impl->Error) { + this->SetError(this->Impl->Error); } return false; } -void cmLoadedCommand::FinalPass() -{ - if (this->info.FinalPass) { - cmLoadedCommand::InstallSignalHandlers(info.Name); - this->info.FinalPass(&this->info, this->Makefile); - cmLoadedCommand::InstallSignalHandlers(info.Name, 1); - } -} - -cmLoadedCommand::~cmLoadedCommand() -{ - if (this->info.Destructor) { - cmLoadedCommand::InstallSignalHandlers(info.Name); - this->info.Destructor(&this->info); - cmLoadedCommand::InstallSignalHandlers(info.Name, 1); - } - if (this->info.Error) { - free(this->info.Error); - } -} +} // namespace // cmLoadCommandCommand bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args, @@ -173,16 +184,14 @@ bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args, // Construct a variable to report what file was loaded, if any. // Start by removing the definition in case of failure. - std::string reportVar = "CMAKE_LOADED_COMMAND_"; - reportVar += args[0]; + std::string reportVar = cmStrCat("CMAKE_LOADED_COMMAND_", args[0]); this->Makefile->RemoveDefinition(reportVar); // the file must exist - std::string moduleName = - this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX"); - moduleName += "cm" + args[0]; - moduleName += - this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX"); + std::string moduleName = cmStrCat( + this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX"), "cm", + args[0], + this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX")); // search for the file std::vector<std::string> path; @@ -208,8 +217,8 @@ bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args, cmsys::DynamicLoader::LibraryHandle lib = cmDynamicLoader::OpenLibrary(fullPath.c_str()); if (!lib) { - std::string err = "Attempt to load the library "; - err += fullPath + " failed."; + std::string err = + cmStrCat("Attempt to load the library ", fullPath, " failed."); const char* error = cmsys::DynamicLoader::LastError(); if (error) { err += " Additional error info is:\n"; @@ -220,26 +229,23 @@ bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args, } // Report what file was loaded for this command. - this->Makefile->AddDefinition(reportVar, fullPath.c_str()); + this->Makefile->AddDefinition(reportVar, fullPath); // find the init function std::string initFuncName = args[0] + "Init"; CM_INIT_FUNCTION initFunction = reinterpret_cast<CM_INIT_FUNCTION>( cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName)); if (!initFunction) { - initFuncName = "_"; - initFuncName += args[0]; - initFuncName += "Init"; + initFuncName = cmStrCat('_', args[0], "Init"); initFunction = reinterpret_cast<CM_INIT_FUNCTION>( cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName)); } // if the symbol is found call it to set the name on the // function blocker if (initFunction) { - // create a function blocker and set it up - cmLoadedCommand* f = new cmLoadedCommand(); - (*initFunction)(&f->info); - this->Makefile->GetState()->AddScriptedCommand(args[0], f); + this->Makefile->GetState()->AddScriptedCommand( + args[0], + cmLegacyCommandWrapper(cm::make_unique<cmLoadedCommand>(initFunction))); return true; } this->SetError("Attempt to load command failed. " |