|
|
/*=========================================================================
Program: CMake - Cross-Platform Makefile Generator Module: $RCSfile$ Language: C++ Date: $Date$ Version: $Revision$
Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices 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);
/**
* 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();
/**
* The name of the command as specified in CMakeList.txt. */ virtual const char* GetName() { return info.Name; } /**
* Succinct documentation. */ virtual const char* GetTerseDocumentation() { 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() { 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) { 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) { 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; }
|