1
0

cmLoadCommandCommand.cxx 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  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. cmExecutionStatus &);
  50. /**
  51. * This is called at the end after all the information
  52. * specified by the command is accumulated. Most commands do
  53. * not implement this method. At this point, reading and
  54. * writing to the cache can be done.
  55. */
  56. virtual void FinalPass();
  57. virtual bool HasFinalPass() const
  58. { return this->info.FinalPass? true:false; }
  59. /**
  60. * The name of the command as specified in CMakeList.txt.
  61. */
  62. virtual const char* GetName() { return info.Name; }
  63. /**
  64. * Succinct documentation.
  65. */
  66. virtual const char* GetTerseDocumentation()
  67. {
  68. if (this->info.GetTerseDocumentation)
  69. {
  70. cmLoadedCommand::InstallSignalHandlers(info.Name);
  71. const char* ret = info.GetTerseDocumentation();
  72. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  73. return ret;
  74. }
  75. else
  76. {
  77. return "LoadedCommand without any additional documentation";
  78. }
  79. }
  80. static const char* LastName;
  81. static void TrapsForSignals(int sig)
  82. {
  83. fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n",
  84. cmLoadedCommand::LastName, sig);
  85. }
  86. static void InstallSignalHandlers(const char* name, int remove = 0)
  87. {
  88. cmLoadedCommand::LastName = name;
  89. if(!name)
  90. {
  91. cmLoadedCommand::LastName = "????";
  92. }
  93. if(!remove)
  94. {
  95. signal(SIGSEGV, TrapsForSignalsCFunction);
  96. #ifdef SIGBUS
  97. signal(SIGBUS, TrapsForSignalsCFunction);
  98. #endif
  99. signal(SIGILL, TrapsForSignalsCFunction);
  100. }
  101. else
  102. {
  103. signal(SIGSEGV, 0);
  104. #ifdef SIGBUS
  105. signal(SIGBUS, 0);
  106. #endif
  107. signal(SIGILL, 0);
  108. }
  109. }
  110. /**
  111. * More documentation.
  112. */
  113. virtual const char* GetFullDocumentation()
  114. {
  115. if (this->info.GetFullDocumentation)
  116. {
  117. cmLoadedCommand::InstallSignalHandlers(info.Name);
  118. const char* ret = info.GetFullDocumentation();
  119. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  120. return ret;
  121. }
  122. else
  123. {
  124. return "LoadedCommand without any additional documentation";
  125. }
  126. }
  127. cmTypeMacro(cmLoadedCommand, cmCommand);
  128. cmLoadedCommandInfo info;
  129. };
  130. extern "C" void TrapsForSignalsCFunction(int sig)
  131. {
  132. cmLoadedCommand::TrapsForSignals(sig);
  133. }
  134. const char* cmLoadedCommand::LastName = 0;
  135. bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args,
  136. cmExecutionStatus &)
  137. {
  138. if (!info.InitialPass)
  139. {
  140. return true;
  141. }
  142. // clear the error string
  143. if (this->info.Error)
  144. {
  145. free(this->info.Error);
  146. }
  147. // create argc and argv and then invoke the command
  148. int argc = static_cast<int> (args.size());
  149. char **argv = 0;
  150. if (argc)
  151. {
  152. argv = (char **)malloc(argc*sizeof(char *));
  153. }
  154. int i;
  155. for (i = 0; i < argc; ++i)
  156. {
  157. argv[i] = strdup(args[i].c_str());
  158. }
  159. cmLoadedCommand::InstallSignalHandlers(info.Name);
  160. int result = info.InitialPass((void *)&info,
  161. (void *)this->Makefile,argc,argv);
  162. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  163. cmFreeArguments(argc,argv);
  164. if (result)
  165. {
  166. return true;
  167. }
  168. /* Initial Pass must have failed so set the error string */
  169. if (this->info.Error)
  170. {
  171. this->SetError(this->info.Error);
  172. }
  173. return false;
  174. }
  175. void cmLoadedCommand::FinalPass()
  176. {
  177. if (this->info.FinalPass)
  178. {
  179. cmLoadedCommand::InstallSignalHandlers(info.Name);
  180. this->info.FinalPass((void *)&this->info,(void *)this->Makefile);
  181. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  182. }
  183. }
  184. cmLoadedCommand::~cmLoadedCommand()
  185. {
  186. if (this->info.Destructor)
  187. {
  188. cmLoadedCommand::InstallSignalHandlers(info.Name);
  189. this->info.Destructor((void *)&this->info);
  190. cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
  191. }
  192. if (this->info.Error)
  193. {
  194. free(this->info.Error);
  195. }
  196. }
  197. // cmLoadCommandCommand
  198. bool cmLoadCommandCommand
  199. ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
  200. {
  201. if(args.size() < 1 )
  202. {
  203. return true;
  204. }
  205. // Construct a variable to report what file was loaded, if any.
  206. // Start by removing the definition in case of failure.
  207. std::string reportVar = "CMAKE_LOADED_COMMAND_";
  208. reportVar += args[0];
  209. this->Makefile->RemoveDefinition(reportVar.c_str());
  210. // the file must exist
  211. std::string moduleName =
  212. this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX");
  213. moduleName += "cm" + args[0];
  214. moduleName +=
  215. this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX");
  216. // search for the file
  217. std::vector<std::string> path;
  218. for (unsigned int j = 1; j < args.size(); j++)
  219. {
  220. // expand variables
  221. std::string exp = args[j];
  222. cmSystemTools::ExpandRegistryValues(exp);
  223. // Glob the entry in case of wildcards.
  224. cmSystemTools::GlobDirs(exp.c_str(), path);
  225. }
  226. // Try to find the program.
  227. std::string fullPath = cmSystemTools::FindFile(moduleName.c_str(), path);
  228. if (fullPath == "")
  229. {
  230. cmOStringStream e;
  231. e << "Attempt to load command failed from file \""
  232. << moduleName << "\"";
  233. this->SetError(e.str().c_str());
  234. return false;
  235. }
  236. // try loading the shared library / dll
  237. cmsys::DynamicLoader::LibraryHandle lib
  238. = cmDynamicLoader::OpenLibrary(fullPath.c_str());
  239. if(!lib)
  240. {
  241. std::string err = "Attempt to load the library ";
  242. err += fullPath + " failed.";
  243. const char* error = cmsys::DynamicLoader::LastError();
  244. if ( error )
  245. {
  246. err += " Additional error info is:\n";
  247. err += error;
  248. }
  249. this->SetError(err.c_str());
  250. return false;
  251. }
  252. // Report what file was loaded for this command.
  253. this->Makefile->AddDefinition(reportVar.c_str(), fullPath.c_str());
  254. // find the init function
  255. std::string initFuncName = args[0] + "Init";
  256. CM_INIT_FUNCTION initFunction
  257. = (CM_INIT_FUNCTION)
  258. cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str());
  259. if ( !initFunction )
  260. {
  261. initFuncName = "_";
  262. initFuncName += args[0];
  263. initFuncName += "Init";
  264. initFunction = (CM_INIT_FUNCTION)(
  265. cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str()));
  266. }
  267. // if the symbol is found call it to set the name on the
  268. // function blocker
  269. if(initFunction)
  270. {
  271. // create a function blocker and set it up
  272. cmLoadedCommand *f = new cmLoadedCommand();
  273. (*initFunction)(&f->info);
  274. this->Makefile->AddCommand(f);
  275. return true;
  276. }
  277. this->SetError("Attempt to load command failed. "
  278. "No init function found.");
  279. return false;
  280. }