You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

315 lines
8.0 KiB

23 years ago
23 years ago
23 years ago
23 years ago
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "cmLoadCommandCommand.h"
  14. #include "cmCPluginAPI.h"
  15. #include "cmCPluginAPI.cxx"
  16. #include "cmDynamicLoader.h"
  17. #include <cmsys/DynamicLoader.hxx>
  18. #include <stdlib.h>
  19. #ifdef __QNX__
  20. # include <malloc.h> /* for malloc/free on QNX */
  21. #endif
  22. #include <signal.h>
  23. extern "C" void TrapsForSignalsCFunction(int sig);
  24. // a class for loadabple commands
  25. class cmLoadedCommand : public cmCommand
  26. {
  27. public:
  28. cmLoadedCommand() {
  29. memset(&this->info,0,sizeof(this->info));
  30. this->info.CAPI = &cmStaticCAPI;
  31. }
  32. ///! clean up any memory allocated by the plugin
  33. ~cmLoadedCommand();
  34. /**
  35. * This is a virtual constructor for the command.
  36. */
  37. virtual cmCommand* Clone()
  38. {
  39. cmLoadedCommand *newC = new cmLoadedCommand;
  40. // we must copy when we clone
  41. memcpy(&newC->info,&this->info,sizeof(info));
  42. return newC;
  43. }
  44. /**
  45. * This is called when the command is first encountered in
  46. * the CMakeLists.txt file.
  47. */
  48. virtual bool InitialPass(std::vector<std::string> const& args);
  49. /**
  50. * This is called at the end after all the information
  51. * specified by the command is accumulated. Most commands do
  52. * not implement this method. At this point, reading and
  53. * writing to the cache can be done.
  54. */
  55. virtual void FinalPass();
  56. /**
  57. * The name of the command as specified in CMakeList.txt.
  58. */
  59. virtual const char* GetName() { return info.Name; }
  60. /**
  61. * Succinct documentation.
  62. */
  63. virtual const char* GetTerseDocumentation()
  64. {
  65. if (this->info.GetTerseDocumentation)
  66. {
  67. cmLoadedCommand::InstallSignalHandlers(info.Name);
  68. const char* ret = info.GetTerseDocumentation();
  69. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  70. return ret;
  71. }
  72. else
  73. {
  74. return "LoadedCommand without any additional documentation";
  75. }
  76. }
  77. static const char* LastName;
  78. static void TrapsForSignals(int sig)
  79. {
  80. fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n",
  81. cmLoadedCommand::LastName, sig);
  82. }
  83. static void InstallSignalHandlers(const char* name, int remove = 0)
  84. {
  85. cmLoadedCommand::LastName = name;
  86. if(!name)
  87. {
  88. cmLoadedCommand::LastName = "????";
  89. }
  90. if(!remove)
  91. {
  92. signal(SIGSEGV, TrapsForSignalsCFunction);
  93. #ifdef SIGBUS
  94. signal(SIGBUS, TrapsForSignalsCFunction);
  95. #endif
  96. signal(SIGILL, TrapsForSignalsCFunction);
  97. }
  98. else
  99. {
  100. signal(SIGSEGV, 0);
  101. #ifdef SIGBUS
  102. signal(SIGBUS, 0);
  103. #endif
  104. signal(SIGILL, 0);
  105. }
  106. }
  107. /**
  108. * More documentation.
  109. */
  110. virtual const char* GetFullDocumentation()
  111. {
  112. if (this->info.GetFullDocumentation)
  113. {
  114. cmLoadedCommand::InstallSignalHandlers(info.Name);
  115. const char* ret = info.GetFullDocumentation();
  116. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  117. return ret;
  118. }
  119. else
  120. {
  121. return "LoadedCommand without any additional documentation";
  122. }
  123. }
  124. cmTypeMacro(cmLoadedCommand, cmCommand);
  125. cmLoadedCommandInfo info;
  126. };
  127. extern "C" void TrapsForSignalsCFunction(int sig)
  128. {
  129. cmLoadedCommand::TrapsForSignals(sig);
  130. }
  131. const char* cmLoadedCommand::LastName = 0;
  132. bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args)
  133. {
  134. if (!info.InitialPass)
  135. {
  136. return true;
  137. }
  138. // clear the error string
  139. if (this->info.Error)
  140. {
  141. free(this->info.Error);
  142. }
  143. // create argc and argv and then invoke the command
  144. int argc = static_cast<int> (args.size());
  145. char **argv = 0;
  146. if (argc)
  147. {
  148. argv = (char **)malloc(argc*sizeof(char *));
  149. }
  150. int i;
  151. for (i = 0; i < argc; ++i)
  152. {
  153. argv[i] = strdup(args[i].c_str());
  154. }
  155. cmLoadedCommand::InstallSignalHandlers(info.Name);
  156. int result = info.InitialPass((void *)&info,
  157. (void *)this->Makefile,argc,argv);
  158. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  159. cmFreeArguments(argc,argv);
  160. if (result)
  161. {
  162. return true;
  163. }
  164. /* Initial Pass must have failed so set the error string */
  165. if (this->info.Error)
  166. {
  167. this->SetError(this->info.Error);
  168. }
  169. return false;
  170. }
  171. void cmLoadedCommand::FinalPass()
  172. {
  173. if (this->info.FinalPass)
  174. {
  175. cmLoadedCommand::InstallSignalHandlers(info.Name);
  176. this->info.FinalPass((void *)&this->info,(void *)this->Makefile);
  177. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  178. }
  179. }
  180. cmLoadedCommand::~cmLoadedCommand()
  181. {
  182. if (this->info.Destructor)
  183. {
  184. cmLoadedCommand::InstallSignalHandlers(info.Name);
  185. this->info.Destructor((void *)&this->info);
  186. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  187. }
  188. if (this->info.Error)
  189. {
  190. free(this->info.Error);
  191. }
  192. }
  193. // cmLoadCommandCommand
  194. bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args)
  195. {
  196. if(args.size() < 1 )
  197. {
  198. return true;
  199. }
  200. // Construct a variable to report what file was loaded, if any.
  201. // Start by removing the definition in case of failure.
  202. std::string reportVar = "CMAKE_LOADED_COMMAND_";
  203. reportVar += args[0];
  204. this->Makefile->RemoveDefinition(reportVar.c_str());
  205. // the file must exist
  206. std::string moduleName =
  207. this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX");
  208. moduleName += "cm" + args[0];
  209. moduleName +=
  210. this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX");
  211. // search for the file
  212. std::vector<std::string> path;
  213. for (unsigned int j = 1; j < args.size(); j++)
  214. {
  215. // expand variables
  216. std::string exp = args[j];
  217. cmSystemTools::ExpandRegistryValues(exp);
  218. // Glob the entry in case of wildcards.
  219. cmSystemTools::GlobDirs(exp.c_str(), path);
  220. }
  221. // Try to find the program.
  222. std::string fullPath = cmSystemTools::FindFile(moduleName.c_str(), path);
  223. if (fullPath == "")
  224. {
  225. cmOStringStream e;
  226. e << "Attempt to load command failed from file \""
  227. << moduleName << "\"";
  228. this->SetError(e.str().c_str());
  229. return false;
  230. }
  231. // try loading the shared library / dll
  232. cmsys::DynamicLoader::LibraryHandle lib
  233. = cmDynamicLoader::OpenLibrary(fullPath.c_str());
  234. if(!lib)
  235. {
  236. std::string err = "Attempt to load the library ";
  237. err += fullPath + " failed.";
  238. const char* error = cmsys::DynamicLoader::LastError();
  239. if ( error )
  240. {
  241. err += " Additional error info is:\n";
  242. err += error;
  243. }
  244. this->SetError(err.c_str());
  245. return false;
  246. }
  247. // Report what file was loaded for this command.
  248. this->Makefile->AddDefinition(reportVar.c_str(), fullPath.c_str());
  249. // find the init function
  250. std::string initFuncName = args[0] + "Init";
  251. CM_INIT_FUNCTION initFunction
  252. = (CM_INIT_FUNCTION)
  253. cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str());
  254. if ( !initFunction )
  255. {
  256. initFuncName = "_";
  257. initFuncName += args[0];
  258. initFuncName += "Init";
  259. initFunction = (CM_INIT_FUNCTION)(
  260. cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str()));
  261. }
  262. // if the symbol is found call it to set the name on the
  263. // function blocker
  264. if(initFunction)
  265. {
  266. // create a function blocker and set it up
  267. cmLoadedCommand *f = new cmLoadedCommand();
  268. (*initFunction)(&f->info);
  269. this->Makefile->AddCommand(f);
  270. return true;
  271. }
  272. this->SetError("Attempt to load command failed. "
  273. "No init function found.");
  274. return false;
  275. }