1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmLoadCommandCommand.cxx,v $
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>
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();
73 * The name of the command as specified in CMakeList.txt.
75 virtual const char* GetName() { return info
.Name
; }
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);
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
;
105 cmLoadedCommand::LastName
= "????";
110 signal(SIGSEGV
, TrapsForSignalsCFunction
);
112 signal(SIGBUS
, TrapsForSignalsCFunction
);
114 signal(SIGILL
, TrapsForSignalsCFunction
);
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);
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
,
160 if (!info
.InitialPass
)
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());
176 argv
= (char **)malloc(argc
*sizeof(char *));
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
);
194 /* Initial Pass must have failed so set the error string */
195 if (this->info
.Error
)
197 this->SetError(this->info
.Error
);
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
&)
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];
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
++)
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
);
265 e
<< "Attempt to load command failed from file \""
266 << moduleName
<< "\"";
267 this->SetError(e
.str().c_str());
271 // try loading the shared library / dll
272 cmsys::DynamicLoader::LibraryHandle lib
273 = cmDynamicLoader::OpenLibrary(fullPath
.c_str());
276 std::string err
= "Attempt to load the library ";
277 err
+= fullPath
+ " failed.";
278 const char* error
= cmsys::DynamicLoader::LastError();
281 err
+= " Additional error info is:\n";
284 this->SetError(err
.c_str());
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
295 cmsys::DynamicLoader::GetSymbolAddress(lib
, initFuncName
.c_str());
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
308 // create a function blocker and set it up
309 cmLoadedCommand
*f
= new cmLoadedCommand();
310 (*initFunction
)(&f
->info
);
311 this->Makefile
->AddCommand(f
);
314 this->SetError("Attempt to load command failed. "
315 "No init function found.");