diff options
Diffstat (limited to 'Source/cmLoadCommandCommand.cxx')
-rw-r--r-- | Source/cmLoadCommandCommand.cxx | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx new file mode 100644 index 0000000..ddf6ce6 --- /dev/null +++ b/Source/cmLoadCommandCommand.cxx @@ -0,0 +1,265 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 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 "cmLoadCommandCommand.h" + +#include "cmCPluginAPI.cxx" +#include "cmCPluginAPI.h" +#include "cmDynamicLoader.h" + +#include <cmsys/DynamicLoader.hxx> + +#include <stdlib.h> + +#ifdef __QNX__ +#include <malloc.h> /* for malloc/free on QNX */ +#endif + +#include <signal.h> +extern "C" void TrapsForSignalsCFunction(int sig); + +// a class for loadabple commands +class cmLoadedCommand : public cmCommand +{ +public: + cmLoadedCommand() + { + memset(&this->info, 0, sizeof(this->info)); + this->info.CAPI = &cmStaticCAPI; + } + + ///! clean up any memory allocated by the plugin + ~cmLoadedCommand() CM_OVERRIDE; + + /** + * This is a virtual constructor for the command. + */ + cmCommand* Clone() CM_OVERRIDE + { + cmLoadedCommand* newC = new cmLoadedCommand; + // we must copy when we clone + memcpy(&newC->info, &this->info, sizeof(info)); + return newC; + } + + /** + * This is called when the command is first encountered in + * the CMakeLists.txt file. + */ + bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus&) CM_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() CM_OVERRIDE; + bool HasFinalPass() const CM_OVERRIDE + { + return this->info.FinalPass ? true : false; + } + + /** + * The name of the command as specified in CMakeList.txt. + */ + std::string GetName() const CM_OVERRIDE { return info.Name; } + + 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, CM_NULLPTR); +#ifdef SIGBUS + signal(SIGBUS, CM_NULLPTR); +#endif + signal(SIGILL, CM_NULLPTR); + } + } + + cmTypeMacro(cmLoadedCommand, cmCommand); + + cmLoadedCommandInfo info; +}; + +extern "C" void TrapsForSignalsCFunction(int sig) +{ + cmLoadedCommand::TrapsForSignals(sig); +} + +const char* cmLoadedCommand::LastName = CM_NULLPTR; + +bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args, + cmExecutionStatus&) +{ + if (!info.InitialPass) { + return true; + } + + // clear the error string + if (this->info.Error) { + free(this->info.Error); + } + + // create argc and argv and then invoke the command + int argc = static_cast<int>(args.size()); + char** argv = CM_NULLPTR; + if (argc) { + argv = (char**)malloc(argc * sizeof(char*)); + } + int i; + for (i = 0; i < argc; ++i) { + argv[i] = strdup(args[i].c_str()); + } + cmLoadedCommand::InstallSignalHandlers(info.Name); + int result = + info.InitialPass((void*)&info, (void*)this->Makefile, argc, argv); + cmLoadedCommand::InstallSignalHandlers(info.Name, 1); + cmFreeArguments(argc, argv); + + if (result) { + return true; + } + + /* Initial Pass must have failed so set the error string */ + if (this->info.Error) { + this->SetError(this->info.Error); + } + return false; +} + +void cmLoadedCommand::FinalPass() +{ + if (this->info.FinalPass) { + cmLoadedCommand::InstallSignalHandlers(info.Name); + this->info.FinalPass((void*)&this->info, (void*)this->Makefile); + cmLoadedCommand::InstallSignalHandlers(info.Name, 1); + } +} + +cmLoadedCommand::~cmLoadedCommand() +{ + if (this->info.Destructor) { + cmLoadedCommand::InstallSignalHandlers(info.Name); + this->info.Destructor((void*)&this->info); + cmLoadedCommand::InstallSignalHandlers(info.Name, 1); + } + if (this->info.Error) { + free(this->info.Error); + } +} + +// cmLoadCommandCommand +bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args, + cmExecutionStatus&) +{ + if (this->Disallowed( + cmPolicies::CMP0031, + "The load_command command should not be called; see CMP0031.")) { + return true; + } + if (args.size() < 1) { + return true; + } + + // 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]; + 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"); + + // search for the file + std::vector<std::string> path; + for (unsigned int j = 1; j < args.size(); j++) { + // expand variables + std::string exp = args[j]; + cmSystemTools::ExpandRegistryValues(exp); + + // Glob the entry in case of wildcards. + cmSystemTools::GlobDirs(exp, path); + } + + // Try to find the program. + std::string fullPath = cmSystemTools::FindFile(moduleName.c_str(), path); + if (fullPath == "") { + std::ostringstream e; + e << "Attempt to load command failed from file \"" << moduleName << "\""; + this->SetError(e.str()); + return false; + } + + // try loading the shared library / dll + cmsys::DynamicLoader::LibraryHandle lib = + cmDynamicLoader::OpenLibrary(fullPath.c_str()); + if (!lib) { + std::string err = "Attempt to load the library "; + err += fullPath + " failed."; + const char* error = cmsys::DynamicLoader::LastError(); + if (error) { + err += " Additional error info is:\n"; + err += error; + } + this->SetError(err); + return false; + } + + // Report what file was loaded for this command. + this->Makefile->AddDefinition(reportVar, fullPath.c_str()); + + // find the init function + std::string initFuncName = args[0] + "Init"; + CM_INIT_FUNCTION initFunction = + (CM_INIT_FUNCTION)cmsys::DynamicLoader::GetSymbolAddress( + lib, initFuncName.c_str()); + if (!initFunction) { + initFuncName = "_"; + initFuncName += args[0]; + initFuncName += "Init"; + initFunction = (CM_INIT_FUNCTION)( + cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str())); + } + // 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()->AddCommand(f); + return true; + } + this->SetError("Attempt to load command failed. " + "No init function found."); + return false; +} |