Clarify documentation for if.
[cmake.git] / Source / cmLoadCommandCommand.cxx
blob141fe15ea4fa59dd51a2c934a672484b93cfd489
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmLoadCommandCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2009-07-24 17:31:34 $
7 Version: $Revision: 1.30 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmLoadCommandCommand.h"
18 #include "cmCPluginAPI.h"
19 #include "cmCPluginAPI.cxx"
20 #include "cmDynamicLoader.h"
22 #include <cmsys/DynamicLoader.hxx>
24 #include <stdlib.h>
26 #ifdef __QNX__
27 # include <malloc.h> /* for malloc/free on QNX */
28 #endif
30 #include <signal.h>
31 extern "C" void TrapsForSignalsCFunction(int sig);
34 // a class for loadabple commands
35 class cmLoadedCommand : public cmCommand
37 public:
38 cmLoadedCommand() {
39 memset(&this->info,0,sizeof(this->info));
40 this->info.CAPI = &cmStaticCAPI;
43 ///! clean up any memory allocated by the plugin
44 ~cmLoadedCommand();
46 /**
47 * This is a virtual constructor for the command.
49 virtual cmCommand* Clone()
51 cmLoadedCommand *newC = new cmLoadedCommand;
52 // we must copy when we clone
53 memcpy(&newC->info,&this->info,sizeof(info));
54 return newC;
57 /**
58 * This is called when the command is first encountered in
59 * the CMakeLists.txt file.
61 virtual bool InitialPass(std::vector<std::string> const& args,
62 cmExecutionStatus &);
64 /**
65 * This is called at the end after all the information
66 * specified by the command is accumulated. Most commands do
67 * not implement this method. At this point, reading and
68 * writing to the cache can be done.
70 virtual void FinalPass();
71 virtual bool HasFinalPass() const
72 { return this->info.FinalPass? true:false; }
74 /**
75 * The name of the command as specified in CMakeList.txt.
77 virtual const char* GetName() { return info.Name; }
79 /**
80 * Succinct documentation.
82 virtual const char* GetTerseDocumentation()
84 if (this->info.GetTerseDocumentation)
86 cmLoadedCommand::InstallSignalHandlers(info.Name);
87 const char* ret = info.GetTerseDocumentation();
88 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
89 return ret;
91 else
93 return "LoadedCommand without any additional documentation";
96 static const char* LastName;
97 static void TrapsForSignals(int sig)
99 fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n",
100 cmLoadedCommand::LastName, sig);
102 static void InstallSignalHandlers(const char* name, int remove = 0)
104 cmLoadedCommand::LastName = name;
105 if(!name)
107 cmLoadedCommand::LastName = "????";
110 if(!remove)
112 signal(SIGSEGV, TrapsForSignalsCFunction);
113 #ifdef SIGBUS
114 signal(SIGBUS, TrapsForSignalsCFunction);
115 #endif
116 signal(SIGILL, TrapsForSignalsCFunction);
118 else
120 signal(SIGSEGV, 0);
121 #ifdef SIGBUS
122 signal(SIGBUS, 0);
123 #endif
124 signal(SIGILL, 0);
129 * More documentation.
131 virtual const char* GetFullDocumentation()
133 if (this->info.GetFullDocumentation)
135 cmLoadedCommand::InstallSignalHandlers(info.Name);
136 const char* ret = info.GetFullDocumentation();
137 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
138 return ret;
140 else
142 return "LoadedCommand without any additional documentation";
146 cmTypeMacro(cmLoadedCommand, cmCommand);
148 cmLoadedCommandInfo info;
151 extern "C" void TrapsForSignalsCFunction(int sig)
153 cmLoadedCommand::TrapsForSignals(sig);
157 const char* cmLoadedCommand::LastName = 0;
159 bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args,
160 cmExecutionStatus &)
162 if (!info.InitialPass)
164 return true;
167 // clear the error string
168 if (this->info.Error)
170 free(this->info.Error);
173 // create argc and argv and then invoke the command
174 int argc = static_cast<int> (args.size());
175 char **argv = 0;
176 if (argc)
178 argv = (char **)malloc(argc*sizeof(char *));
180 int i;
181 for (i = 0; i < argc; ++i)
183 argv[i] = strdup(args[i].c_str());
185 cmLoadedCommand::InstallSignalHandlers(info.Name);
186 int result = info.InitialPass((void *)&info,
187 (void *)this->Makefile,argc,argv);
188 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
189 cmFreeArguments(argc,argv);
191 if (result)
193 return true;
196 /* Initial Pass must have failed so set the error string */
197 if (this->info.Error)
199 this->SetError(this->info.Error);
201 return false;
204 void cmLoadedCommand::FinalPass()
206 if (this->info.FinalPass)
208 cmLoadedCommand::InstallSignalHandlers(info.Name);
209 this->info.FinalPass((void *)&this->info,(void *)this->Makefile);
210 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
214 cmLoadedCommand::~cmLoadedCommand()
216 if (this->info.Destructor)
218 cmLoadedCommand::InstallSignalHandlers(info.Name);
219 this->info.Destructor((void *)&this->info);
220 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
222 if (this->info.Error)
224 free(this->info.Error);
228 // cmLoadCommandCommand
229 bool cmLoadCommandCommand
230 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
232 if(args.size() < 1 )
234 return true;
237 // Construct a variable to report what file was loaded, if any.
238 // Start by removing the definition in case of failure.
239 std::string reportVar = "CMAKE_LOADED_COMMAND_";
240 reportVar += args[0];
241 this->Makefile->RemoveDefinition(reportVar.c_str());
243 // the file must exist
244 std::string moduleName =
245 this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX");
246 moduleName += "cm" + args[0];
247 moduleName +=
248 this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX");
250 // search for the file
251 std::vector<std::string> path;
252 for (unsigned int j = 1; j < args.size(); j++)
254 // expand variables
255 std::string exp = args[j];
256 cmSystemTools::ExpandRegistryValues(exp);
258 // Glob the entry in case of wildcards.
259 cmSystemTools::GlobDirs(exp.c_str(), path);
262 // Try to find the program.
263 std::string fullPath = cmSystemTools::FindFile(moduleName.c_str(), path);
264 if (fullPath == "")
266 cmOStringStream e;
267 e << "Attempt to load command failed from file \""
268 << moduleName << "\"";
269 this->SetError(e.str().c_str());
270 return false;
273 // try loading the shared library / dll
274 cmsys::DynamicLoader::LibraryHandle lib
275 = cmDynamicLoader::OpenLibrary(fullPath.c_str());
276 if(!lib)
278 std::string err = "Attempt to load the library ";
279 err += fullPath + " failed.";
280 const char* error = cmsys::DynamicLoader::LastError();
281 if ( error )
283 err += " Additional error info is:\n";
284 err += error;
286 this->SetError(err.c_str());
287 return false;
290 // Report what file was loaded for this command.
291 this->Makefile->AddDefinition(reportVar.c_str(), fullPath.c_str());
293 // find the init function
294 std::string initFuncName = args[0] + "Init";
295 CM_INIT_FUNCTION initFunction
296 = (CM_INIT_FUNCTION)
297 cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str());
298 if ( !initFunction )
300 initFuncName = "_";
301 initFuncName += args[0];
302 initFuncName += "Init";
303 initFunction = (CM_INIT_FUNCTION)(
304 cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str()));
306 // if the symbol is found call it to set the name on the
307 // function blocker
308 if(initFunction)
310 // create a function blocker and set it up
311 cmLoadedCommand *f = new cmLoadedCommand();
312 (*initFunction)(&f->info);
313 this->Makefile->AddCommand(f);
314 return true;
316 this->SetError("Attempt to load command failed. "
317 "No init function found.");
318 return false;