1 /*============================================================================
2 CMake - Cross Platform Makefile Generator
3 Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
5 Distributed under the OSI-approved BSD License (the "License");
6 see accompanying file Copyright.txt for details.
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"
17 #include <cmsys/DynamicLoader.hxx>
22 # include <malloc.h> /* for malloc/free on QNX */
26 extern "C" void TrapsForSignalsCFunction(int sig);
29 // a class for loadabple commands
30 class cmLoadedCommand : public cmCommand
34 memset(&this->info,0,sizeof(this->info));
35 this->info.CAPI = &cmStaticCAPI;
38 ///! clean up any memory allocated by the plugin
42 * This is a virtual constructor for the command.
44 virtual cmCommand* Clone()
46 cmLoadedCommand *newC = new cmLoadedCommand;
47 // we must copy when we clone
48 memcpy(&newC->info,&this->info,sizeof(info));
53 * This is called when the command is first encountered in
54 * the CMakeLists.txt file.
56 virtual bool InitialPass(std::vector<std::string> const& args,
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.
65 virtual void FinalPass();
66 virtual bool HasFinalPass() const
67 { return this->info.FinalPass? true:false; }
70 * The name of the command as specified in CMakeList.txt.
72 virtual const char* GetName() const { return info.Name; }
75 * Succinct documentation.
77 virtual const char* GetTerseDocumentation() const
79 if (this->info.GetTerseDocumentation)
81 cmLoadedCommand::InstallSignalHandlers(info.Name);
82 const char* ret = info.GetTerseDocumentation();
83 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
88 return "LoadedCommand without any additional documentation";
91 static const char* LastName;
92 static void TrapsForSignals(int sig)
94 fprintf(stderr, "CMake loaded command %s crashed with signal: %d.\n",
95 cmLoadedCommand::LastName, sig);
97 static void InstallSignalHandlers(const char* name, int remove = 0)
99 cmLoadedCommand::LastName = name;
102 cmLoadedCommand::LastName = "????";
107 signal(SIGSEGV, TrapsForSignalsCFunction);
109 signal(SIGBUS, TrapsForSignalsCFunction);
111 signal(SIGILL, TrapsForSignalsCFunction);
124 * More documentation.
126 virtual const char* GetFullDocumentation() const
128 if (this->info.GetFullDocumentation)
130 cmLoadedCommand::InstallSignalHandlers(info.Name);
131 const char* ret = info.GetFullDocumentation();
132 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
137 return "LoadedCommand without any additional documentation";
141 cmTypeMacro(cmLoadedCommand, cmCommand);
143 cmLoadedCommandInfo info;
146 extern "C" void TrapsForSignalsCFunction(int sig)
148 cmLoadedCommand::TrapsForSignals(sig);
152 const char* cmLoadedCommand::LastName = 0;
154 bool cmLoadedCommand::InitialPass(std::vector<std::string> const& args,
157 if (!info.InitialPass)
162 // clear the error string
163 if (this->info.Error)
165 free(this->info.Error);
168 // create argc and argv and then invoke the command
169 int argc = static_cast<int> (args.size());
173 argv = (char **)malloc(argc*sizeof(char *));
176 for (i = 0; i < argc; ++i)
178 argv[i] = strdup(args[i].c_str());
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);
191 /* Initial Pass must have failed so set the error string */
192 if (this->info.Error)
194 this->SetError(this->info.Error);
199 void cmLoadedCommand::FinalPass()
201 if (this->info.FinalPass)
203 cmLoadedCommand::InstallSignalHandlers(info.Name);
204 this->info.FinalPass((void *)&this->info,(void *)this->Makefile);
205 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
209 cmLoadedCommand::~cmLoadedCommand()
211 if (this->info.Destructor)
213 cmLoadedCommand::InstallSignalHandlers(info.Name);
214 this->info.Destructor((void *)&this->info);
215 cmLoadedCommand::InstallSignalHandlers(info.Name, 1);
217 if (this->info.Error)
219 free(this->info.Error);
223 // cmLoadCommandCommand
224 bool cmLoadCommandCommand
225 ::InitialPass(std::vector<std::string> const& args, cmExecutionStatus &)
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());
238 // the file must exist
239 std::string moduleName =
240 this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_PREFIX");
241 moduleName += "cm" + args[0];
243 this->Makefile->GetRequiredDefinition("CMAKE_SHARED_MODULE_SUFFIX");
245 // search for the file
246 std::vector<std::string> path;
247 for (unsigned int j = 1; j < args.size(); j++)
250 std::string exp = args[j];
251 cmSystemTools::ExpandRegistryValues(exp);
253 // Glob the entry in case of wildcards.
254 cmSystemTools::GlobDirs(exp.c_str(), path);
257 // Try to find the program.
258 std::string fullPath = cmSystemTools::FindFile(moduleName.c_str(), path);
262 e << "Attempt to load command failed from file \""
263 << moduleName << "\"";
264 this->SetError(e.str().c_str());
268 // try loading the shared library / dll
269 cmsys::DynamicLoader::LibraryHandle lib
270 = cmDynamicLoader::OpenLibrary(fullPath.c_str());
273 std::string err = "Attempt to load the library ";
274 err += fullPath + " failed.";
275 const char* error = cmsys::DynamicLoader::LastError();
278 err += " Additional error info is:\n";
281 this->SetError(err.c_str());
285 // Report what file was loaded for this command.
286 this->Makefile->AddDefinition(reportVar.c_str(), fullPath.c_str());
288 // find the init function
289 std::string initFuncName = args[0] + "Init";
290 CM_INIT_FUNCTION initFunction
292 cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str());
296 initFuncName += args[0];
297 initFuncName += "Init";
298 initFunction = (CM_INIT_FUNCTION)(
299 cmsys::DynamicLoader::GetSymbolAddress(lib, initFuncName.c_str()));
301 // if the symbol is found call it to set the name on the
305 // create a function blocker and set it up
306 cmLoadedCommand *f = new cmLoadedCommand();
307 (*initFunction)(&f->info);
308 this->Makefile->AddCommand(f);
311 this->SetError("Attempt to load command failed. "
312 "No init function found.");