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