1 | //{{{ Banner |
---|
2 | |
---|
3 | //========================================================================== |
---|
4 | // |
---|
5 | // build.cxx |
---|
6 | // |
---|
7 | // libcdl support for building and for header file generation |
---|
8 | // |
---|
9 | //========================================================================== |
---|
10 | //####COPYRIGHTBEGIN#### |
---|
11 | // |
---|
12 | // ---------------------------------------------------------------------------- |
---|
13 | // Copyright (C) 2002, 2003 Bart Veer |
---|
14 | // Copyright (C) 1999, 2000, 2001 Red Hat, Inc. |
---|
15 | // |
---|
16 | // This file is part of the eCos host tools. |
---|
17 | // |
---|
18 | // This program is free software; you can redistribute it and/or modify it |
---|
19 | // under the terms of the GNU General Public License as published by the Free |
---|
20 | // Software Foundation; either version 2 of the License, or (at your option) |
---|
21 | // any later version. |
---|
22 | // |
---|
23 | // This program is distributed in the hope that it will be useful, but WITHOUT |
---|
24 | // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
---|
25 | // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
---|
26 | // more details. |
---|
27 | // |
---|
28 | // You should have received a copy of the GNU General Public License along with |
---|
29 | // this program; if not, write to the Free Software Foundation, Inc., |
---|
30 | // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
31 | // |
---|
32 | // ---------------------------------------------------------------------------- |
---|
33 | // |
---|
34 | //####COPYRIGHTEND#### |
---|
35 | //========================================================================== |
---|
36 | //#####DESCRIPTIONBEGIN#### |
---|
37 | // |
---|
38 | // Author(s): bartv |
---|
39 | // Contributors: bartv |
---|
40 | // Date: 1999-06-018 |
---|
41 | // |
---|
42 | //####DESCRIPTIONEND#### |
---|
43 | //========================================================================== |
---|
44 | |
---|
45 | //}}} |
---|
46 | //{{{ #include's |
---|
47 | |
---|
48 | // ---------------------------------------------------------------------------- |
---|
49 | #include "cdlconfig.h" |
---|
50 | |
---|
51 | // Get the infrastructure types, assertions, tracing and similar |
---|
52 | // facilities. |
---|
53 | #include <cyg/infra/cyg_ass.h> |
---|
54 | #include <cyg/infra/cyg_trac.h> |
---|
55 | |
---|
56 | // <cdl.hxx> defines everything implemented in this module. |
---|
57 | // It implicitly supplies <string>, <vector> and <map> because |
---|
58 | // the class definitions rely on these headers. |
---|
59 | #include <cdlcore.hxx> |
---|
60 | #include <string.h> |
---|
61 | //}}} |
---|
62 | |
---|
63 | //{{{ Statics |
---|
64 | |
---|
65 | // ---------------------------------------------------------------------------- |
---|
66 | CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlBuildLoadableBody); |
---|
67 | CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlBuildableBody); |
---|
68 | CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlDefineLoadableBody); |
---|
69 | CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlDefinableBody); |
---|
70 | |
---|
71 | //}}} |
---|
72 | //{{{ CdlBuildableBody |
---|
73 | |
---|
74 | //{{{ Basics |
---|
75 | |
---|
76 | // ---------------------------------------------------------------------------- |
---|
77 | // There is little data specific to a buildable. The only distinguishing |
---|
78 | // feature is the set of properties that are supported, plus a handful |
---|
79 | // of functions to extract that information. |
---|
80 | |
---|
81 | CdlBuildableBody::CdlBuildableBody() |
---|
82 | { |
---|
83 | CYG_REPORT_FUNCNAME("CdlBuildable:: default constructor"); |
---|
84 | CYG_REPORT_FUNCARG1XV(this); |
---|
85 | |
---|
86 | // There is no data to initialize yet |
---|
87 | cdlbuildablebody_cookie = CdlBuildableBody_Magic; |
---|
88 | CYGDBG_MEMLEAK_CONSTRUCTOR(); |
---|
89 | |
---|
90 | CYG_POSTCONDITION_THISC(); |
---|
91 | CYG_REPORT_RETURN(); |
---|
92 | } |
---|
93 | |
---|
94 | CdlBuildableBody::~CdlBuildableBody() |
---|
95 | { |
---|
96 | CYG_REPORT_FUNCNAME("CdlBuildable:: destructor"); |
---|
97 | CYG_REPORT_FUNCARG1XV(this); |
---|
98 | CYG_PRECONDITION_THISC(); |
---|
99 | |
---|
100 | cdlbuildablebody_cookie = CdlBuildableBody_Invalid; |
---|
101 | CYGDBG_MEMLEAK_DESTRUCTOR(); |
---|
102 | |
---|
103 | CYG_REPORT_RETURN(); |
---|
104 | } |
---|
105 | |
---|
106 | // ---------------------------------------------------------------------------- |
---|
107 | |
---|
108 | std::string |
---|
109 | CdlBuildableBody::get_class_name() const |
---|
110 | { |
---|
111 | CYG_REPORT_FUNCNAME("CdlBuildable::get_class_name"); |
---|
112 | CYG_PRECONDITION_THISC(); |
---|
113 | CYG_REPORT_RETURN(); |
---|
114 | return "buildable"; |
---|
115 | } |
---|
116 | |
---|
117 | // ---------------------------------------------------------------------------- |
---|
118 | |
---|
119 | bool |
---|
120 | CdlBuildableBody::check_this(cyg_assert_class_zeal zeal) const |
---|
121 | { |
---|
122 | if (CdlBuildableBody_Magic != cdlbuildablebody_cookie) { |
---|
123 | return false; |
---|
124 | } |
---|
125 | CYGDBG_MEMLEAK_CHECKTHIS(); |
---|
126 | return CdlNodeBody::check_this(zeal); |
---|
127 | } |
---|
128 | |
---|
129 | //}}} |
---|
130 | //{{{ Add and check property parsers |
---|
131 | |
---|
132 | // ---------------------------------------------------------------------------- |
---|
133 | |
---|
134 | void |
---|
135 | CdlBuildableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers) |
---|
136 | { |
---|
137 | CYG_REPORT_FUNCNAME("CdlBuildable::add_property_parsers"); |
---|
138 | |
---|
139 | static CdlInterpreterCommandEntry commands[] = |
---|
140 | { |
---|
141 | CdlInterpreterCommandEntry("compile", &CdlBuildableBody::parse_compile ), |
---|
142 | CdlInterpreterCommandEntry("object", &CdlBuildableBody::parse_object ), |
---|
143 | CdlInterpreterCommandEntry("make_object", &CdlBuildableBody::parse_make_object), |
---|
144 | CdlInterpreterCommandEntry("make", &CdlBuildableBody::parse_make ), |
---|
145 | CdlInterpreterCommandEntry("build_proc", &CdlBuildableBody::parse_build_proc ), |
---|
146 | CdlInterpreterCommandEntry("", 0 ), |
---|
147 | }; |
---|
148 | |
---|
149 | for (int i = 0; commands[i].command != 0; i++) { |
---|
150 | std::vector<CdlInterpreterCommandEntry>::const_iterator j; |
---|
151 | for (j = parsers.begin(); j != parsers.end(); j++) { |
---|
152 | if (commands[i].name == j->name) { |
---|
153 | if (commands[i].command != j->command) { |
---|
154 | CYG_FAIL("Property names are being re-used"); |
---|
155 | } |
---|
156 | break; |
---|
157 | } |
---|
158 | } |
---|
159 | if (j == parsers.end()) { |
---|
160 | parsers.push_back(commands[i]); |
---|
161 | } |
---|
162 | } |
---|
163 | CdlNodeBody::add_property_parsers(parsers); |
---|
164 | |
---|
165 | CYG_REPORT_RETURN(); |
---|
166 | } |
---|
167 | |
---|
168 | void |
---|
169 | CdlBuildableBody::check_properties(CdlInterpreter interp) |
---|
170 | { |
---|
171 | CYG_REPORT_FUNCNAME("CdlBuildable::check_properties"); |
---|
172 | CYG_REPORT_FUNCARG2XV(this, interp); |
---|
173 | CYG_PRECONDITION_THISC(); |
---|
174 | CYG_PRECONDITION_CLASSC(interp); |
---|
175 | |
---|
176 | // There are no real constraints on the number of compile |
---|
177 | // properties etc. |
---|
178 | // TODO: check that the relevant sources files exist, |
---|
179 | // unless marked appropriately (build_proc can create |
---|
180 | // new source files). |
---|
181 | |
---|
182 | CdlNodeBody::check_properties(interp); |
---|
183 | |
---|
184 | CYG_REPORT_RETURN(); |
---|
185 | } |
---|
186 | |
---|
187 | //}}} |
---|
188 | //{{{ Property parsers |
---|
189 | |
---|
190 | // ---------------------------------------------------------------------------- |
---|
191 | // Syntax: compile <file1 file2 ...> |
---|
192 | // |
---|
193 | // There are a couple of checks that could be performed here: |
---|
194 | // |
---|
195 | // 1) does each listed file actually exist? Unfortunately that approach |
---|
196 | // falls foul of build_proc, which is allowed to generate source files |
---|
197 | // on the fly. |
---|
198 | // |
---|
199 | // 2) does the file have a recognised suffix such as .c or .cxx. This |
---|
200 | // relies libcdl having some way of knowing how to treat different |
---|
201 | // files. |
---|
202 | // |
---|
203 | // For now there are no validity checks. |
---|
204 | // |
---|
205 | // A future extension may allow dependencies to be listed, as an |
---|
206 | // option. This would allow component vendors to specify that |
---|
207 | // particular custom build steps should happen before particular |
---|
208 | // compilations, a more robust approach than the current priority |
---|
209 | // scheme. |
---|
210 | |
---|
211 | int |
---|
212 | CdlBuildableBody::parse_compile(CdlInterpreter interp, int argc, const char* argv[]) |
---|
213 | { |
---|
214 | CYG_REPORT_FUNCNAMETYPE("parse_compile", "result %d"); |
---|
215 | static char* options[] = { |
---|
216 | "library:", |
---|
217 | 0 |
---|
218 | }; |
---|
219 | |
---|
220 | int result = CdlParse::parse_stringvector_property(interp, argc, argv, CdlPropertyId_Compile, options, 0, true); |
---|
221 | |
---|
222 | CYG_REPORT_RETVAL(result); |
---|
223 | return result; |
---|
224 | } |
---|
225 | |
---|
226 | // ---------------------------------------------------------------------------- |
---|
227 | // A utility to break a custom build step down into its three components. |
---|
228 | // |
---|
229 | // A custom build step takes the form: |
---|
230 | // target : deps |
---|
231 | // rules |
---|
232 | // |
---|
233 | // This utility function takes a single string of this form and breaks |
---|
234 | // it down into its constituent parts. |
---|
235 | // |
---|
236 | // NOTE: this will need lots of extra code in future to allow for |
---|
237 | // escaped characters, spaces in filenames, etc. For now just keep |
---|
238 | // things simple. |
---|
239 | |
---|
240 | bool |
---|
241 | CdlBuildableBody::split_custom_build_step(std::string str_data, std::string& target, std::string& deps, std::string& rules, |
---|
242 | std::string& error_msg) |
---|
243 | { |
---|
244 | CYG_REPORT_FUNCNAMETYPE("CdlBuildable::split_custom_build_step", "result %d"); |
---|
245 | |
---|
246 | target = ""; |
---|
247 | deps = ""; |
---|
248 | rules = ""; |
---|
249 | error_msg = ""; |
---|
250 | |
---|
251 | const char* data = str_data.c_str(); |
---|
252 | |
---|
253 | // Skip any leading white space, and make sure that this leaves some real data. |
---|
254 | while (('\0' != *data) && isspace(*data)) { |
---|
255 | data++; |
---|
256 | } |
---|
257 | if ('\0' == *data) { |
---|
258 | error_msg = "no data in custom build_step"; |
---|
259 | CYG_REPORT_RETVAL(false); |
---|
260 | return false; |
---|
261 | } |
---|
262 | |
---|
263 | // Now extract the target. This consists of any sequence of characters |
---|
264 | // upto space, tab, colon. |
---|
265 | for ( ; ('\0' != *data) && (':' != *data) && (' ' != *data) && ('\t' != *data); data++) { |
---|
266 | target += *data; |
---|
267 | } |
---|
268 | // Discard any spaces or tabs, they are of no interest |
---|
269 | while ((' ' == *data) || ('\t' == *data)) { |
---|
270 | data++; |
---|
271 | } |
---|
272 | // The current character should be a colon |
---|
273 | if (':' != *data) { |
---|
274 | error_msg = "expecting a colon `;' after the target `" + target + "'"; |
---|
275 | CYG_REPORT_RETVAL(false); |
---|
276 | return false; |
---|
277 | } |
---|
278 | |
---|
279 | // Move past the colon, and skip any further spaces or tabs |
---|
280 | data++; |
---|
281 | while (('\0' != *data) && ((' ' == *data) || ('\t' == *data))) { |
---|
282 | data++; |
---|
283 | } |
---|
284 | |
---|
285 | // Everything from here until the end of line should be part of the deps field, |
---|
286 | // including white space. |
---|
287 | while (('\0' != *data) && ('\n' != *data) && (';' != *data)) { |
---|
288 | deps += *data++; |
---|
289 | } |
---|
290 | |
---|
291 | if ("" == deps) { |
---|
292 | error_msg = "expecting dependency list after `" + target + ":'"; |
---|
293 | CYG_REPORT_RETVAL(false); |
---|
294 | return false; |
---|
295 | } |
---|
296 | |
---|
297 | // Having some rules is compulsory. |
---|
298 | if ('\0' == *data) { |
---|
299 | error_msg = "expecting one or more rules after the dependency list"; |
---|
300 | CYG_REPORT_RETVAL(false); |
---|
301 | return false; |
---|
302 | } else { |
---|
303 | // We are currently at \n or ;, move on to the actual rules |
---|
304 | data++; |
---|
305 | } |
---|
306 | |
---|
307 | // Rules consist of one or more lines. Any leading white space on a given |
---|
308 | // line should be discarded. |
---|
309 | while ('\0' != *data) { |
---|
310 | // Processing the current rule. Skip leading spaces and tabs |
---|
311 | while ((' ' == *data) || ('\t' == *data)) { |
---|
312 | data++; |
---|
313 | } |
---|
314 | // Now add everything up to the next newline or EOD to the rules. |
---|
315 | while (('\0' != *data) && ('\n' != *data)) { |
---|
316 | rules += *data++; |
---|
317 | } |
---|
318 | |
---|
319 | // Terminate this line of the rules with a newline, even if that |
---|
320 | // character is absent from the raw data. |
---|
321 | rules += '\n'; |
---|
322 | |
---|
323 | // And ignore the newline in the raw data itself |
---|
324 | if ('\n' == *data) { |
---|
325 | data++; |
---|
326 | } |
---|
327 | } |
---|
328 | |
---|
329 | // Better make sure that there are some rules. All of the looping above |
---|
330 | // may just have left white space |
---|
331 | if ("" == rules) { |
---|
332 | error_msg = "no rules provided"; |
---|
333 | CYG_REPORT_RETVAL(false); |
---|
334 | return false; |
---|
335 | } |
---|
336 | |
---|
337 | // Everything is ok. |
---|
338 | |
---|
339 | CYG_REPORT_RETVAL(true); |
---|
340 | return true; |
---|
341 | } |
---|
342 | |
---|
343 | |
---|
344 | // ---------------------------------------------------------------------------- |
---|
345 | // syntax: make <target> <rules> |
---|
346 | // |
---|
347 | // There is rather a lot of checking to be done. |
---|
348 | // |
---|
349 | // 1) the priority should be valid. In particular it should be a number |
---|
350 | // within a reasonable range. |
---|
351 | // |
---|
352 | // 2) the rules should take the form: |
---|
353 | // <target> : <deps> ;|\n rules |
---|
354 | // |
---|
355 | // Where the target should be a single file, identical to the |
---|
356 | // first property argument. |
---|
357 | |
---|
358 | static void |
---|
359 | parse_make_final_check(CdlInterpreter interp, CdlProperty_String prop) |
---|
360 | { |
---|
361 | CYG_REPORT_FUNCNAME("parse_make_final_check"); |
---|
362 | CYG_PRECONDITION_CLASSC(interp); |
---|
363 | CYG_PRECONDITION_CLASSC(prop); |
---|
364 | |
---|
365 | std::string prio_string = prop->get_option("priority"); |
---|
366 | if ("" != prio_string) { |
---|
367 | cdl_int tmp = 1; |
---|
368 | if (!Cdl::string_to_integer(prio_string, tmp)) { |
---|
369 | CdlParse::report_property_parse_error(interp, prop, |
---|
370 | "Invalid priority option, priorities should be simple numbers."); |
---|
371 | } else { |
---|
372 | if ((tmp < 1) || (tmp > 1024)) { |
---|
373 | CdlParse::report_property_parse_error(interp, prop, |
---|
374 | "Invalid priority value, priorities should be in the range 1 to 1024."); |
---|
375 | } |
---|
376 | } |
---|
377 | } |
---|
378 | |
---|
379 | std::string data = prop->get_string(); |
---|
380 | std::string target; |
---|
381 | std::string deps; |
---|
382 | std::string rules; |
---|
383 | std::string error_msg; |
---|
384 | |
---|
385 | if (!CdlBuildableBody::split_custom_build_step(data, target, deps, rules, error_msg)) { |
---|
386 | CdlParse::report_property_parse_error(interp, prop, "Invalid custom build step, " + error_msg); |
---|
387 | } |
---|
388 | } |
---|
389 | |
---|
390 | int |
---|
391 | CdlBuildableBody::parse_make(CdlInterpreter interp, int argc, const char* argv[]) |
---|
392 | { |
---|
393 | CYG_REPORT_FUNCNAMETYPE("parse_make", "result %d"); |
---|
394 | static char* options[] = { |
---|
395 | "priority:", |
---|
396 | 0 |
---|
397 | }; |
---|
398 | |
---|
399 | int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Make, options, &parse_make_final_check); |
---|
400 | |
---|
401 | CYG_REPORT_RETVAL(result); |
---|
402 | return result; |
---|
403 | } |
---|
404 | |
---|
405 | |
---|
406 | // ---------------------------------------------------------------------------- |
---|
407 | // syntax: make_object <target> <rules> |
---|
408 | // |
---|
409 | // The rules here are much the same as for the "make" property. |
---|
410 | |
---|
411 | static void |
---|
412 | parse_make_object_final_check(CdlInterpreter interp, CdlProperty_String prop) |
---|
413 | { |
---|
414 | CYG_REPORT_FUNCNAME("parse_make_object_final_check"); |
---|
415 | CYG_PRECONDITION_CLASSC(interp); |
---|
416 | CYG_PRECONDITION_CLASSC(prop); |
---|
417 | |
---|
418 | |
---|
419 | std::string prio_string = prop->get_option("priority"); |
---|
420 | if ("" != prio_string) { |
---|
421 | cdl_int tmp = 1; |
---|
422 | if (!Cdl::string_to_integer(prio_string, tmp)) { |
---|
423 | CdlParse::report_property_parse_error(interp, prop, |
---|
424 | "Invalid priority option, priorities should be simple numbers."); |
---|
425 | } else { |
---|
426 | if ((tmp < 1) || (tmp > 1024)) { |
---|
427 | CdlParse::report_property_parse_error(interp, prop, |
---|
428 | "Invalid priority value, priorities should be in the range 1 to 1024."); |
---|
429 | } |
---|
430 | } |
---|
431 | } |
---|
432 | |
---|
433 | std::string data = prop->get_string(); |
---|
434 | std::string target; |
---|
435 | std::string deps; |
---|
436 | std::string rules; |
---|
437 | std::string error_msg; |
---|
438 | |
---|
439 | if (!CdlBuildableBody::split_custom_build_step(data, target, deps, rules, error_msg)) { |
---|
440 | CdlParse::report_property_parse_error(interp, prop, "Invalid custom build step, " + error_msg); |
---|
441 | } |
---|
442 | } |
---|
443 | |
---|
444 | int |
---|
445 | CdlBuildableBody::parse_make_object(CdlInterpreter interp, int argc, const char* argv[]) |
---|
446 | { |
---|
447 | CYG_REPORT_FUNCNAMETYPE("parse_make_object", "result %d"); |
---|
448 | static char* options[] = { |
---|
449 | "library:", |
---|
450 | "priority:", |
---|
451 | 0 |
---|
452 | }; |
---|
453 | |
---|
454 | int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_MakeObject, options, |
---|
455 | &parse_make_object_final_check); |
---|
456 | |
---|
457 | CYG_REPORT_RETVAL(result); |
---|
458 | return result; |
---|
459 | } |
---|
460 | |
---|
461 | |
---|
462 | // ---------------------------------------------------------------------------- |
---|
463 | // Syntax: object <file1> <file2> ... |
---|
464 | |
---|
465 | int |
---|
466 | CdlBuildableBody::parse_object(CdlInterpreter interp, int argc, const char* argv[]) |
---|
467 | { |
---|
468 | CYG_REPORT_FUNCNAMETYPE("parse_object", "result %d"); |
---|
469 | static char* options[] = { |
---|
470 | "library:", |
---|
471 | 0 |
---|
472 | }; |
---|
473 | |
---|
474 | int result = CdlParse::parse_stringvector_property(interp, argc, argv, CdlPropertyId_Object, options, 0, true); |
---|
475 | |
---|
476 | CYG_REPORT_RETVAL(result); |
---|
477 | return result; |
---|
478 | } |
---|
479 | |
---|
480 | // ---------------------------------------------------------------------------- |
---|
481 | // Syntax: build_proc { tcl code } |
---|
482 | |
---|
483 | int |
---|
484 | CdlBuildableBody::parse_build_proc(CdlInterpreter interp, int argc, const char* argv[]) |
---|
485 | { |
---|
486 | CYG_REPORT_FUNCNAMETYPE("parse_build_proc", "result %d"); |
---|
487 | |
---|
488 | int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_BuildProc, 0, 0); |
---|
489 | |
---|
490 | CYG_REPORT_RETVAL(result); |
---|
491 | return result; |
---|
492 | } |
---|
493 | |
---|
494 | //}}} |
---|
495 | //{{{ update_build_info() |
---|
496 | |
---|
497 | // ---------------------------------------------------------------------------- |
---|
498 | // Most of the work is done in update_all_build_info(). The update_build_info() |
---|
499 | // merely checks the active and enabled state first. |
---|
500 | void |
---|
501 | CdlBuildableBody::update_build_info(CdlBuildInfo_Loadable& build_info, std::string library) const |
---|
502 | { |
---|
503 | CYG_REPORT_FUNCNAME("CdlBuildable::update_build_info"); |
---|
504 | CYG_REPORT_FUNCARG2XV(this, &build_info); |
---|
505 | CYG_PRECONDITION_THISC(); |
---|
506 | CYG_PRECONDITIONC("" != library); |
---|
507 | |
---|
508 | if (!is_active()) { |
---|
509 | CYG_REPORT_RETURN(); |
---|
510 | return; |
---|
511 | } |
---|
512 | |
---|
513 | CdlConstValuable valuable = dynamic_cast<CdlConstValuable>(this); |
---|
514 | if (0 != valuable) { |
---|
515 | if (!valuable->is_enabled()) { |
---|
516 | CYG_REPORT_RETURN(); |
---|
517 | return; |
---|
518 | } |
---|
519 | } |
---|
520 | |
---|
521 | update_all_build_info(build_info, library); |
---|
522 | |
---|
523 | CYG_REPORT_RETURN(); |
---|
524 | } |
---|
525 | |
---|
526 | //}}} |
---|
527 | //{{{ update_all_build_info() |
---|
528 | |
---|
529 | // ---------------------------------------------------------------------------- |
---|
530 | // There are four properties to be considered, each of which may occur |
---|
531 | // multiple times: "compile", "object", "make_object", and "make". |
---|
532 | // Each of these will result in separate additions to the build_info |
---|
533 | // structure. |
---|
534 | |
---|
535 | void |
---|
536 | CdlBuildableBody::update_all_build_info(CdlBuildInfo_Loadable& build_info, std::string package_library) const |
---|
537 | { |
---|
538 | CYG_REPORT_FUNCNAME("CdlBuildable::update_all_build_info"); |
---|
539 | CYG_REPORT_FUNCARG2XV(this, &build_info); |
---|
540 | CYG_PRECONDITION_THISC(); |
---|
541 | CYG_PRECONDITIONC("" != package_library); |
---|
542 | |
---|
543 | // Get some information about the owning loadable first. |
---|
544 | CdlLoadable loadable = get_owner(); |
---|
545 | CYG_ASSERT_CLASSC(loadable); |
---|
546 | std::string directory = loadable->get_directory(); |
---|
547 | std::string repository = loadable->get_repository(); |
---|
548 | CYG_ASSERTC("" != directory); |
---|
549 | CYG_ASSERTC("" != repository); |
---|
550 | CdlInterpreter interp = loadable->get_interpreter(); |
---|
551 | CYG_ASSERT_CLASSC(interp); |
---|
552 | |
---|
553 | // The interpreter needs some information about the locations |
---|
554 | // of various things. This code has to be kept in step with |
---|
555 | // CdlLoadable::find_relative_file() |
---|
556 | interp->set_variable("::cdl_topdir", repository); |
---|
557 | interp->set_variable("::cdl_pkgdir", directory); |
---|
558 | |
---|
559 | // For many packages the sources will reside in a src subdirectory. |
---|
560 | // For simple packages the sources may live directly at the toplevel |
---|
561 | bool has_src_subdir = loadable->has_subdirectory("src"); |
---|
562 | |
---|
563 | // NOTE: the object property is not yet supported |
---|
564 | std::vector<CdlProperty> compile_properties; |
---|
565 | get_properties(CdlPropertyId_Compile, compile_properties); |
---|
566 | std::vector<CdlProperty> makeobject_properties; |
---|
567 | get_properties(CdlPropertyId_MakeObject, makeobject_properties); |
---|
568 | std::vector<CdlProperty> make_properties; |
---|
569 | get_properties(CdlPropertyId_Make, make_properties); |
---|
570 | std::vector<CdlProperty>::const_iterator prop_i; |
---|
571 | |
---|
572 | for (prop_i = compile_properties.begin(); prop_i != compile_properties.end(); prop_i++) { |
---|
573 | CdlProperty_StringVector compile_prop = dynamic_cast<CdlProperty_StringVector>(*prop_i); |
---|
574 | CYG_LOOP_INVARIANT_CLASSC(compile_prop); |
---|
575 | |
---|
576 | // Does this property have a library option? |
---|
577 | std::string current_library = compile_prop->get_option("library"); |
---|
578 | if ("" == current_library) { |
---|
579 | current_library = package_library; |
---|
580 | } |
---|
581 | |
---|
582 | const std::vector<std::string>& files = compile_prop->get_strings(); |
---|
583 | std::vector<std::string>::const_iterator file_i; |
---|
584 | |
---|
585 | for (file_i = files.begin(); file_i != files.end(); file_i++) { |
---|
586 | |
---|
587 | // For each listed file, try to find it. If this is unsuccessful |
---|
588 | // then assume that the file will be generated later on. |
---|
589 | std::string path = loadable->find_relative_file(*file_i, "src"); |
---|
590 | if ("" == path) { |
---|
591 | if (has_src_subdir) { |
---|
592 | path = "src/" + *file_i; |
---|
593 | } else { |
---|
594 | path = *file_i; |
---|
595 | } |
---|
596 | } |
---|
597 | |
---|
598 | // Now check whether or not the specified file is already present. |
---|
599 | std::vector<CdlBuildInfo_Compile>::const_iterator info_i; |
---|
600 | for (info_i = build_info.compiles.begin(); info_i != build_info.compiles.end(); info_i++) { |
---|
601 | if ((current_library == info_i->library) && (path == info_i->source)) { |
---|
602 | break; |
---|
603 | } |
---|
604 | } |
---|
605 | if (info_i == build_info.compiles.end()) { |
---|
606 | CdlBuildInfo_Compile new_info; |
---|
607 | new_info.library = current_library; |
---|
608 | new_info.source = path; |
---|
609 | build_info.compiles.push_back(new_info); |
---|
610 | } |
---|
611 | } |
---|
612 | } |
---|
613 | |
---|
614 | for (prop_i = makeobject_properties.begin(); prop_i != makeobject_properties.end(); prop_i++) { |
---|
615 | CdlProperty_String prop = dynamic_cast<CdlProperty_String>(*prop_i); |
---|
616 | CYG_LOOP_INVARIANT_CLASSC(prop); |
---|
617 | |
---|
618 | // Does thie property have a library option? |
---|
619 | std::string current_library = prop->get_option("library"); |
---|
620 | if ("" == current_library) { |
---|
621 | current_library = package_library; |
---|
622 | } |
---|
623 | |
---|
624 | // How about a priority field? The default priority for make_object is 100 |
---|
625 | // We can rely on the validation done during the parsing process |
---|
626 | cdl_int priority = 100; |
---|
627 | std::string priority_option = prop->get_option("priority"); |
---|
628 | if ("" != priority_option) { |
---|
629 | Cdl::string_to_integer(priority_option, priority); |
---|
630 | } |
---|
631 | |
---|
632 | // What we need now is the separate target, deps, and rules. These |
---|
633 | // can be obtained via a utility. The raw data will have been validated |
---|
634 | // already. |
---|
635 | std::string raw_data = prop->get_string(); |
---|
636 | std::string target; |
---|
637 | std::string deps; |
---|
638 | std::string rules; |
---|
639 | std::string error_msg; |
---|
640 | bool result; |
---|
641 | |
---|
642 | result = CdlBuildableBody::split_custom_build_step(raw_data, target, deps, rules, error_msg); |
---|
643 | CYG_ASSERTC(true == result); |
---|
644 | |
---|
645 | // Construct a local object, then copy it into the vector |
---|
646 | CdlBuildInfo_MakeObject local_copy; |
---|
647 | local_copy.priority = priority; |
---|
648 | local_copy.library = current_library; |
---|
649 | local_copy.object = target; |
---|
650 | local_copy.deps = deps; |
---|
651 | local_copy.rules = rules; |
---|
652 | |
---|
653 | build_info.make_objects.push_back(local_copy); |
---|
654 | } |
---|
655 | |
---|
656 | for (prop_i = make_properties.begin(); prop_i != make_properties.end(); prop_i++) { |
---|
657 | CdlProperty_String prop = dynamic_cast<CdlProperty_String>(*prop_i); |
---|
658 | CYG_LOOP_INVARIANT_CLASSC(prop); |
---|
659 | |
---|
660 | // Is there a priority field? The default priority for make is |
---|
661 | // 300 We can rely on the validation done during the parsing |
---|
662 | // process |
---|
663 | cdl_int priority = 300; |
---|
664 | std::string priority_option = prop->get_option("priority"); |
---|
665 | if ("" != priority_option) { |
---|
666 | Cdl::string_to_integer(priority_option, priority); |
---|
667 | } |
---|
668 | |
---|
669 | // What we need now is the separate target, deps, and rules. These |
---|
670 | // can be obtained via a utility. The raw data will have been validated |
---|
671 | // already. |
---|
672 | std::string raw_data = prop->get_string(); |
---|
673 | std::string target; |
---|
674 | std::string deps; |
---|
675 | std::string rules; |
---|
676 | std::string error_msg; |
---|
677 | bool result; |
---|
678 | |
---|
679 | result = CdlBuildableBody::split_custom_build_step(raw_data, target, deps, rules, error_msg); |
---|
680 | CYG_ASSERTC(true == result); |
---|
681 | |
---|
682 | // Construct a local object, then copy it into the vector |
---|
683 | CdlBuildInfo_Make local_copy; |
---|
684 | local_copy.priority = priority; |
---|
685 | local_copy.target = target; |
---|
686 | local_copy.deps = deps; |
---|
687 | local_copy.rules = rules; |
---|
688 | |
---|
689 | build_info.makes.push_back(local_copy); |
---|
690 | } |
---|
691 | |
---|
692 | CYG_REPORT_RETURN(); |
---|
693 | } |
---|
694 | |
---|
695 | //}}} |
---|
696 | |
---|
697 | //}}} |
---|
698 | //{{{ CdlBuildLoadableBody |
---|
699 | |
---|
700 | //{{{ Class variables |
---|
701 | |
---|
702 | // ---------------------------------------------------------------------------- |
---|
703 | // This variable controls the default library that should be generated. |
---|
704 | // Some applications may wish to override this. |
---|
705 | char* CdlBuildLoadableBody::default_library_name = "libtarget.a"; |
---|
706 | |
---|
707 | // The pattern that should be used to identify header files. |
---|
708 | // FIXME: this information should come out of a data file |
---|
709 | char* CdlBuildLoadableBody::default_headers_glob_pattern = "*.h *.hxx *.inl *.si *.inc"; |
---|
710 | |
---|
711 | //}}} |
---|
712 | //{{{ The simple stuff |
---|
713 | |
---|
714 | // ---------------------------------------------------------------------------- |
---|
715 | |
---|
716 | CdlBuildLoadableBody::CdlBuildLoadableBody() |
---|
717 | : CdlLoadableBody() |
---|
718 | { |
---|
719 | CYG_REPORT_FUNCNAME("CdlBuildLoadable:: default constructor"); |
---|
720 | CYG_REPORT_FUNCARG1XV(this); |
---|
721 | |
---|
722 | // There is no data to initialize |
---|
723 | cdlbuildloadablebody_cookie = CdlBuildLoadableBody_Magic; |
---|
724 | CYGDBG_MEMLEAK_CONSTRUCTOR(); |
---|
725 | |
---|
726 | CYG_POSTCONDITION_THISC(); |
---|
727 | CYG_REPORT_RETURN(); |
---|
728 | } |
---|
729 | |
---|
730 | CdlBuildLoadableBody::~CdlBuildLoadableBody() |
---|
731 | { |
---|
732 | CYG_REPORT_FUNCNAME("CdlBuildLoadable:: destructor"); |
---|
733 | CYG_REPORT_FUNCARG1XV(this); |
---|
734 | CYG_PRECONDITION_THISC(); |
---|
735 | |
---|
736 | cdlbuildloadablebody_cookie = CdlBuildLoadableBody_Invalid; |
---|
737 | CYGDBG_MEMLEAK_DESTRUCTOR(); |
---|
738 | |
---|
739 | CYG_REPORT_RETURN(); |
---|
740 | } |
---|
741 | |
---|
742 | // ---------------------------------------------------------------------------- |
---|
743 | |
---|
744 | std::string |
---|
745 | CdlBuildLoadableBody::get_class_name() const |
---|
746 | { |
---|
747 | CYG_REPORT_FUNCNAME("CdlBuildLoadable::get_class_name"); |
---|
748 | CYG_PRECONDITION_THISC(); |
---|
749 | CYG_REPORT_RETURN(); |
---|
750 | return "build_loadable"; |
---|
751 | } |
---|
752 | |
---|
753 | // ---------------------------------------------------------------------------- |
---|
754 | |
---|
755 | bool |
---|
756 | CdlBuildLoadableBody::check_this(cyg_assert_class_zeal zeal) const |
---|
757 | { |
---|
758 | if (CdlBuildLoadableBody_Magic != cdlbuildloadablebody_cookie) { |
---|
759 | return false; |
---|
760 | } |
---|
761 | CYGDBG_MEMLEAK_CHECKTHIS(); |
---|
762 | return CdlContainerBody::check_this(zeal) && CdlNodeBody::check_this(zeal); |
---|
763 | } |
---|
764 | |
---|
765 | //}}} |
---|
766 | //{{{ Property parsers |
---|
767 | |
---|
768 | // ---------------------------------------------------------------------------- |
---|
769 | |
---|
770 | void |
---|
771 | CdlBuildLoadableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers) |
---|
772 | { |
---|
773 | CYG_REPORT_FUNCNAME("CdlBuildLoadable::add_property_parsers"); |
---|
774 | |
---|
775 | static CdlInterpreterCommandEntry commands[] = |
---|
776 | { |
---|
777 | CdlInterpreterCommandEntry("library", &CdlBuildLoadableBody::parse_library ), |
---|
778 | CdlInterpreterCommandEntry("makefile", &CdlBuildLoadableBody::parse_makefile ), |
---|
779 | CdlInterpreterCommandEntry("include_dir", &CdlBuildLoadableBody::parse_include_dir ), |
---|
780 | CdlInterpreterCommandEntry("include_files", &CdlBuildLoadableBody::parse_include_files ), |
---|
781 | CdlInterpreterCommandEntry("", 0 ) |
---|
782 | }; |
---|
783 | |
---|
784 | for (int i = 0; commands[i].command != 0; i++) { |
---|
785 | std::vector<CdlInterpreterCommandEntry>::const_iterator j; |
---|
786 | for (j = parsers.begin(); j != parsers.end(); j++) { |
---|
787 | if (commands[i].name == j->name) { |
---|
788 | if (commands[i].command != j->command) { |
---|
789 | CYG_FAIL("Property names are being re-used"); |
---|
790 | } |
---|
791 | break; |
---|
792 | } |
---|
793 | } |
---|
794 | if (j == parsers.end()) { |
---|
795 | parsers.push_back(commands[i]); |
---|
796 | } |
---|
797 | } |
---|
798 | |
---|
799 | CYG_REPORT_RETURN(); |
---|
800 | } |
---|
801 | |
---|
802 | void |
---|
803 | CdlBuildLoadableBody::check_properties(CdlInterpreter interp) |
---|
804 | { |
---|
805 | CYG_REPORT_FUNCNAME("CdlBuildLoadable::check_properties"); |
---|
806 | CYG_REPORT_FUNCARG2XV(this, interp); |
---|
807 | CYG_PRECONDITION_THISC(); |
---|
808 | CYG_PRECONDITION_CLASSC(interp); |
---|
809 | |
---|
810 | CdlNodeBody::check_properties(interp); |
---|
811 | |
---|
812 | CYG_REPORT_RETURN(); |
---|
813 | } |
---|
814 | |
---|
815 | // ---------------------------------------------------------------------------- |
---|
816 | // syntax: library <filename> |
---|
817 | // |
---|
818 | // NOTE: there should probably be a check that the library name is in |
---|
819 | // a valid format, i.e. libxxx.a |
---|
820 | |
---|
821 | int |
---|
822 | CdlBuildLoadableBody::parse_library(CdlInterpreter interp, int argc, const char* argv[]) |
---|
823 | { |
---|
824 | CYG_REPORT_FUNCNAMETYPE("parse_library", "result %d"); |
---|
825 | |
---|
826 | int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Library, 0, 0); |
---|
827 | |
---|
828 | CYG_REPORT_RETVAL(result); |
---|
829 | return result; |
---|
830 | } |
---|
831 | |
---|
832 | // ---------------------------------------------------------------------------- |
---|
833 | // syntax: makefile <filename> |
---|
834 | // |
---|
835 | // NOTE: possibly there should be a check that the makefile exists. |
---|
836 | // Do we want to allow build_proc's to generate makefiles? |
---|
837 | int |
---|
838 | CdlBuildLoadableBody::parse_makefile(CdlInterpreter interp, int argc, const char* argv[]) |
---|
839 | { |
---|
840 | CYG_REPORT_FUNCNAMETYPE("parse_makefile", "result %d"); |
---|
841 | |
---|
842 | int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Makefile, 0, 0); |
---|
843 | |
---|
844 | CYG_REPORT_RETVAL(result); |
---|
845 | return result; |
---|
846 | } |
---|
847 | |
---|
848 | // ---------------------------------------------------------------------------- |
---|
849 | // syntax: include_dir <directory name> |
---|
850 | int |
---|
851 | CdlBuildLoadableBody::parse_include_dir(CdlInterpreter interp, int argc, const char* argv[]) |
---|
852 | { |
---|
853 | CYG_REPORT_FUNCNAMETYPE("parse_include_dir", "result %d"); |
---|
854 | |
---|
855 | int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_IncludeDir, 0, 0); |
---|
856 | |
---|
857 | CYG_REPORT_RETVAL(result); |
---|
858 | return result; |
---|
859 | } |
---|
860 | |
---|
861 | // ---------------------------------------------------------------------------- |
---|
862 | // Syntax: include_files <file1 file2 ...> |
---|
863 | // |
---|
864 | // This lists the header files that should be copied into the install tree |
---|
865 | // as part of the build operation. In the absence of an include_files property |
---|
866 | // there should be an include subdirectory, and all files in that subdirectory |
---|
867 | // are assumed to be exportable headers. |
---|
868 | // |
---|
869 | // NOTE: add a finalizer to check that the files exist or get created. |
---|
870 | |
---|
871 | int |
---|
872 | CdlBuildLoadableBody::parse_include_files(CdlInterpreter interp, int argc, const char* argv[]) |
---|
873 | { |
---|
874 | CYG_REPORT_FUNCNAMETYPE("parse_include_files", "result %d"); |
---|
875 | |
---|
876 | int result = CdlParse::parse_stringvector_property(interp, argc, argv, CdlPropertyId_IncludeFiles, 0, 0, true); |
---|
877 | |
---|
878 | CYG_REPORT_RETVAL(result); |
---|
879 | return result; |
---|
880 | } |
---|
881 | |
---|
882 | //}}} |
---|
883 | //{{{ update_build_info() |
---|
884 | |
---|
885 | // ---------------------------------------------------------------------------- |
---|
886 | // This utility routine takes care of filling in a Buildinfo_Loadable |
---|
887 | // structure with the appropriate header file information. This involves |
---|
888 | // the following: |
---|
889 | // |
---|
890 | // 1) there may be an include_dir property. This affects the destination |
---|
891 | // of any header files that are listed. |
---|
892 | // |
---|
893 | // 2) the loadable may or may not have an include subdirectory. For |
---|
894 | // non-trivial packages the include subdirectory provides a clean |
---|
895 | // way of separating interface and implementation. For simple |
---|
896 | // packages it is too heavyweight. |
---|
897 | // |
---|
898 | // 3) there may be one or more include_files property. If so then these |
---|
899 | // specify all the files that should be exported. |
---|
900 | // |
---|
901 | // 4) otherwise if there is an include subdirectory then we need to |
---|
902 | // know all the header files in that subdirectory. A Tcl script is |
---|
903 | // used for this. |
---|
904 | // |
---|
905 | // 5) otherwise all the header files below the package directory itself |
---|
906 | // are of interest. |
---|
907 | |
---|
908 | static void |
---|
909 | update_header_file_info(CdlConstBuildLoadable loadable, CdlBuildInfo_Loadable& build_info) |
---|
910 | { |
---|
911 | CYG_REPORT_FUNCNAME("update_header_file_info"); |
---|
912 | CYG_REPORT_FUNCARG2XV(loadable, &build_info); |
---|
913 | CYG_PRECONDITION_CLASSC(loadable); |
---|
914 | |
---|
915 | std::string dest_dir = ""; |
---|
916 | CdlProperty include_dir_prop = loadable->get_property(CdlPropertyId_IncludeDir); |
---|
917 | if (0 != include_dir_prop) { |
---|
918 | CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(include_dir_prop); |
---|
919 | CYG_ASSERT_CLASSC(strprop); |
---|
920 | dest_dir = strprop->get_string(); |
---|
921 | } |
---|
922 | |
---|
923 | bool has_include_subdir = loadable->has_subdirectory("include"); |
---|
924 | |
---|
925 | std::vector<CdlProperty> include_file_properties; |
---|
926 | loadable->get_properties(CdlPropertyId_IncludeFiles, include_file_properties); |
---|
927 | if (include_file_properties.size() > 0) { |
---|
928 | std::vector<CdlProperty>::const_iterator prop_i; |
---|
929 | for (prop_i = include_file_properties.begin(); prop_i != include_file_properties.end(); prop_i++) { |
---|
930 | |
---|
931 | CdlProperty_StringVector strvprop = dynamic_cast<CdlProperty_StringVector>(*prop_i); |
---|
932 | CYG_ASSERT_CLASSC(strvprop); |
---|
933 | |
---|
934 | const std::vector<std::string>& filenames = strvprop->get_strings(); |
---|
935 | std::vector<std::string>::const_iterator file_i; |
---|
936 | for (file_i = filenames.begin(); file_i != filenames.end(); file_i++) { |
---|
937 | std::string path = loadable->find_relative_file(*file_i, "include"); |
---|
938 | // Assume that the header file will be generated by a build_proc |
---|
939 | if ("" == path) { |
---|
940 | if (has_include_subdir) { |
---|
941 | path = "include/" + *file_i; |
---|
942 | } else { |
---|
943 | path = *file_i; |
---|
944 | } |
---|
945 | } |
---|
946 | CdlBuildInfo_Header local_copy; |
---|
947 | local_copy.source = path; |
---|
948 | local_copy.destination = ""; |
---|
949 | if ("" != dest_dir) { |
---|
950 | local_copy.destination = dest_dir + "/"; |
---|
951 | } |
---|
952 | // At this stage "path" may begin with "include/", which should not |
---|
953 | // be present in the destination. |
---|
954 | const char* tmp = path.c_str(); |
---|
955 | if (0 == strncmp("include/", tmp, 8)) { |
---|
956 | local_copy.destination += &(tmp[8]); |
---|
957 | } else { |
---|
958 | local_copy.destination += path; |
---|
959 | } |
---|
960 | build_info.headers.push_back(local_copy); |
---|
961 | } |
---|
962 | } |
---|
963 | CYG_REPORT_RETURN(); |
---|
964 | return; |
---|
965 | } |
---|
966 | |
---|
967 | // It is necessary to search for the appropriate files. |
---|
968 | CdlInterpreter interp = loadable->get_interpreter(); |
---|
969 | std::string path = loadable->get_repository() + "/" + loadable->get_directory(); |
---|
970 | if (has_include_subdir) { |
---|
971 | std::vector<std::string> files; |
---|
972 | std::vector<std::string>::const_iterator file_i; |
---|
973 | interp->locate_all_files(path + "/include", files); |
---|
974 | for (file_i = files.begin(); file_i != files.end(); file_i++) { |
---|
975 | // NOTE: for now discard any header files in the pkgconf subdirectory |
---|
976 | if (0 == strncmp("pkgconf/", file_i->c_str(), 8)) { |
---|
977 | continue; |
---|
978 | } |
---|
979 | if ('~' == *(file_i->rbegin())) { |
---|
980 | continue; |
---|
981 | } |
---|
982 | CdlBuildInfo_Header local_copy; |
---|
983 | local_copy.source = "include/" + *file_i; |
---|
984 | local_copy.destination = ""; |
---|
985 | if ("" != dest_dir) { |
---|
986 | local_copy.destination = dest_dir + "/"; |
---|
987 | } |
---|
988 | local_copy.destination += *file_i; |
---|
989 | build_info.headers.push_back(local_copy); |
---|
990 | } |
---|
991 | } else { |
---|
992 | // Look for all header files, which for now means files with |
---|
993 | // a .h, .hxx, .inl or .inc extension. |
---|
994 | // FIXME: the definition of what constitutes a header file |
---|
995 | // should not be hard-wired here. |
---|
996 | std::vector<std::string> files; |
---|
997 | std::vector<std::string>::const_iterator file_i; |
---|
998 | interp->locate_all_files(path, files); |
---|
999 | for (file_i = files.begin(); file_i != files.end(); file_i++) { |
---|
1000 | |
---|
1001 | // Problems with libstdc++ versions, use C comparisons instead. |
---|
1002 | const char* c_string = file_i->c_str(); |
---|
1003 | unsigned int len = strlen(c_string); |
---|
1004 | if (((len >= 2) && (0 == strncmp(c_string + len - 2, ".h", 2))) || |
---|
1005 | ((len >= 4) && (0 == strncmp(c_string + len - 4, ".hxx", 4))) || |
---|
1006 | ((len >= 4) && (0 == strncmp(c_string + len - 4, ".inl", 4))) || |
---|
1007 | ((len >= 4) && (0 == strncmp(c_string + len - 4, ".inc", 4)))) { |
---|
1008 | |
---|
1009 | CdlBuildInfo_Header local_copy; |
---|
1010 | local_copy.source = *file_i; |
---|
1011 | local_copy.destination = ""; |
---|
1012 | if ("" != dest_dir) { |
---|
1013 | local_copy.destination = dest_dir + "/"; |
---|
1014 | } |
---|
1015 | local_copy.destination += *file_i; |
---|
1016 | build_info.headers.push_back(local_copy); |
---|
1017 | } |
---|
1018 | } |
---|
1019 | } |
---|
1020 | |
---|
1021 | CYG_REPORT_RETURN(); |
---|
1022 | return; |
---|
1023 | } |
---|
1024 | |
---|
1025 | // ---------------------------------------------------------------------------- |
---|
1026 | // Updating a loadable build's info involves two steps. First, there |
---|
1027 | // is some information associated with the loadable as a whole such as |
---|
1028 | // header files. Second, each buildable in the loadable (including itself) |
---|
1029 | // may contain properties such as compile etc. This is all handled via |
---|
1030 | // a CdlBuildable member function. |
---|
1031 | |
---|
1032 | void |
---|
1033 | CdlBuildLoadableBody::update_build_info(CdlBuildInfo& build_info) const |
---|
1034 | { |
---|
1035 | CYG_REPORT_FUNCNAME("CdlBuildLoadable::update_build_info"); |
---|
1036 | CYG_REPORT_FUNCARG2XV(this, &build_info); |
---|
1037 | CYG_PRECONDITION_THISC(); |
---|
1038 | |
---|
1039 | // It is not possible to disable a loadable itself: either the |
---|
1040 | // loadable is present or it is not (although in some cases users |
---|
1041 | // may be able to change versions). However, because of reparenting |
---|
1042 | // it is possible for a loadable to be below a disabled container, |
---|
1043 | // and hence it is still necessary to check whether or not the |
---|
1044 | // loadable is active. |
---|
1045 | if (!is_active()) { |
---|
1046 | CYG_REPORT_RETURN(); |
---|
1047 | return; |
---|
1048 | } |
---|
1049 | |
---|
1050 | // Time to add a new CdlBuildInfo_Loadable object to the current |
---|
1051 | // vector. The name and directory can be filled in straightaway, |
---|
1052 | // the vectors will all be initialized to empty. |
---|
1053 | CdlBuildInfo_Loadable tmp_info; |
---|
1054 | build_info.entries.push_back(tmp_info); |
---|
1055 | CdlBuildInfo_Loadable& this_info = *(build_info.entries.rbegin()); |
---|
1056 | this_info.name = get_name(); |
---|
1057 | this_info.repository = get_repository(); |
---|
1058 | this_info.directory = get_directory(); |
---|
1059 | |
---|
1060 | // Take care of the header files |
---|
1061 | update_header_file_info(this, this_info); |
---|
1062 | |
---|
1063 | // Work out the library name appropriate for this loadable. |
---|
1064 | // There may be a library property, otherwise the global default |
---|
1065 | // should be used. |
---|
1066 | std::string loadable_library = default_library_name; |
---|
1067 | if (has_property(CdlPropertyId_Library)) { |
---|
1068 | CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_Library)); |
---|
1069 | loadable_library = strprop->get_string(); |
---|
1070 | } |
---|
1071 | |
---|
1072 | const std::vector<CdlNode>& contents = get_owned(); |
---|
1073 | std::vector<CdlNode>::const_iterator node_i; |
---|
1074 | for (node_i = contents.begin(); node_i != contents.end(); node_i++) { |
---|
1075 | CdlBuildable buildable = dynamic_cast<CdlBuildable>(*node_i); |
---|
1076 | if (0 != buildable) { |
---|
1077 | buildable->update_build_info(this_info, loadable_library); |
---|
1078 | } |
---|
1079 | } |
---|
1080 | |
---|
1081 | CYG_REPORT_RETURN(); |
---|
1082 | } |
---|
1083 | |
---|
1084 | // This is much the same as the above, but there is no test for |
---|
1085 | // active either at the loadable level or for the individual buildables. |
---|
1086 | void |
---|
1087 | CdlBuildLoadableBody::update_all_build_info(CdlBuildInfo& build_info) const |
---|
1088 | { |
---|
1089 | CYG_REPORT_FUNCNAME("CdlBuildLoadable::update_all_build_info"); |
---|
1090 | CYG_REPORT_FUNCARG2XV(this, &build_info); |
---|
1091 | CYG_PRECONDITION_THISC(); |
---|
1092 | |
---|
1093 | CdlBuildInfo_Loadable tmp_info; |
---|
1094 | build_info.entries.push_back(tmp_info); |
---|
1095 | CdlBuildInfo_Loadable& this_info = *(build_info.entries.rbegin()); |
---|
1096 | this_info.name = get_name(); |
---|
1097 | this_info.directory = get_directory(); |
---|
1098 | |
---|
1099 | std::string loadable_library = default_library_name; |
---|
1100 | if (has_property(CdlPropertyId_Library)) { |
---|
1101 | CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_Library)); |
---|
1102 | loadable_library = strprop->get_string(); |
---|
1103 | } |
---|
1104 | |
---|
1105 | const std::vector<CdlNode>& contents = get_owned(); |
---|
1106 | std::vector<CdlNode>::const_iterator node_i; |
---|
1107 | for (node_i = contents.begin(); node_i != contents.end(); node_i++) { |
---|
1108 | CdlBuildable buildable = dynamic_cast<CdlBuildable>(*node_i); |
---|
1109 | if (0 != buildable) { |
---|
1110 | buildable->update_build_info(this_info, loadable_library); |
---|
1111 | } |
---|
1112 | } |
---|
1113 | |
---|
1114 | CYG_REPORT_RETURN(); |
---|
1115 | CYG_REPORT_RETURN(); |
---|
1116 | } |
---|
1117 | |
---|
1118 | //}}} |
---|
1119 | |
---|
1120 | //}}} |
---|
1121 | //{{{ Version number #define's |
---|
1122 | |
---|
1123 | // ---------------------------------------------------------------------------- |
---|
1124 | // Given a package xxxPKG_A_B_C with a version V1_2_3, generate additional |
---|
1125 | // #define's of the form: |
---|
1126 | // |
---|
1127 | // #define xxxNUM_A_B_C_VERSION_MAJOR 1 |
---|
1128 | // #define xxxNUM_A_B_C_VERSION_MINOR 2 |
---|
1129 | // #define xxxNUM_A_B_C_VERSION_RELEASE 3 |
---|
1130 | // |
---|
1131 | // The goal here is to allow application code to cope with API |
---|
1132 | // changes (which of course should be a rare event but cannot be |
---|
1133 | // eliminated completely). C preprocessor #if statements are |
---|
1134 | // essentially limited to numerical values, so there is no easy |
---|
1135 | // way of coping with V1_2_3 at the preprocessor level. However it |
---|
1136 | // is possible to cope with VERSION_NUMBER #define's. |
---|
1137 | // |
---|
1138 | // Note that only application code and third party packages are |
---|
1139 | // affected. |
---|
1140 | // |
---|
1141 | // These #define's go into system.h, alongside the main definition of |
---|
1142 | // the package. There seems to be little point in putting them in the |
---|
1143 | // package's own configuration header. |
---|
1144 | // |
---|
1145 | // There are three problems. First, what should be done for packages |
---|
1146 | // which do not follow the naming conventions? Given a completely |
---|
1147 | // random package rather than something like xxxPKG_..., what symbol |
---|
1148 | // names should be used? Basically, if the package does not follow the |
---|
1149 | // naming convention then there is no safe way of generating new |
---|
1150 | // symbols. Any names that are chosen might clash. Of course even for |
---|
1151 | // packages that do follow the naming convention a clash is still |
---|
1152 | // possible, just a lot less likely. |
---|
1153 | // |
---|
1154 | // Conclusion: if a package does not follow the naming convention, do |
---|
1155 | // not generate version #define's for it. |
---|
1156 | // |
---|
1157 | // Second, what happens if a different version numbering scheme is |
---|
1158 | // used? For example the release number might be absent. Version |
---|
1159 | // numbering schemes might change between releases, but application |
---|
1160 | // code may still check the #define's. |
---|
1161 | // |
---|
1162 | // Third and related, what should happen for "current" and anoncvs? Do |
---|
1163 | // we want to look at what other versions are installed and bump one |
---|
1164 | // of the numbers? |
---|
1165 | // |
---|
1166 | // Conclusion: the version #define's always have to be generated, |
---|
1167 | // even if they are not present in the version string, to allow |
---|
1168 | // application code to test these symbols anyway. A safe default is |
---|
1169 | // necessary, and -1 is probably the best bet. For example, if |
---|
1170 | // the version is bumped from 1.3.287 to 1.4 then the release number |
---|
1171 | // for the latter is set to -1. Another possible default would be |
---|
1172 | // 0, but that could cause problems for packages that start counting |
---|
1173 | // from 0 (not a common practice, but...) |
---|
1174 | // |
---|
1175 | // This leaves the question of what to do about "current". Chances are |
---|
1176 | // that "current" comes from anoncvs and is always more recent than |
---|
1177 | // any official release, so when comparing versions "current" should |
---|
1178 | // always be greater than anything else. This can be achieved by using |
---|
1179 | // a sufficiently large number for the major version. In practice |
---|
1180 | // it is cleaner to have another #define to indicate the current |
---|
1181 | // version, and then define package versions to match, i.e.: |
---|
1182 | // |
---|
1183 | // #define CYGNUM_VERSION_CURRENT 0x7fffff00 |
---|
1184 | // ... |
---|
1185 | // #define xxxNUM_A_B_C_VERSION_MAJOR CYGNUM_VERSION_CURRENT |
---|
1186 | // #define xxxNUM_A_B_C_VERSION_MINOR -1 |
---|
1187 | // #define xxxNUM_A_B_C_VERSION_RELEASE -1 |
---|
1188 | // |
---|
1189 | // All comparisons should now work sensibly. Leaving a little bit |
---|
1190 | // of slack for VERSION_CURRENT seems like a good precaution. |
---|
1191 | |
---|
1192 | static void |
---|
1193 | system_h_add_version_header(Tcl_Channel system_h) |
---|
1194 | { |
---|
1195 | CYG_REPORT_FUNCNAME("system_h_add_version_header"); |
---|
1196 | Tcl_Write(system_h, "#define CYGNUM_VERSION_CURRENT 0x7fffff00\n", -1); |
---|
1197 | CYG_REPORT_RETURN(); |
---|
1198 | } |
---|
1199 | |
---|
1200 | static void |
---|
1201 | system_h_add_package_versioning(Tcl_Channel system_h, std::string name, std::string value) |
---|
1202 | { |
---|
1203 | CYG_REPORT_FUNCNAME("system_h_add_package_versioning"); |
---|
1204 | |
---|
1205 | char name_buf[256]; |
---|
1206 | char line_buf[512]; |
---|
1207 | |
---|
1208 | // The first thing to check is that the package name can be used |
---|
1209 | // as the basis for the version symbols. |
---|
1210 | bool ok = false; |
---|
1211 | unsigned int i; |
---|
1212 | for (i = 0; i < name.size(); i++) { |
---|
1213 | if ('_' == name[i]) { |
---|
1214 | if (3 < i) { |
---|
1215 | if ((name[i-3] == 'P') && (name[i-2] == 'K') && (name[i-1] == 'G')) { |
---|
1216 | ok = true; |
---|
1217 | } |
---|
1218 | } |
---|
1219 | break; |
---|
1220 | } |
---|
1221 | } |
---|
1222 | if (name.size() >= 256) { |
---|
1223 | ok = false; |
---|
1224 | } |
---|
1225 | if (!ok) { |
---|
1226 | CYG_REPORT_RETURN(); |
---|
1227 | return; |
---|
1228 | } |
---|
1229 | |
---|
1230 | strcpy(name_buf, name.c_str()); |
---|
1231 | |
---|
1232 | // Change from xxxPKG to xxxNUM |
---|
1233 | name_buf[i - 3] = 'N'; |
---|
1234 | name_buf[i - 2] = 'U'; |
---|
1235 | name_buf[i - 1] = 'M'; |
---|
1236 | |
---|
1237 | // Now determine the version strings. |
---|
1238 | std::string major = "-1"; |
---|
1239 | std::string minor = "-1"; |
---|
1240 | std::string release = "-1"; |
---|
1241 | if ("current" == value) { |
---|
1242 | major = "CYGNUM_VERSION_CURRENT"; |
---|
1243 | } else { |
---|
1244 | Cdl::split_version_string(value, major, minor, release); |
---|
1245 | } |
---|
1246 | |
---|
1247 | sprintf(line_buf, "#define %s_VERSION_MAJOR %s\n", name_buf, major.c_str()); |
---|
1248 | Tcl_Write(system_h, line_buf, -1); |
---|
1249 | sprintf(line_buf, "#define %s_VERSION_MINOR %s\n", name_buf, minor.c_str()); |
---|
1250 | Tcl_Write(system_h, line_buf, -1); |
---|
1251 | sprintf(line_buf, "#define %s_VERSION_RELEASE %s\n", name_buf, release.c_str()); |
---|
1252 | Tcl_Write(system_h, line_buf, -1); |
---|
1253 | |
---|
1254 | CYG_REPORT_RETURN(); |
---|
1255 | } |
---|
1256 | |
---|
1257 | //}}} |
---|
1258 | //{{{ CdlDefinableBody |
---|
1259 | |
---|
1260 | //{{{ Basics |
---|
1261 | |
---|
1262 | // ---------------------------------------------------------------------------- |
---|
1263 | |
---|
1264 | CdlDefinableBody::CdlDefinableBody() |
---|
1265 | { |
---|
1266 | CYG_REPORT_FUNCNAME("CdlDefinable:: default constructor"); |
---|
1267 | CYG_REPORT_FUNCARG1XV(this); |
---|
1268 | |
---|
1269 | // There is no data to initialize |
---|
1270 | cdldefinablebody_cookie = CdlDefinableBody_Magic; |
---|
1271 | CYGDBG_MEMLEAK_CONSTRUCTOR(); |
---|
1272 | |
---|
1273 | CYG_POSTCONDITION_THISC(); |
---|
1274 | CYG_REPORT_RETURN(); |
---|
1275 | } |
---|
1276 | |
---|
1277 | CdlDefinableBody::~CdlDefinableBody() |
---|
1278 | { |
---|
1279 | CYG_REPORT_FUNCNAME("CdlDefinable:: destructor"); |
---|
1280 | CYG_REPORT_FUNCARG1XV(this); |
---|
1281 | CYG_PRECONDITION_THISC(); |
---|
1282 | |
---|
1283 | cdldefinablebody_cookie = CdlDefinableBody_Invalid; |
---|
1284 | CYGDBG_MEMLEAK_DESTRUCTOR(); |
---|
1285 | |
---|
1286 | CYG_REPORT_RETURN(); |
---|
1287 | } |
---|
1288 | |
---|
1289 | // ---------------------------------------------------------------------------- |
---|
1290 | |
---|
1291 | std::string |
---|
1292 | CdlDefinableBody::get_class_name() const |
---|
1293 | { |
---|
1294 | CYG_REPORT_FUNCNAME("CdlDefinable::get_class_name"); |
---|
1295 | CYG_PRECONDITION_THISC(); |
---|
1296 | CYG_REPORT_RETURN(); |
---|
1297 | return "definable"; |
---|
1298 | } |
---|
1299 | |
---|
1300 | // ---------------------------------------------------------------------------- |
---|
1301 | |
---|
1302 | bool |
---|
1303 | CdlDefinableBody::check_this(cyg_assert_class_zeal zeal) const |
---|
1304 | { |
---|
1305 | if (CdlDefinableBody_Magic != cdldefinablebody_cookie) { |
---|
1306 | return false; |
---|
1307 | } |
---|
1308 | CYGDBG_MEMLEAK_CHECKTHIS(); |
---|
1309 | return CdlNodeBody::check_this(zeal); |
---|
1310 | } |
---|
1311 | |
---|
1312 | //}}} |
---|
1313 | //{{{ add_property_parser() and check_properties() |
---|
1314 | |
---|
1315 | // ---------------------------------------------------------------------------- |
---|
1316 | |
---|
1317 | void |
---|
1318 | CdlDefinableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers) |
---|
1319 | { |
---|
1320 | CYG_REPORT_FUNCNAME("CdlDefinable::add_property_parsers"); |
---|
1321 | |
---|
1322 | static CdlInterpreterCommandEntry commands[] = |
---|
1323 | { |
---|
1324 | CdlInterpreterCommandEntry("no_define", &parse_no_define ), |
---|
1325 | CdlInterpreterCommandEntry("define", &parse_define ), |
---|
1326 | CdlInterpreterCommandEntry("define_format", &parse_define_format ), |
---|
1327 | CdlInterpreterCommandEntry("define_proc", &parse_define_proc ), |
---|
1328 | CdlInterpreterCommandEntry("if_define", &parse_if_define ), |
---|
1329 | CdlInterpreterCommandEntry("", 0 ) |
---|
1330 | }; |
---|
1331 | |
---|
1332 | for (int i = 0; commands[i].command != 0; i++) { |
---|
1333 | std::vector<CdlInterpreterCommandEntry>::const_iterator j; |
---|
1334 | for (j = parsers.begin(); j != parsers.end(); j++) { |
---|
1335 | if (commands[i].name == j->name) { |
---|
1336 | if (commands[i].command != j->command) { |
---|
1337 | CYG_FAIL("Property names are being re-used"); |
---|
1338 | } |
---|
1339 | break; |
---|
1340 | } |
---|
1341 | } |
---|
1342 | if (j == parsers.end()) { |
---|
1343 | parsers.push_back(commands[i]); |
---|
1344 | } |
---|
1345 | } |
---|
1346 | CdlNodeBody::add_property_parsers(parsers); |
---|
1347 | |
---|
1348 | CYG_REPORT_RETURN(); |
---|
1349 | } |
---|
1350 | |
---|
1351 | void |
---|
1352 | CdlDefinableBody::check_properties(CdlInterpreter interp) |
---|
1353 | { |
---|
1354 | CYG_REPORT_FUNCNAME("CdlDefinable::check_properties"); |
---|
1355 | CYG_REPORT_FUNCARG2XV(this, interp); |
---|
1356 | CYG_PRECONDITION_THISC(); |
---|
1357 | CYG_PRECONDITION_CLASSC(interp); |
---|
1358 | |
---|
1359 | // There should be at most one each of no_define and define_format. |
---|
1360 | if (count_properties(CdlPropertyId_NoDefine) > 1) { |
---|
1361 | CdlParse::report_error(interp, "", "There should be at most one no_define property."); |
---|
1362 | } |
---|
1363 | if (count_properties(CdlPropertyId_DefineFormat) > 1) { |
---|
1364 | CdlParse::report_error(interp, "", "There should be at most one define_format property."); |
---|
1365 | } |
---|
1366 | if (has_property(CdlPropertyId_NoDefine) && has_property(CdlPropertyId_DefineFormat)) { |
---|
1367 | CdlParse::report_error(interp, "", "The no_define and define_format properties are mutually exclusive."); |
---|
1368 | } |
---|
1369 | // FIXME: the define_format property only makes sense for certain |
---|
1370 | // flavors. However the flavor property may not have been processed yet. |
---|
1371 | |
---|
1372 | CdlNodeBody::check_properties(interp); |
---|
1373 | |
---|
1374 | CYG_REPORT_RETURN(); |
---|
1375 | } |
---|
1376 | |
---|
1377 | //}}} |
---|
1378 | //{{{ Definable properties |
---|
1379 | |
---|
1380 | // ---------------------------------------------------------------------------- |
---|
1381 | // Syntax: no_define |
---|
1382 | int |
---|
1383 | CdlDefinableBody::parse_no_define(CdlInterpreter interp, int argc, const char* argv[]) |
---|
1384 | { |
---|
1385 | CYG_REPORT_FUNCNAMETYPE("parse_no_define", "result %d"); |
---|
1386 | |
---|
1387 | int result = CdlParse::parse_minimal_property(interp, argc, argv, CdlPropertyId_NoDefine, 0, 0); |
---|
1388 | |
---|
1389 | CYG_REPORT_RETVAL(result); |
---|
1390 | return result; |
---|
1391 | } |
---|
1392 | |
---|
1393 | // ---------------------------------------------------------------------------- |
---|
1394 | // syntax: define <symbol> |
---|
1395 | |
---|
1396 | // The argument to "define" should be a valid C preprocessor symbol. |
---|
1397 | static void |
---|
1398 | parse_define_final_check(CdlInterpreter interp, CdlProperty_String prop) |
---|
1399 | { |
---|
1400 | CYG_REPORT_FUNCNAME("parse_define_final_check"); |
---|
1401 | CYG_PRECONDITION_CLASSC(prop); |
---|
1402 | CYG_PRECONDITION_CLASSC(interp); |
---|
1403 | |
---|
1404 | const std::string& str = prop->get_string(); |
---|
1405 | |
---|
1406 | if (!Cdl::is_valid_c_preprocessor_symbol(str)) { |
---|
1407 | CdlParse::report_property_parse_error(interp, prop, str + " is not a valid C preprocessor symbol"); |
---|
1408 | } |
---|
1409 | |
---|
1410 | // There may be a file option. At this stage the only valid filename |
---|
1411 | // that can be used here is system.h |
---|
1412 | std::string file_option = prop->get_option("file"); |
---|
1413 | if (("" != file_option) && ("system.h" != file_option)) { |
---|
1414 | CdlParse::report_property_parse_error(interp, prop, "Invalid -file option " + file_option); |
---|
1415 | } |
---|
1416 | |
---|
1417 | // FIXME: validate the format string |
---|
1418 | |
---|
1419 | CYG_REPORT_RETURN(); |
---|
1420 | } |
---|
1421 | |
---|
1422 | int |
---|
1423 | CdlDefinableBody::parse_define(CdlInterpreter interp, int argc, const char* argv[]) |
---|
1424 | { |
---|
1425 | CYG_REPORT_FUNCNAMETYPE("parse_define", "result %d"); |
---|
1426 | |
---|
1427 | static char* options[] = { |
---|
1428 | "file:", |
---|
1429 | "format:", |
---|
1430 | 0 |
---|
1431 | }; |
---|
1432 | int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Define, options, &parse_define_final_check); |
---|
1433 | |
---|
1434 | CYG_REPORT_RETVAL(result); |
---|
1435 | return result; |
---|
1436 | } |
---|
1437 | |
---|
1438 | |
---|
1439 | // ---------------------------------------------------------------------------- |
---|
1440 | // syntax: define_format <string> |
---|
1441 | // |
---|
1442 | // FIXME: it is possible to apply some checks to the string, e.g. that there |
---|
1443 | // is only one conversion operation. |
---|
1444 | // |
---|
1445 | // FIXME: also check that the flavor is sensible, define_format has no effect |
---|
1446 | // for none or bool |
---|
1447 | // |
---|
1448 | // FIXME: enforce mutual exclusion with no_define |
---|
1449 | |
---|
1450 | int |
---|
1451 | CdlDefinableBody::parse_define_format(CdlInterpreter interp, int argc, const char* argv[]) |
---|
1452 | { |
---|
1453 | CYG_REPORT_FUNCNAMETYPE("parse_format", "result %d"); |
---|
1454 | |
---|
1455 | int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_DefineFormat, 0, 0); |
---|
1456 | |
---|
1457 | CYG_REPORT_RETVAL(result); |
---|
1458 | return result; |
---|
1459 | } |
---|
1460 | // ---------------------------------------------------------------------------- |
---|
1461 | // syntax: define_proc <tclcode> |
---|
1462 | int |
---|
1463 | CdlDefinableBody::parse_define_proc(CdlInterpreter interp, int argc, const char* argv[]) |
---|
1464 | { |
---|
1465 | CYG_REPORT_FUNCNAMETYPE("parse_define_proc", "result %d"); |
---|
1466 | |
---|
1467 | int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_DefineProc, 0, 0); |
---|
1468 | |
---|
1469 | CYG_REPORT_RETVAL(result); |
---|
1470 | return result; |
---|
1471 | } |
---|
1472 | |
---|
1473 | // ---------------------------------------------------------------------------- |
---|
1474 | // Syntax: if_define sym1 sym2 |
---|
1475 | |
---|
1476 | static void |
---|
1477 | parse_if_define_final_check(CdlInterpreter interp, CdlProperty_StringVector prop) |
---|
1478 | { |
---|
1479 | CYG_REPORT_FUNCNAME("parse_if_define_final_check"); |
---|
1480 | CYG_PRECONDITION_CLASSC(interp); |
---|
1481 | CYG_PRECONDITION_CLASSC(prop); |
---|
1482 | |
---|
1483 | // There should be exactly two entries in the vector, and both of them should be |
---|
1484 | // valid preprocessor symbols. |
---|
1485 | const std::vector<std::string>& strings = prop->get_strings(); |
---|
1486 | |
---|
1487 | if (2 != strings.size()) { |
---|
1488 | CdlParse::report_property_parse_error(interp, prop, "There should be exactly two arguments."); |
---|
1489 | } |
---|
1490 | if (!Cdl::is_valid_c_preprocessor_symbol(strings[0])) { |
---|
1491 | CdlParse::report_property_parse_error(interp, prop, strings[0] + " is not a valid C preprocessor symbol."); |
---|
1492 | } |
---|
1493 | if (!Cdl::is_valid_c_preprocessor_symbol(strings[1])) { |
---|
1494 | CdlParse::report_property_parse_error(interp, prop, strings[1] + " is not a valid C preprocessor symbol."); |
---|
1495 | } |
---|
1496 | |
---|
1497 | // There may be a file option. At this stage the only valid filename |
---|
1498 | // that can be used here is system.h |
---|
1499 | std::string file_option = prop->get_option("file"); |
---|
1500 | if (("" != file_option) && ("system.h" != file_option)) { |
---|
1501 | CdlParse::report_property_parse_error(interp, prop, "Invalid -file option " + file_option); |
---|
1502 | } |
---|
1503 | } |
---|
1504 | |
---|
1505 | int |
---|
1506 | CdlDefinableBody::parse_if_define(CdlInterpreter interp, int argc, const char* argv[]) |
---|
1507 | { |
---|
1508 | CYG_REPORT_FUNCNAMETYPE("parse_if_define", "result %d"); |
---|
1509 | |
---|
1510 | char* options[] = { |
---|
1511 | "file:", |
---|
1512 | 0 |
---|
1513 | }; |
---|
1514 | int result = CdlParse::parse_stringvector_property(interp, argc, argv, CdlPropertyId_IfDefine, options, |
---|
1515 | &parse_if_define_final_check, false); |
---|
1516 | |
---|
1517 | CYG_REPORT_RETVAL(result); |
---|
1518 | return result; |
---|
1519 | } |
---|
1520 | |
---|
1521 | //}}} |
---|
1522 | //{{{ generate_config_header() |
---|
1523 | |
---|
1524 | // ---------------------------------------------------------------------------- |
---|
1525 | // This code needs to allow for the following properties. |
---|
1526 | // |
---|
1527 | // 1) no_define. This suppresses the default #define generation. |
---|
1528 | // |
---|
1529 | // 2) define_format <format_string. |
---|
1530 | // |
---|
1531 | // 3) define [-file <filename>][-format <format_string>] symbol |
---|
1532 | // |
---|
1533 | // 4) define_proc |
---|
1534 | // |
---|
1535 | // 5) if_define |
---|
1536 | |
---|
1537 | void |
---|
1538 | CdlDefinableBody::generate_config_header(Tcl_Channel this_hdr, Tcl_Channel system_h) const |
---|
1539 | { |
---|
1540 | CYG_REPORT_FUNCNAME("CdlDefinable::generate_config_header"); |
---|
1541 | CYG_REPORT_FUNCARG1XV(this); |
---|
1542 | CYG_PRECONDITION_THISC(); |
---|
1543 | |
---|
1544 | CdlLoadable loadable = get_owner(); |
---|
1545 | CdlInterpreter interp = loadable->get_interpreter(); |
---|
1546 | |
---|
1547 | // This definable is known to be active. However it may or may not be enabled. |
---|
1548 | CYG_PRECONDITIONC(is_active()); |
---|
1549 | |
---|
1550 | std::string name = get_name(); |
---|
1551 | CdlValueFlavor flavor = CdlValueFlavor_Bool; |
---|
1552 | std::string value = "1"; |
---|
1553 | CdlConstValuable valuable = dynamic_cast<CdlConstValuable>(this); |
---|
1554 | if (0 != valuable) { |
---|
1555 | // It is always possible to check the enabled() flag. |
---|
1556 | if (!valuable->is_enabled()) { |
---|
1557 | CYG_REPORT_RETURN(); |
---|
1558 | return; |
---|
1559 | } |
---|
1560 | // The value is only valid for BoolData and Data flavors, and may |
---|
1561 | // not have been provided. If there is no value then this option |
---|
1562 | // should not generate a #define |
---|
1563 | flavor = valuable->get_flavor(); |
---|
1564 | if ((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor)) { |
---|
1565 | value = valuable->get_value(); |
---|
1566 | } |
---|
1567 | } |
---|
1568 | |
---|
1569 | // Flavor and value are now both set to sensible strings. |
---|
1570 | // First, check the no_define property. If this is present then the default |
---|
1571 | // #define generation should be suppressed. |
---|
1572 | if (!has_property(CdlPropertyId_NoDefine)) { |
---|
1573 | |
---|
1574 | // OK, it is necessary to generate at least one #define. |
---|
1575 | // If this node is actually a loadable then the #define should go |
---|
1576 | // into system.h, otherwise into the current header |
---|
1577 | Tcl_Channel chan = this_hdr; |
---|
1578 | if (dynamic_cast<CdlConstLoadable>((CdlConstNode)this) == loadable) { |
---|
1579 | chan = system_h; |
---|
1580 | } |
---|
1581 | |
---|
1582 | // For flavors None and Bool, there should be just one #define |
---|
1583 | if ((CdlValueFlavor_None == flavor) || (CdlValueFlavor_Bool == flavor)) { |
---|
1584 | std::string define = "#define " + name + " 1\n"; |
---|
1585 | Tcl_Write(chan, const_cast<char*>(define.c_str()), -1); |
---|
1586 | } else { |
---|
1587 | // If there is a format string then that controls the default |
---|
1588 | // value display. |
---|
1589 | if (!has_property(CdlPropertyId_DefineFormat)) { |
---|
1590 | std::string define = "#define " + name + " " + value + "\n"; |
---|
1591 | Tcl_Write(chan, const_cast<char*>(define.c_str()), -1); |
---|
1592 | } else { |
---|
1593 | CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_DefineFormat)); |
---|
1594 | CYG_ASSERT_CLASSC(strprop); |
---|
1595 | std::string format = strprop->get_string(); |
---|
1596 | std::string cmd = "return \"#define " + name + " [format " + format + " " + value + "]\n\""; |
---|
1597 | std::string define; |
---|
1598 | if (TCL_OK != interp->eval(cmd, define)) { |
---|
1599 | throw CdlInputOutputException("Internal error executing tcl fragment to process define_format property"); |
---|
1600 | } |
---|
1601 | Tcl_Write(chan, const_cast<char*>(define.c_str()), -1); |
---|
1602 | } |
---|
1603 | |
---|
1604 | // There may also be a separate #define of the form <name>_<value>, |
---|
1605 | // if that is a valid preprocessor symbol. |
---|
1606 | std::string tmp = name + "_" + value; |
---|
1607 | if (Cdl::is_valid_c_preprocessor_symbol(tmp)) { |
---|
1608 | tmp = "#define "+ tmp + "\n"; |
---|
1609 | Tcl_Write(chan, const_cast<char*>(tmp.c_str()), -1); |
---|
1610 | } |
---|
1611 | |
---|
1612 | // For loadables, add additional version information to system_h |
---|
1613 | if (dynamic_cast<CdlConstLoadable>((CdlConstNode)this) == loadable) { |
---|
1614 | system_h_add_package_versioning(system_h, name, value); |
---|
1615 | } |
---|
1616 | } |
---|
1617 | } |
---|
1618 | |
---|
1619 | // Next, check for any additional define properties |
---|
1620 | std::vector<CdlProperty> define_props; |
---|
1621 | get_properties(CdlPropertyId_Define, define_props); |
---|
1622 | std::vector<CdlProperty>::const_iterator prop_i; |
---|
1623 | for (prop_i = define_props.begin(); prop_i != define_props.end(); prop_i++) { |
---|
1624 | CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(*prop_i); |
---|
1625 | CYG_ASSERT_CLASSC(strprop); |
---|
1626 | std::string symbol = strprop->get_string(); |
---|
1627 | |
---|
1628 | std::string file = strprop->get_option("file"); |
---|
1629 | Tcl_Channel chan = this_hdr; |
---|
1630 | if (("" != file) && ("system.h" == file)) { |
---|
1631 | chan = system_h; |
---|
1632 | } |
---|
1633 | |
---|
1634 | if ((CdlValueFlavor_None == flavor) || (CdlValueFlavor_Bool == flavor)) { |
---|
1635 | std::string define = "#define " + symbol + " 1\n"; |
---|
1636 | Tcl_Write(chan, const_cast<char*>(define.c_str()), -1); |
---|
1637 | } else { |
---|
1638 | std::string format = strprop->get_option("format"); |
---|
1639 | if ("" == format) { |
---|
1640 | std::string define = "#define " + symbol + " " + value + "\n"; |
---|
1641 | Tcl_Write(chan, const_cast<char*>(define.c_str()), -1); |
---|
1642 | } else { |
---|
1643 | std::string cmd = "return \"#define " + symbol + " [format " + format + " " + value + "]\n\""; |
---|
1644 | std::string define; |
---|
1645 | if (TCL_OK != interp->eval(cmd, define)) { |
---|
1646 | throw CdlInputOutputException("Internal error executing tcl fragment to process format option"); |
---|
1647 | } |
---|
1648 | Tcl_Write(chan, const_cast<char*>(define.c_str()), -1); |
---|
1649 | } |
---|
1650 | |
---|
1651 | std::string tmp = symbol + "_" + value; |
---|
1652 | if (Cdl::is_valid_c_preprocessor_symbol(tmp)) { |
---|
1653 | tmp = "#define " + tmp + "\n"; |
---|
1654 | Tcl_Write(chan, const_cast<char*>(tmp.c_str()), -1); |
---|
1655 | } |
---|
1656 | } |
---|
1657 | } |
---|
1658 | |
---|
1659 | // Now check for if_define properties |
---|
1660 | std::vector<CdlProperty> if_define_props; |
---|
1661 | get_properties(CdlPropertyId_IfDefine, if_define_props); |
---|
1662 | for (prop_i = if_define_props.begin(); prop_i != if_define_props.end(); prop_i++) { |
---|
1663 | CdlProperty_StringVector strprop = dynamic_cast<CdlProperty_StringVector>(*prop_i); |
---|
1664 | CYG_ASSERT_CLASSC(strprop); |
---|
1665 | CYG_ASSERTC(2 == strprop->get_number_of_strings()); |
---|
1666 | |
---|
1667 | std::string sym1 = strprop->get_string(0); |
---|
1668 | std::string sym2 = strprop->get_string(1); |
---|
1669 | |
---|
1670 | Tcl_Channel chan = this_hdr; |
---|
1671 | std::string file = strprop->get_option("file"); |
---|
1672 | if (("" != file) && ("system.h" == file)) { |
---|
1673 | chan = system_h; |
---|
1674 | } |
---|
1675 | std::string data = "#ifdef " + sym1 + "\n# define " + sym2 + " 1\n#endif\n"; |
---|
1676 | Tcl_Write(chan, const_cast<char*>(data.c_str()), -1); |
---|
1677 | } |
---|
1678 | |
---|
1679 | // And define_proc properties |
---|
1680 | std::vector<CdlProperty> define_proc_props; |
---|
1681 | get_properties(CdlPropertyId_DefineProc, define_proc_props); |
---|
1682 | for (prop_i = define_proc_props.begin(); prop_i != define_proc_props.end(); prop_i++) { |
---|
1683 | CdlProperty_TclCode codeprop = dynamic_cast<CdlProperty_TclCode>(*prop_i); |
---|
1684 | CYG_ASSERT_CLASSC(codeprop); |
---|
1685 | |
---|
1686 | cdl_tcl_code code = codeprop->get_code(); |
---|
1687 | std::string result; |
---|
1688 | if (TCL_OK != interp->eval(code, result)) { |
---|
1689 | throw CdlInputOutputException("Error evaluating define_proc property for " + name + "\n" + result); |
---|
1690 | } |
---|
1691 | } |
---|
1692 | |
---|
1693 | |
---|
1694 | CYG_REPORT_RETURN(); |
---|
1695 | } |
---|
1696 | |
---|
1697 | //}}} |
---|
1698 | |
---|
1699 | //}}} |
---|
1700 | //{{{ CdlDefineLoadableBody |
---|
1701 | |
---|
1702 | //{{{ Basics |
---|
1703 | |
---|
1704 | // ---------------------------------------------------------------------------- |
---|
1705 | |
---|
1706 | CdlDefineLoadableBody::CdlDefineLoadableBody() |
---|
1707 | { |
---|
1708 | CYG_REPORT_FUNCNAME("CdlDefineLoadable:: default constructor"); |
---|
1709 | CYG_REPORT_FUNCARG1XV(this); |
---|
1710 | |
---|
1711 | cdldefineloadablebody_cookie = CdlDefineLoadableBody_Magic; |
---|
1712 | CYGDBG_MEMLEAK_CONSTRUCTOR(); |
---|
1713 | |
---|
1714 | CYG_POSTCONDITION_THISC(); |
---|
1715 | CYG_REPORT_RETURN(); |
---|
1716 | } |
---|
1717 | |
---|
1718 | CdlDefineLoadableBody::~CdlDefineLoadableBody() |
---|
1719 | { |
---|
1720 | CYG_REPORT_FUNCNAME("CdlDefineLoadable:: destructor"); |
---|
1721 | CYG_REPORT_FUNCARG1XV(this); |
---|
1722 | CYG_PRECONDITION_THISC(); |
---|
1723 | |
---|
1724 | cdldefineloadablebody_cookie = CdlDefineLoadableBody_Invalid; |
---|
1725 | CYGDBG_MEMLEAK_DESTRUCTOR(); |
---|
1726 | |
---|
1727 | CYG_REPORT_RETURN(); |
---|
1728 | } |
---|
1729 | |
---|
1730 | // ---------------------------------------------------------------------------- |
---|
1731 | |
---|
1732 | std::string |
---|
1733 | CdlDefineLoadableBody::get_class_name() const |
---|
1734 | { |
---|
1735 | CYG_REPORT_FUNCNAME("CdlDefineLoadable::get_class_name"); |
---|
1736 | CYG_PRECONDITION_THISC(); |
---|
1737 | CYG_REPORT_RETURN(); |
---|
1738 | return "define_loadable"; |
---|
1739 | } |
---|
1740 | |
---|
1741 | // ---------------------------------------------------------------------------- |
---|
1742 | |
---|
1743 | bool |
---|
1744 | CdlDefineLoadableBody::check_this(cyg_assert_class_zeal zeal) const |
---|
1745 | { |
---|
1746 | if (CdlDefineLoadableBody_Magic != cdldefineloadablebody_cookie) { |
---|
1747 | return false; |
---|
1748 | } |
---|
1749 | CYGDBG_MEMLEAK_CHECKTHIS(); |
---|
1750 | return CdlLoadableBody::check_this(zeal) && CdlNodeBody::check_this(zeal); |
---|
1751 | } |
---|
1752 | |
---|
1753 | //}}} |
---|
1754 | //{{{ Property parsing |
---|
1755 | |
---|
1756 | // ---------------------------------------------------------------------------- |
---|
1757 | |
---|
1758 | void |
---|
1759 | CdlDefineLoadableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers) |
---|
1760 | { |
---|
1761 | CYG_REPORT_FUNCNAME("CdlDefineLoadable::add_property_parsers"); |
---|
1762 | |
---|
1763 | static CdlInterpreterCommandEntry commands[] = |
---|
1764 | { |
---|
1765 | CdlInterpreterCommandEntry("define_header", &parse_define_header), |
---|
1766 | CdlInterpreterCommandEntry("", 0 ) |
---|
1767 | }; |
---|
1768 | |
---|
1769 | for (int i = 0; commands[i].command != 0; i++) { |
---|
1770 | std::vector<CdlInterpreterCommandEntry>::const_iterator j; |
---|
1771 | for (j = parsers.begin(); j != parsers.end(); j++) { |
---|
1772 | if (commands[i].name == j->name) { |
---|
1773 | if (commands[i].command != j->command) { |
---|
1774 | CYG_FAIL("Property names are being re-used"); |
---|
1775 | } |
---|
1776 | break; |
---|
1777 | } |
---|
1778 | } |
---|
1779 | if (j == parsers.end()) { |
---|
1780 | parsers.push_back(commands[i]); |
---|
1781 | } |
---|
1782 | } |
---|
1783 | CdlNodeBody::add_property_parsers(parsers); |
---|
1784 | |
---|
1785 | CYG_REPORT_RETURN(); |
---|
1786 | } |
---|
1787 | |
---|
1788 | void |
---|
1789 | CdlDefineLoadableBody::check_properties(CdlInterpreter interp) |
---|
1790 | { |
---|
1791 | CYG_REPORT_FUNCNAME("CdlDefineLoadable::check_properties"); |
---|
1792 | CYG_REPORT_FUNCARG2XV(this, interp); |
---|
1793 | CYG_PRECONDITION_THISC(); |
---|
1794 | CYG_PRECONDITION_CLASSC(interp); |
---|
1795 | |
---|
1796 | // There should be at most one define_header property |
---|
1797 | int count = count_properties(CdlPropertyId_DefineHeader); |
---|
1798 | if (count> 1) { |
---|
1799 | CdlParse::report_error(interp, "", "There should be at most one define_header property."); |
---|
1800 | } |
---|
1801 | // FIXME: filename validation |
---|
1802 | |
---|
1803 | CdlNodeBody::check_properties(interp); |
---|
1804 | |
---|
1805 | CYG_REPORT_RETURN(); |
---|
1806 | } |
---|
1807 | |
---|
1808 | // ---------------------------------------------------------------------------- |
---|
1809 | // syntax: define_header <header file name> |
---|
1810 | int |
---|
1811 | CdlDefineLoadableBody::parse_define_header(CdlInterpreter interp, int argc, const char* argv[]) |
---|
1812 | { |
---|
1813 | CYG_REPORT_FUNCNAMETYPE("parse_define_header", "result %d"); |
---|
1814 | |
---|
1815 | int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_DefineHeader, 0, 0); |
---|
1816 | |
---|
1817 | CYG_REPORT_RETVAL(result); |
---|
1818 | return result; |
---|
1819 | } |
---|
1820 | |
---|
1821 | //}}} |
---|
1822 | //{{{ generate_config_header() |
---|
1823 | |
---|
1824 | // ---------------------------------------------------------------------------- |
---|
1825 | void |
---|
1826 | CdlDefineLoadableBody::generate_config_header(Tcl_Channel this_hdr, Tcl_Channel system_h) const |
---|
1827 | { |
---|
1828 | CYG_REPORT_FUNCNAME("CdlDefineLoadable::generate_config_header"); |
---|
1829 | CYG_REPORT_FUNCARG1XV(this); |
---|
1830 | CYG_PRECONDITION_THISC(); |
---|
1831 | |
---|
1832 | CdlInterpreter interp = get_interpreter(); |
---|
1833 | Tcl_RegisterChannel(interp->get_tcl_interpreter(), this_hdr); |
---|
1834 | Tcl_RegisterChannel(interp->get_tcl_interpreter(), system_h); |
---|
1835 | |
---|
1836 | CdlInterpreterBody::ContextSupport(interp, std::string("Package ") + this->get_name() + ", header file generation"); |
---|
1837 | |
---|
1838 | try { |
---|
1839 | interp->set_variable("::cdl_header", Tcl_GetChannelName(this_hdr)); |
---|
1840 | interp->set_variable("::cdl_system_header", Tcl_GetChannelName(system_h)); |
---|
1841 | |
---|
1842 | const std::vector<CdlNode>& contents = get_owned(); |
---|
1843 | std::vector<CdlNode>::const_iterator node_i; |
---|
1844 | for (node_i = contents.begin(); node_i != contents.end(); node_i++) { |
---|
1845 | CdlDefinable definable = dynamic_cast<CdlDefinable>(*node_i); |
---|
1846 | if (0 == definable) { |
---|
1847 | continue; |
---|
1848 | } |
---|
1849 | if (!definable->is_active()) { |
---|
1850 | continue; |
---|
1851 | } |
---|
1852 | definable->generate_config_header(this_hdr, system_h); |
---|
1853 | } |
---|
1854 | |
---|
1855 | interp->unset_variable("::cdl_header"); |
---|
1856 | interp->unset_variable("::cdl_system_header"); |
---|
1857 | } catch(...) { |
---|
1858 | Tcl_UnregisterChannel(interp->get_tcl_interpreter(), this_hdr); |
---|
1859 | Tcl_UnregisterChannel(interp->get_tcl_interpreter(), system_h); |
---|
1860 | throw; |
---|
1861 | } |
---|
1862 | |
---|
1863 | Tcl_UnregisterChannel(interp->get_tcl_interpreter(), this_hdr); |
---|
1864 | Tcl_UnregisterChannel(interp->get_tcl_interpreter(), system_h); |
---|
1865 | |
---|
1866 | CYG_REPORT_RETURN(); |
---|
1867 | } |
---|
1868 | |
---|
1869 | //}}} |
---|
1870 | //{{{ get_config_headers() |
---|
1871 | |
---|
1872 | // ---------------------------------------------------------------------------- |
---|
1873 | // What header file should be generated for this loadable? |
---|
1874 | // |
---|
1875 | // If there is a define_header property then this should be used. |
---|
1876 | // Otherwise a filename is constructed from the loadable's name. |
---|
1877 | |
---|
1878 | std::string |
---|
1879 | CdlDefineLoadableBody::get_config_header() const |
---|
1880 | { |
---|
1881 | CYG_REPORT_FUNCNAME("CdlDefineLoadable::get_config_headers"); |
---|
1882 | CYG_REPORT_FUNCARG1XV(this); |
---|
1883 | CYG_PRECONDITION_THISC(); |
---|
1884 | |
---|
1885 | std::string result = ""; |
---|
1886 | CdlProperty prop = get_property(CdlPropertyId_DefineHeader); |
---|
1887 | if (0 != prop) { |
---|
1888 | CdlProperty_String string_prop = dynamic_cast<CdlProperty_String>(prop); |
---|
1889 | CYG_ASSERT_CLASSC(string_prop); |
---|
1890 | result = string_prop->get_string(); |
---|
1891 | } else { |
---|
1892 | std::string tmp = get_name(); |
---|
1893 | result = Cdl::get_short_form(tmp); |
---|
1894 | result += ".h"; |
---|
1895 | } |
---|
1896 | CYG_REPORT_RETURN(); |
---|
1897 | return result; |
---|
1898 | } |
---|
1899 | |
---|
1900 | //}}} |
---|
1901 | |
---|
1902 | //}}} |
---|
1903 | //{{{ CdlToplevel |
---|
1904 | |
---|
1905 | //{{{ CdlToplevel::get_build_info() |
---|
1906 | |
---|
1907 | // ---------------------------------------------------------------------------- |
---|
1908 | // Essentially this code involves iterating over the loadables vector, |
---|
1909 | // looking for BuildLoadables and invoking their update_build_info() |
---|
1910 | // member function. In addition, if there is currently some data in |
---|
1911 | // the build_info vector (probably from a previous call) then that |
---|
1912 | // must be cleared. |
---|
1913 | |
---|
1914 | void |
---|
1915 | CdlToplevelBody::get_build_info(CdlBuildInfo& build_info) |
---|
1916 | { |
---|
1917 | CYG_REPORT_FUNCNAME("CdlToplevel::get_build_info"); |
---|
1918 | CYG_REPORT_FUNCARG2XV(this, &build_info); |
---|
1919 | CYG_PRECONDITION_THISC(); |
---|
1920 | |
---|
1921 | if (0 != build_info.entries.size()) { |
---|
1922 | build_info.entries.clear(); |
---|
1923 | } |
---|
1924 | |
---|
1925 | const std::vector<CdlLoadable>& loadables = get_loadables(); |
---|
1926 | std::vector<CdlLoadable>::const_iterator load_i; |
---|
1927 | for (load_i = loadables.begin(); load_i != loadables.end(); load_i++) { |
---|
1928 | CdlConstBuildLoadable bl = dynamic_cast<CdlConstBuildLoadable>(*load_i); |
---|
1929 | if (0 != bl) { |
---|
1930 | bl->update_build_info(build_info); |
---|
1931 | } |
---|
1932 | } |
---|
1933 | |
---|
1934 | CYG_REPORT_RETURN(); |
---|
1935 | } |
---|
1936 | |
---|
1937 | //}}} |
---|
1938 | //{{{ CdlToplevel::get_all_build_info() |
---|
1939 | |
---|
1940 | // ---------------------------------------------------------------------------- |
---|
1941 | // This is just like get_build_info(), but calls a different |
---|
1942 | // BuildLoadable member. |
---|
1943 | |
---|
1944 | void |
---|
1945 | CdlToplevelBody::get_all_build_info(CdlBuildInfo& build_info) |
---|
1946 | { |
---|
1947 | CYG_REPORT_FUNCNAME("CdlToplevel::get_all_build_info"); |
---|
1948 | CYG_REPORT_FUNCARG2XV(this, &build_info); |
---|
1949 | CYG_PRECONDITION_THISC(); |
---|
1950 | |
---|
1951 | if (0 != build_info.entries.size()) { |
---|
1952 | build_info.entries.clear(); |
---|
1953 | } |
---|
1954 | |
---|
1955 | const std::vector<CdlLoadable>& loadables = get_loadables(); |
---|
1956 | std::vector<CdlLoadable>::const_iterator load_i; |
---|
1957 | for (load_i = loadables.begin(); load_i != loadables.end(); load_i++) { |
---|
1958 | CdlConstBuildLoadable bl = dynamic_cast<CdlConstBuildLoadable>(*load_i); |
---|
1959 | if (0 != bl) { |
---|
1960 | bl->update_all_build_info(build_info); |
---|
1961 | } |
---|
1962 | } |
---|
1963 | |
---|
1964 | CYG_REPORT_RETURN(); |
---|
1965 | } |
---|
1966 | |
---|
1967 | //}}} |
---|
1968 | //{{{ CdlToplevel::generate_config_headers() |
---|
1969 | |
---|
1970 | // ---------------------------------------------------------------------------- |
---|
1971 | // Generating the config headers. This involves the following steps: |
---|
1972 | // |
---|
1973 | // 1) for every DefineLoadable, find out what header file should |
---|
1974 | // be generated. Note that some loadables may share a header file. |
---|
1975 | // |
---|
1976 | // 2) create a temporary version of system.h. Note that it is not |
---|
1977 | // a good idea to just overwrite an existing system.h, chances |
---|
1978 | // are pretty good that the file will not have changed, and |
---|
1979 | // updating it unnecessarily will result in unnecessary rebuilds |
---|
1980 | // due to header file dependencies. |
---|
1981 | // |
---|
1982 | // 3) for each file that should be generated, create a temporary |
---|
1983 | // version and allow all applicable loadables to update it. |
---|
1984 | |
---|
1985 | // A utility to compare two files and do the right thing. |
---|
1986 | // This requires some simple Tcl code. |
---|
1987 | static void |
---|
1988 | compare_and_copy(CdlInterpreter interp, std::string file1, std::string file2) |
---|
1989 | { |
---|
1990 | CYG_REPORT_FUNCNAME("compare_and_copy"); |
---|
1991 | CYG_PRECONDITION_CLASSC(interp); |
---|
1992 | CYG_PRECONDITIONC("" != file1); |
---|
1993 | CYG_PRECONDITIONC("" != file2); |
---|
1994 | CYG_PRECONDITIONC(file1 != file2); |
---|
1995 | |
---|
1996 | static char compare_and_copy_script[] = "\ |
---|
1997 | if {[file exists \"$::cdl_compare_and_copy_file2\"] == 0} { \n\ |
---|
1998 | catch { file rename -- $::cdl_compare_and_copy_file1 $::cdl_compare_and_copy_file2} \n\ |
---|
1999 | return \n\ |
---|
2000 | } \n\ |
---|
2001 | set fd [open \"$::cdl_compare_and_copy_file1\" r] \n\ |
---|
2002 | set data1 [read $fd] \n\ |
---|
2003 | close $fd \n\ |
---|
2004 | set fd [open \"$::cdl_compare_and_copy_file2\" r] \n\ |
---|
2005 | set data2 [read $fd] \n\ |
---|
2006 | close $fd \n\ |
---|
2007 | if {$data1 == $data2} { \n\ |
---|
2008 | file delete \"$::cdl_compare_and_copy_file1\" \n\ |
---|
2009 | } else { \n\ |
---|
2010 | catch { file rename -force -- $::cdl_compare_and_copy_file1 $::cdl_compare_and_copy_file2 } \n\ |
---|
2011 | } \n\ |
---|
2012 | "; |
---|
2013 | |
---|
2014 | interp->set_variable("::cdl_compare_and_copy_file1", file1); |
---|
2015 | interp->set_variable("::cdl_compare_and_copy_file2", file2); |
---|
2016 | std::string tcl_result; |
---|
2017 | if (TCL_OK != interp->eval(compare_and_copy_script, tcl_result)) { |
---|
2018 | throw CdlInputOutputException("internal error manipulating temporary header " + file1 + " and target " + file2 + |
---|
2019 | "\n" + tcl_result); |
---|
2020 | } |
---|
2021 | } |
---|
2022 | |
---|
2023 | void |
---|
2024 | CdlToplevelBody::generate_config_headers(std::string directory) |
---|
2025 | { |
---|
2026 | CYG_REPORT_FUNCNAME("CdlToplevel::generate_config_headers"); |
---|
2027 | CYG_REPORT_FUNCARG1XV(this); |
---|
2028 | CYG_PRECONDITION_THISC(); |
---|
2029 | CYG_ASSERTC("" != directory); |
---|
2030 | |
---|
2031 | // Replace any backslashes in the path with forward slashes. The |
---|
2032 | // latter are used throughout the library |
---|
2033 | // NOTE: this is not i18n-friendly. |
---|
2034 | for (unsigned int i = 0; i < directory.size(); i++) { |
---|
2035 | if ('\\' == directory[i]) { |
---|
2036 | directory[i] = '/'; |
---|
2037 | } |
---|
2038 | } |
---|
2039 | |
---|
2040 | CdlInterpreter interp = get_interpreter(); |
---|
2041 | std::string tcl_result; |
---|
2042 | if ((TCL_OK != interp->eval("file isdirectory \"" + directory + "\"", tcl_result)) || |
---|
2043 | (tcl_result != "1")) { |
---|
2044 | throw CdlInputOutputException("target " + directory + " is not a valid existing directory."); |
---|
2045 | } |
---|
2046 | |
---|
2047 | std::vector<std::pair<CdlDefineLoadable, std::string> > headers; |
---|
2048 | const std::vector<CdlLoadable>& loadables = get_loadables(); |
---|
2049 | std::vector<CdlLoadable>::const_iterator load_i; |
---|
2050 | for (load_i = loadables.begin(); load_i != loadables.end(); load_i++) { |
---|
2051 | CdlDefineLoadable tmp = dynamic_cast<CdlDefineLoadable>(*load_i); |
---|
2052 | if (0 != tmp) { |
---|
2053 | std::string hdr = tmp->get_config_header(); |
---|
2054 | headers.push_back(std::make_pair(tmp, hdr)); |
---|
2055 | } |
---|
2056 | } |
---|
2057 | |
---|
2058 | static char banner_format[] = |
---|
2059 | "#ifndef CYGONCE_PKGCONF_%s\n\ |
---|
2060 | #define CYGONCE_PKGCONF_%s\n\ |
---|
2061 | /*\n\ |
---|
2062 | * File <pkgconf/%s>\n\ |
---|
2063 | *\n\ |
---|
2064 | * This file is generated automatically by the configuration\n\ |
---|
2065 | * system. It should not be edited. Any changes to this file\n\ |
---|
2066 | * may be overwritten.\n\ |
---|
2067 | */\n\ |
---|
2068 | \n"; |
---|
2069 | #ifdef _WIN32 |
---|
2070 | // Create three channels which Tcl will use for standard streams |
---|
2071 | // if these streams do not already exist. This avoids a Tcl |
---|
2072 | // problem which can prevent closure of system.h. (FIXME) |
---|
2073 | Tcl_Channel stdin_chan = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), "nul", "w", 0666); |
---|
2074 | Tcl_Channel stdout_chan = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), "nul", "w", 0666); |
---|
2075 | Tcl_Channel stderr_chan = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), "nul", "w", 0666); |
---|
2076 | Tcl_RegisterChannel(0, stdin_chan); |
---|
2077 | Tcl_RegisterChannel(0, stdout_chan); |
---|
2078 | Tcl_RegisterChannel(0, stderr_chan); |
---|
2079 | #endif |
---|
2080 | // Assume for now that files __libcdl_file1 and __libcdl_file2 are |
---|
2081 | // legal on all platforms of interest, and that nobody is going to |
---|
2082 | // export to these. |
---|
2083 | std::string system_h_name = directory + "/__libcdl_file1"; |
---|
2084 | Tcl_Channel system_h = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), |
---|
2085 | const_cast<char*>(system_h_name.c_str()), "w", 0666); |
---|
2086 | if (0 == system_h) { |
---|
2087 | throw CdlInputOutputException("Unable to open file " + system_h_name + "\n" + |
---|
2088 | interp->get_result()); |
---|
2089 | } |
---|
2090 | // The channel will be registered and unregistered in several |
---|
2091 | // different interpreters. This call prevents the channel from |
---|
2092 | // disappearing prematurely. |
---|
2093 | Tcl_RegisterChannel(0, system_h); |
---|
2094 | |
---|
2095 | // Make sure that this operation is undone if necessary. |
---|
2096 | try { |
---|
2097 | // Now fill in system.h with the appropriate data. Start with the banner. |
---|
2098 | char local_buf[512]; |
---|
2099 | sprintf(local_buf, banner_format, "SYSTEM_H", "SYSTEM_H", "system.h"); |
---|
2100 | Tcl_Write(system_h, local_buf, -1); |
---|
2101 | |
---|
2102 | // Add generic version information |
---|
2103 | system_h_add_version_header(system_h); |
---|
2104 | |
---|
2105 | // The rest of system.h will be filled in by the following loop. |
---|
2106 | // |
---|
2107 | // Walk down the previously constructed headers vector, create |
---|
2108 | // appropriate files, and let each DefineLoadable fill in the |
---|
2109 | // file for itself. |
---|
2110 | std::vector<std::pair<CdlDefineLoadable, std::string> >::iterator outer_i; |
---|
2111 | std::vector<std::pair<CdlDefineLoadable, std::string> >::iterator inner_i; |
---|
2112 | for (outer_i = headers.begin(); outer_i != headers.end(); outer_i++) { |
---|
2113 | if ("" == outer_i->second) { |
---|
2114 | continue; |
---|
2115 | } |
---|
2116 | std::string target_name = outer_i->second; |
---|
2117 | std::string header_name = directory + "/__libcdl_file2"; |
---|
2118 | Tcl_Channel header_h = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), |
---|
2119 | const_cast<char*>(header_name.c_str()), "w", 0666); |
---|
2120 | if (0 == header_h) { |
---|
2121 | throw CdlInputOutputException("Unable to open file " + header_name + "\n" + |
---|
2122 | interp->get_result()); |
---|
2123 | } |
---|
2124 | // The channel may be used in several different interpreters, so |
---|
2125 | // do an extra register operation |
---|
2126 | Tcl_RegisterChannel(0, header_h); |
---|
2127 | |
---|
2128 | try { |
---|
2129 | // Output the banner. This requires an all-upper-case version of the |
---|
2130 | // header name. |
---|
2131 | std::string upper_case; |
---|
2132 | for (unsigned int i = 0; i < target_name.size(); i++) { |
---|
2133 | if (islower(target_name[i])) { |
---|
2134 | upper_case += toupper(target_name[i]); |
---|
2135 | } else if ('.' == target_name[i]) { |
---|
2136 | upper_case += '_'; |
---|
2137 | } else { |
---|
2138 | upper_case += target_name[i]; |
---|
2139 | } |
---|
2140 | } |
---|
2141 | sprintf(local_buf, banner_format, upper_case.c_str(), upper_case.c_str(), target_name.c_str()); |
---|
2142 | Tcl_Write(header_h, local_buf, -1); |
---|
2143 | |
---|
2144 | // Now iterate over all the loadables looking for ones which |
---|
2145 | // should generate #define's for this header, and invoke the |
---|
2146 | // appropriate member function. |
---|
2147 | for (inner_i = outer_i; inner_i != headers.end(); inner_i++) { |
---|
2148 | if (inner_i->second == target_name) { |
---|
2149 | inner_i->first->generate_config_header(header_h, system_h); |
---|
2150 | inner_i->second = ""; |
---|
2151 | } |
---|
2152 | } |
---|
2153 | |
---|
2154 | // The header file has now been updated. Close it and decide whether |
---|
2155 | // or not to replace the old version |
---|
2156 | Tcl_Write(header_h, "\n#endif\n", -1); |
---|
2157 | } catch(...) { |
---|
2158 | Tcl_UnregisterChannel(0, header_h); |
---|
2159 | throw; |
---|
2160 | } |
---|
2161 | Tcl_UnregisterChannel(0, header_h); |
---|
2162 | compare_and_copy(interp, header_name, directory + "/" + target_name); |
---|
2163 | } |
---|
2164 | |
---|
2165 | Tcl_Write(system_h, "\n#endif\n", -1); |
---|
2166 | } catch(...) { |
---|
2167 | Tcl_UnregisterChannel(0, system_h); |
---|
2168 | throw; |
---|
2169 | } |
---|
2170 | |
---|
2171 | // This call to UnregisterChannel automatically closes the |
---|
2172 | // channel, there is no need for an explicit Tcl_Close() call. |
---|
2173 | Tcl_UnregisterChannel(0, system_h); |
---|
2174 | #ifdef _WIN32 |
---|
2175 | Tcl_UnregisterChannel(0, stderr_chan); |
---|
2176 | Tcl_UnregisterChannel(0, stdout_chan); |
---|
2177 | Tcl_UnregisterChannel(0, stdin_chan); |
---|
2178 | #endif |
---|
2179 | compare_and_copy(interp, system_h_name, directory +"/system.h"); |
---|
2180 | } |
---|
2181 | |
---|
2182 | //}}} |
---|
2183 | //{{{ CdlToplevel::get_config_headers() |
---|
2184 | |
---|
2185 | // ---------------------------------------------------------------------------- |
---|
2186 | // Return details of the header files that should be generated. This |
---|
2187 | // allows higher-level code to detect files that should no longer |
---|
2188 | // be present, amongst other uses. |
---|
2189 | // |
---|
2190 | // The main complication is that some packages may wish to share the |
---|
2191 | // same header file, especially hardware packages. |
---|
2192 | |
---|
2193 | void |
---|
2194 | CdlToplevelBody::get_config_headers(std::vector<std::string>& headers) |
---|
2195 | { |
---|
2196 | CYG_REPORT_FUNCNAME("CdlToplevelBody::get_config_headers"); |
---|
2197 | CYG_REPORT_FUNCARG2XV(this, &headers); |
---|
2198 | CYG_PRECONDITION_THISC(); |
---|
2199 | |
---|
2200 | // Allow the vector argument to be re-used in multiple calls. |
---|
2201 | // Strictly speaking this is better done at the application |
---|
2202 | // level, but the behaviour is consistent with get_build_info(); |
---|
2203 | headers.clear(); |
---|
2204 | |
---|
2205 | // There will always be a system.h header file with details |
---|
2206 | // of the loadables. |
---|
2207 | // FIXME: the name of this file should probably be controllable |
---|
2208 | headers.push_back("system.h"); |
---|
2209 | |
---|
2210 | // Now check each loadable and adds its header file, assuming |
---|
2211 | // this is unique. |
---|
2212 | const std::vector<CdlLoadable>& loadables = get_loadables(); |
---|
2213 | std::vector<CdlLoadable>::const_iterator i; |
---|
2214 | for (i = loadables.begin(); i != loadables.end(); i++) { |
---|
2215 | CdlDefineLoadable current = dynamic_cast<CdlDefineLoadable>(*i); |
---|
2216 | if (0 != current) { |
---|
2217 | std::string its_file = current->get_config_header(); |
---|
2218 | CYG_LOOP_INVARIANTC("" != its_file); |
---|
2219 | if (std::find(headers.begin(), headers.end(), its_file) == headers.end()) { |
---|
2220 | headers.push_back(its_file); |
---|
2221 | } |
---|
2222 | } |
---|
2223 | } |
---|
2224 | |
---|
2225 | CYG_REPORT_RETURN(); |
---|
2226 | } |
---|
2227 | |
---|
2228 | //}}} |
---|
2229 | //{{{ CdlToplevel::generate_build_tree() |
---|
2230 | |
---|
2231 | void |
---|
2232 | CdlToplevelBody::generate_build_tree(std::string build_tree, std::string install_tree) |
---|
2233 | { |
---|
2234 | } |
---|
2235 | |
---|
2236 | //}}} |
---|
2237 | |
---|
2238 | //}}} |
---|