1 //
2 // Copyright (c) ZeroC, Inc. All rights reserved.
3 //
4
5 #include <IceUtil/Options.h>
6 #include <IceUtil/CtrlCHandler.h>
7 #include <IceUtil/Mutex.h>
8 #include <IceUtil/MutexPtrLock.h>
9 #include <IceUtil/ConsoleUtil.h>
10
11 #include <Slice/Preprocessor.h>
12 #include <Slice/FileTracker.h>
13 #include <Slice/Util.h>
14 #include "Gen.h"
15
16 using namespace std;
17 using namespace Slice;
18 using namespace IceUtilInternal;
19
20 namespace
21 {
22
23 IceUtil::Mutex* globalMutex = 0;
24 bool interrupted = false;
25
26 class Init
27 {
28 public:
29
Init()30 Init()
31 {
32 globalMutex = new IceUtil::Mutex;
33 }
34
~Init()35 ~Init()
36 {
37 delete globalMutex;
38 globalMutex = 0;
39 }
40 };
41
42 Init init;
43
44 }
45
46 void
interruptedCallback(int)47 interruptedCallback(int /*signal*/)
48 {
49 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex);
50
51 interrupted = true;
52 }
53
54 void
usage(const string & n)55 usage(const string& n)
56 {
57 consoleErr << "Usage: " << n << " [options] slice-files...\n";
58 consoleErr <<
59 "Options:\n"
60 "-h, --help Show this message.\n"
61 "-v, --version Display the Ice version.\n"
62 "-DNAME Define NAME as 1.\n"
63 "-DNAME=DEF Define NAME as DEF.\n"
64 "-UNAME Remove any definition for NAME.\n"
65 "-IDIR Put DIR in the include file search path.\n"
66 "-E Print preprocessor output on stdout.\n"
67 "--output-dir DIR Create files in the directory DIR.\n"
68 "-d, --debug Print debug messages.\n"
69 "--depend Generate Makefile dependencies.\n"
70 "--depend-xml Generate dependencies in XML format.\n"
71 "--depend-file FILE Write dependencies to FILE instead of standard output.\n"
72 "--validate Validate command line options.\n"
73 "--header-ext EXT Use EXT instead of the default `h' extension.\n"
74 "--source-ext EXT Use EXT instead of the default `cpp' extension.\n"
75 "--add-header HDR[,GUARD] Add #include for HDR (with guard GUARD) to generated source file.\n"
76 "--include-dir DIR Use DIR as the header include directory in source files.\n"
77 "--impl-c++11 Generate sample implementations for C++11 mapping.\n"
78 "--impl-c++98 Generate sample implementations for C++98 mapping.\n"
79 "--checksum Generate checksums for Slice definitions.\n"
80 "--dll-export SYMBOL Use SYMBOL for DLL exports\n"
81 " deprecated: use instead [[\"cpp:dll-export:SYMBOL\"]] metadata.\n"
82 "--ice Allow reserved Ice prefix in Slice identifiers\n"
83 " deprecated: use instead [[\"ice-prefix\"]] metadata.\n"
84 "--underscore Allow underscores in Slice identifiers\n"
85 " deprecated: use instead [[\"underscore\"]] metadata.\n"
86 ;
87 }
88
89 int
compile(const vector<string> & argv)90 compile(const vector<string>& argv)
91 {
92 IceUtilInternal::Options opts;
93 opts.addOpt("h", "help");
94 opts.addOpt("v", "version");
95 opts.addOpt("", "validate");
96 opts.addOpt("", "header-ext", IceUtilInternal::Options::NeedArg, "h");
97 opts.addOpt("", "source-ext", IceUtilInternal::Options::NeedArg, "cpp");
98 opts.addOpt("", "add-header", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
99 opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
100 opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
101 opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
102 opts.addOpt("E");
103 opts.addOpt("", "include-dir", IceUtilInternal::Options::NeedArg);
104 opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg);
105 opts.addOpt("", "dll-export", IceUtilInternal::Options::NeedArg);
106 opts.addOpt("", "impl-c++98");
107 opts.addOpt("", "impl-c++11");
108 opts.addOpt("", "depend");
109 opts.addOpt("", "depend-xml");
110 opts.addOpt("", "depend-file", IceUtilInternal::Options::NeedArg, "");
111 opts.addOpt("d", "debug");
112 opts.addOpt("", "ice");
113 opts.addOpt("", "underscore");
114 opts.addOpt("", "checksum");
115
116 bool validate = find(argv.begin(), argv.end(), "--validate") != argv.end();
117 vector<string> args;
118 try
119 {
120 args = opts.parse(argv);
121 }
122 catch(const IceUtilInternal::BadOptException& e)
123 {
124 consoleErr << argv[0] << ": " << e.reason << endl;
125 if(!validate)
126 {
127 usage(argv[0]);
128 }
129 return EXIT_FAILURE;
130 }
131
132 if(opts.isSet("help"))
133 {
134 usage(argv[0]);
135 return EXIT_SUCCESS;
136 }
137
138 if(opts.isSet("version"))
139 {
140 consoleErr << ICE_STRING_VERSION << endl;
141 return EXIT_SUCCESS;
142 }
143
144 string headerExtension = opts.optArg("header-ext");
145 string sourceExtension = opts.optArg("source-ext");
146
147 vector<string> extraHeaders = opts.argVec("add-header");
148
149 vector<string> cppArgs;
150 vector<string> optargs = opts.argVec("D");
151 for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
152 {
153 cppArgs.push_back("-D" + *i);
154 }
155
156 optargs = opts.argVec("U");
157 for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
158 {
159 cppArgs.push_back("-U" + *i);
160 }
161
162 vector<string> includePaths;
163 includePaths = opts.argVec("I");
164 for(vector<string>::const_iterator i = includePaths.begin(); i != includePaths.end(); ++i)
165 {
166 cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i));
167 }
168
169 bool preprocess = opts.isSet("E");
170
171 string include = opts.optArg("include-dir");
172
173 string output = opts.optArg("output-dir");
174
175 string dllExport = opts.optArg("dll-export");
176
177 bool implCpp98 = opts.isSet("impl-c++98");
178
179 bool implCpp11 = opts.isSet("impl-c++11");
180
181 bool depend = opts.isSet("depend");
182
183 bool dependxml = opts.isSet("depend-xml");
184
185 string dependFile = opts.optArg("depend-file");
186
187 bool debug = opts.isSet("debug");
188
189 bool ice = opts.isSet("ice");
190
191 bool underscore = opts.isSet("underscore");
192
193 bool checksum = opts.isSet("checksum");
194
195 if(args.empty())
196 {
197 consoleErr << argv[0] << ": error: no input file" << endl;
198 if(!validate)
199 {
200 usage(argv[0]);
201 }
202 return EXIT_FAILURE;
203 }
204
205 if(depend && dependxml)
206 {
207 consoleErr << argv[0] << ": error: cannot specify both --depend and --depend-xml" << endl;
208 if(!validate)
209 {
210 usage(argv[0]);
211 }
212 return EXIT_FAILURE;
213 }
214
215 if(implCpp98 && implCpp11)
216 {
217 consoleErr << argv[0] << ": error: cannot specify both --impl-c++98 and --impl-c++11" << endl;
218 if(!validate)
219 {
220 usage(argv[0]);
221 }
222 return EXIT_FAILURE;
223 }
224
225 if(validate)
226 {
227 return EXIT_SUCCESS;
228 }
229
230 int status = EXIT_SUCCESS;
231
232 IceUtil::CtrlCHandler ctrlCHandler;
233 ctrlCHandler.setCallback(interruptedCallback);
234
235 ostringstream os;
236 if(dependxml)
237 {
238 os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<dependencies>" << endl;
239 }
240
241 for(vector<string>::const_iterator i = args.begin(); i != args.end(); ++i)
242 {
243 //
244 // Ignore duplicates.
245 //
246 vector<string>::iterator p = find(args.begin(), args.end(), *i);
247 if(p != i)
248 {
249 continue;
250 }
251
252 if(depend || dependxml)
253 {
254 PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
255 FILE* cppHandle = icecpp->preprocess(false, "-D__SLICE2CPP__");
256
257 if(cppHandle == 0)
258 {
259 return EXIT_FAILURE;
260 }
261
262 UnitPtr u = Unit::createUnit(false, false, ice, underscore);
263 int parseStatus = u->parse(*i, cppHandle, debug);
264
265 string ext = headerExtension;
266 static const string headerExtPrefix = "cpp:header-ext:";
267 DefinitionContextPtr dc = u->findDefinitionContext(u->topLevelFile());
268 assert(dc);
269 string meta = dc->findMetaData(headerExtPrefix);
270 if(meta.size() > headerExtPrefix.size())
271 {
272 ext = meta.substr(headerExtPrefix.size());
273 }
274
275 u->destroy();
276
277 if(parseStatus == EXIT_FAILURE)
278 {
279 return EXIT_FAILURE;
280 }
281
282 if(!icecpp->printMakefileDependencies(os, depend ? Preprocessor::CPlusPlus : Preprocessor::SliceXML,
283 includePaths, "-D__SLICE2CPP__", sourceExtension, ext))
284 {
285 return EXIT_FAILURE;
286 }
287
288 if(!icecpp->close())
289 {
290 return EXIT_FAILURE;
291 }
292 }
293 else
294 {
295 PreprocessorPtr icecpp = Preprocessor::create(argv[0], *i, cppArgs);
296 FILE* cppHandle = icecpp->preprocess(true, "-D__SLICE2CPP__");
297
298 if(cppHandle == 0)
299 {
300 return EXIT_FAILURE;
301 }
302
303 if(preprocess)
304 {
305 char buf[4096];
306 while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != ICE_NULLPTR)
307 {
308 if(fputs(buf, stdout) == EOF)
309 {
310 return EXIT_FAILURE;
311 }
312 }
313 if(!icecpp->close())
314 {
315 return EXIT_FAILURE;
316 }
317 }
318 else
319 {
320 UnitPtr u = Unit::createUnit(false, false, ice, underscore);
321 int parseStatus = u->parse(*i, cppHandle, debug);
322
323 if(!icecpp->close())
324 {
325 u->destroy();
326 return EXIT_FAILURE;
327 }
328
329 if(parseStatus == EXIT_FAILURE)
330 {
331 status = EXIT_FAILURE;
332 }
333 else
334 {
335 try
336 {
337 Gen gen(icecpp->getBaseName(), headerExtension, sourceExtension, extraHeaders, include,
338 includePaths, dllExport, output, implCpp98, implCpp11, checksum, ice);
339 gen.generate(u);
340 }
341 catch(const Slice::FileException& ex)
342 {
343 // If a file could not be created, then
344 // cleanup any created files.
345 FileTracker::instance()->cleanup();
346 u->destroy();
347 consoleErr << argv[0] << ": error: " << ex.reason() << endl;
348 return EXIT_FAILURE;
349 }
350 }
351
352 u->destroy();
353 }
354 }
355
356 {
357 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex);
358
359 if(interrupted)
360 {
361 FileTracker::instance()->cleanup();
362 return EXIT_FAILURE;
363 }
364 }
365 }
366
367 if(dependxml)
368 {
369 os << "</dependencies>\n";
370 }
371
372 if(depend || dependxml)
373 {
374 writeDependencies(os.str(), dependFile);
375 }
376
377 return status;
378 }
379
380 #ifdef _WIN32
wmain(int argc,wchar_t * argv[])381 int wmain(int argc, wchar_t* argv[])
382 #else
383 int main(int argc, char* argv[])
384 #endif
385 {
386 vector<string> args = Slice::argvToArgs(argc, argv);
387 try
388 {
389 return compile(args);
390 }
391 catch(const std::exception& ex)
392 {
393 consoleErr << args[0] << ": error:" << ex.what() << endl;
394 return EXIT_FAILURE;
395 }
396 catch(...)
397 {
398 consoleErr << args[0] << ": error:" << "unknown exception" << endl;
399 return EXIT_FAILURE;
400 }
401 }
402