STYLE: Fix typo in GetFilenameLastExtension docs
[cmake.git] / Source / cmLoadCommandCommand.cxx
blob246e60cd65c910152c05fe20bc4fd6338efffa87
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmLoadCommandCommand.cxx,v $
5 Language: C++
6 Date: $Date: 2008-01-23 15:27:59 $
7 Version: $Revision: 1.29 $
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();
72 /**
73 * The name of the command as specified in CMakeList.txt.
75 virtual const char* GetName() { return info.Name; }
77 /**
78 * Succinct documentation.
80 virtual const char* GetTerseDocumentation()
82 if (this->info.GetTerseDocumentation)
84 cmLoadedCommand::InstallSignalHandlers(info.Name);
85 const char* ret = info.GetTerseDocumentation();
86 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
87 return ret;
89 else
91 return "LoadedCommand without any additional documentation";
94 static const char* LastName;
95 static void TrapsForSignals(int sig)
97 fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n",
98 cmLoadedCommand::LastName, sig);
100 static void InstallSignalHandlers(const char* name, int remove = 0)
102 cmLoadedCommand::LastName = name;
103 if(!name)
105 cmLoadedCommand::LastName = "????";
108 if(!remove)
110 signal(SIGSEGV, TrapsForSignalsCFunction);
111 #ifdef SIGBUS
112 signal(SIGBUS, TrapsForSignalsCFunction);
113 #endif
114 signal(SIGILL, TrapsForSignalsCFunction);
116 else
118 signal(SIGSEGV, 0);
119 #ifdef SIGBUS
120 signal(SIGBUS, 0);
121 #endif
122 signal(SIGILL, 0);
127 * More documentation.
129 virtual const char* GetFullDocumentation()
131 if (this->info.GetFullDocumentation)
133 cmLoadedCommand::InstallSignalHandlers(info.Name);
134 const char* ret = info.GetFullDocumentation();
135 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
136 return ret;
138 else
140 return "LoadedCommand without any additional documentation";
144 cmTypeMacro(cmLoadedCommand, cmCommand);
146 cmLoadedCommandInfo info;
149 extern "C" void TrapsForSignalsCFunction(int sig)
151 cmLoadedCommand::TrapsForSignals(sig);
155 const char* cmLoadedCommand::LastName = 0;
157 bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args,
158 cmExecutionStatus &)
160 if (!info.InitialPass)
162 return true;
165 // clear the error string
166 if (this->info.Error)
168 free(this->info.Error);
171 // create argc and argv and then invoke the command
172 int argc = static_cast<int> (args.size());
173 char **argv = 0;
174 if (argc)
176 argv = (char **)malloc(argc*sizeof(char *));
178 int i;
179 for (i = 0; i < argc; ++i)
181 argv[i] = strdup(args[i].c_str());
183 cmLoadedCommand::InstallSignalHandlers(info.Name);
184 int result = info.InitialPass((void *)&info,
185 (void *)this->Makefile,argc,argv);
186 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
187 cmFreeArguments(argc,argv);
189 if (result)
191 return true;
194 /* Initial Pass must have failed so set the error string */
195 if (this->info.Error)
197 this->SetError(this->info.Error);
199 return false;
202 void cmLoadedCommand::FinalPass()
204 if (this->info.FinalPass)
206 cmLoadedCommand::InstallSignalHandlers(info.Name);
207 this->info.FinalPass((void *)&this->info,(void *)this->Makefile);
208 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
212 cmLoadedCommand::~cmLoadedCommand()
214 if (this->info.Destructor)
216 cmLoadedCommand::InstallSignalHandlers(info.Name);
217 this->info.Destructor((void *)&this->info);
218 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
220 if (this->info.Error)
222 free(this->info.Error);
226 // cmLoadCommandCommand
227 bool cmLoadCommandCommand
228 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
230 if(args.size() < 1 )
232 return true;
235 // Construct a variable to report what file was loaded, if any.
236 // Start by removing the definition in case of failure.
237 std::string reportVar = "CMAKE_LOADED_COMMAND_";
238 reportVar += args[0];
239 this->Makefile->RemoveDefinition(reportVar.c_str());
241 // the file must exist
242 std::string moduleName =
243 this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX");
244 moduleName += "cm" + args[0];
245 moduleName +=
246 this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX");
248 // search for the file
249 std::vector<std::string> path;
250 for (unsigned int j = 1; j < args.size(); j++)
252 // expand variables
253 std::string exp = args[j];
254 cmSystemTools::ExpandRegistryValues(exp);
256 // Glob the entry in case of wildcards.
257 cmSystemTools::GlobDirs(exp.c_str(), path);
260 // Try to find the program.
261 std::string fullPath = cmSystemTools::FindFile(moduleName.c_str(), path);
262 if (fullPath == "")
264 cmOStringStream e;
265 e << "Attempt to load command failed from file \""
266 << moduleName << "\"";
267 this->SetError(e.str().c_str());
268 return false;
271 // try loading the shared library / dll
272 cmsys::DynamicLoader::LibraryHandle lib
273 = cmDynamicLoader::OpenLibrary(fullPath.c_str());
274 if(!lib)
276 std::string err = "Attempt to load the library ";
277 err += fullPath + " failed.";
278 const char* error = cmsys::DynamicLoader::LastError();
279 if ( error )
281 err += " Additional error info is:\n";
282 err += error;
284 this->SetError(err.c_str());
285 return false;
288 // Report what file was loaded for this command.
289 this->Makefile->AddDefinition(reportVar.c_str(), fullPath.c_str());
291 // find the init function
292 std::string initFuncName = args[0] + "Init";
293 CM_INIT_FUNCTION initFunction
294 = (CM_INIT_FUNCTION)
295 cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str());
296 if ( !initFunction )
298 initFuncName = "_";
299 initFuncName += args[0];
300 initFuncName += "Init";
301 initFunction = (CM_INIT_FUNCTION)(
302 cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str()));
304 // if the symbol is found call it to set the name on the
305 // function blocker
306 if(initFunction)
308 // create a function blocker and set it up
309 cmLoadedCommand *f = new cmLoadedCommand();
310 (*initFunction)(&f->info);
311 this->Makefile->AddCommand(f);
312 return true;
314 this->SetError("Attempt to load command failed. "
315 "No init function found.");
316 return false;