diff options
Diffstat (limited to 'Source/cmLoadCommandCommand.cxx')
-rw-r--r-- | Source/cmLoadCommandCommand.cxx | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx new file mode 100644 index 000000000..3a0115c96 --- /dev/null +++ b/Source/cmLoadCommandCommand.cxx @@ -0,0 +1,315 @@ +/*============================================================================ + 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.h" +#include "cmCPluginAPI.cxx" +#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(); + + /** + * This is a virtual constructor for the command. + */ + virtual cmCommand* Clone() + { + 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. + */ + virtual bool InitialPass(std::vector<std::string> const& args, + cmExecutionStatus &); + + /** + * 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. + */ + virtual void FinalPass(); + virtual bool HasFinalPass() const + { return this->info.FinalPass? true:false; } + + /** + * The name of the command as specified in CMakeList.txt. + */ + virtual const char* GetName() const { return info.Name; } + + /** + * Succinct documentation. + */ + virtual const char* GetTerseDocumentation() const + { + if (this->info.GetTerseDocumentation) + { + cmLoadedCommand::InstallSignalHandlers(info.Name); + const char* ret = info.GetTerseDocumentation(); + cmLoadedCommand::InstallSignalHandlers(info.Name, 1); + return ret; + } + else + { + return "LoadedCommand without any additional documentation"; + } + } + 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, 0); +#ifdef SIGBUS + signal(SIGBUS, 0); +#endif + signal(SIGILL, 0); + } + } + + /** + * More documentation. + */ + virtual const char* GetFullDocumentation() const + { + if (this->info.GetFullDocumentation) + { + cmLoadedCommand::InstallSignalHandlers(info.Name); + const char* ret = info.GetFullDocumentation(); + cmLoadedCommand::InstallSignalHandlers(info.Name, 1); + return ret; + } + else + { + return "LoadedCommand without any additional documentation"; + } + } + + cmTypeMacro(cmLoadedCommand, cmCommand); + + cmLoadedCommandInfo info; +}; + +extern "C" void TrapsForSignalsCFunction(int sig) +{ + cmLoadedCommand::TrapsForSignals(sig); +} + + +const char* cmLoadedCommand::LastName = 0; + +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 = 0; + 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(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.c_str()); + + // 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.c_str(), path); + } + + // Try to find the program. + std::string fullPath = cmSystemTools::FindFile(moduleName.c_str(), path); + if (fullPath == "") + { + cmOStringStream e; + e << "Attempt to load command failed from file \"" + << moduleName << "\""; + this->SetError(e.str().c_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.c_str()); + return false; + } + + // Report what file was loaded for this command. + this->Makefile->AddDefinition(reportVar.c_str(), 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->AddCommand(f); + return true; + } + this->SetError("Attempt to load command failed. " + "No init function found."); + return false; +} + |