1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmLoadCommandCommand.cxx,v $
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>
27 # include <malloc.h> /* for malloc/free on QNX */
31 extern "C" void TrapsForSignalsCFunction(int sig
);
34 // a class for loadabple commands
35 class cmLoadedCommand
: public cmCommand
39 memset(&this->info
,0,sizeof(this->info
));
40 this->info
.CAPI
= &cmStaticCAPI
;
43 ///! clean up any memory allocated by the plugin
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
));
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
,
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; }
75 * The name of the command as specified in CMakeList.txt.
77 virtual const char* GetName() { return info
.Name
; }
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);
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
;
107 cmLoadedCommand::LastName
= "????";
112 signal(SIGSEGV
, TrapsForSignalsCFunction
);
114 signal(SIGBUS
, TrapsForSignalsCFunction
);
116 signal(SIGILL
, TrapsForSignalsCFunction
);
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);
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
,
162 if (!info
.InitialPass
)
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());
178 argv
= (char **)malloc(argc
*sizeof(char *));
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
);
196 /* Initial Pass must have failed so set the error string */
197 if (this->info
.Error
)
199 this->SetError(this->info
.Error
);
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
&)
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];
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
++)
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
);
267 e
<< "Attempt to load command failed from file \""
268 << moduleName
<< "\"";
269 this->SetError(e
.str().c_str());
273 // try loading the shared library / dll
274 cmsys::DynamicLoader::LibraryHandle lib
275 = cmDynamicLoader::OpenLibrary(fullPath
.c_str());
278 std::string err
= "Attempt to load the library ";
279 err
+= fullPath
+ " failed.";
280 const char* error
= cmsys::DynamicLoader::LastError();
283 err
+= " Additional error info is:\n";
286 this->SetError(err
.c_str());
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
297 cmsys::DynamicLoader::GetSymbolAddress(lib
, initFuncName
.c_str());
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
310 // create a function blocker and set it up
311 cmLoadedCommand
*f
= new cmLoadedCommand();
312 (*initFunction
)(&f
->info
);
313 this->Makefile
->AddCommand(f
);
316 this->SetError("Attempt to load command failed. "
317 "No init function found.");