3 //==========================================================================
7 // libcdl support for building and for header file generation
9 //==========================================================================
10 //####COPYRIGHTBEGIN####
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 2002, 2003 Bart Veer
14 // Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
16 // This file is part of the eCos host tools.
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)
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
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.
32 // ----------------------------------------------------------------------------
34 //####COPYRIGHTEND####
35 //==========================================================================
36 //#####DESCRIPTIONBEGIN####
39 // Contributors: bartv
42 //####DESCRIPTIONEND####
43 //==========================================================================
48 // ----------------------------------------------------------------------------
50 #include "cdlconfig.h"
52 // Get the infrastructure types, assertions, tracing and similar
54 #include <cyg/infra/cyg_ass.h>
55 #include <cyg/infra/cyg_trac.h>
57 // <cdl.hxx> defines everything implemented in this module.
58 // It implicitly supplies <string>, <vector> and <map> because
59 // the class definitions rely on these headers.
60 #include <cdlcore.hxx>
66 // ----------------------------------------------------------------------------
67 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlBuildLoadableBody);
68 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlBuildableBody);
69 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlDefineLoadableBody);
70 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlDefinableBody);
73 //{{{ CdlBuildableBody
77 // ----------------------------------------------------------------------------
78 // There is little data specific to a buildable. The only distinguishing
79 // feature is the set of properties that are supported, plus a handful
80 // of functions to extract that information.
82 CdlBuildableBody::CdlBuildableBody()
84 CYG_REPORT_FUNCNAME("CdlBuildable:: default constructor");
85 CYG_REPORT_FUNCARG1XV(this);
87 // There is no data to initialize yet
88 cdlbuildablebody_cookie = CdlBuildableBody_Magic;
89 CYGDBG_MEMLEAK_CONSTRUCTOR();
91 CYG_POSTCONDITION_THISC();
95 CdlBuildableBody::~CdlBuildableBody()
97 CYG_REPORT_FUNCNAME("CdlBuildable:: destructor");
98 CYG_REPORT_FUNCARG1XV(this);
99 CYG_PRECONDITION_THISC();
101 cdlbuildablebody_cookie = CdlBuildableBody_Invalid;
102 CYGDBG_MEMLEAK_DESTRUCTOR();
107 // ----------------------------------------------------------------------------
110 CdlBuildableBody::get_class_name() const
112 CYG_REPORT_FUNCNAME("CdlBuildable::get_class_name");
113 CYG_PRECONDITION_THISC();
118 // ----------------------------------------------------------------------------
121 CdlBuildableBody::check_this(cyg_assert_class_zeal zeal) const
123 if (CdlBuildableBody_Magic != cdlbuildablebody_cookie) {
126 CYGDBG_MEMLEAK_CHECKTHIS();
127 return CdlNodeBody::check_this(zeal);
131 //{{{ Add and check property parsers
133 // ----------------------------------------------------------------------------
136 CdlBuildableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers)
138 CYG_REPORT_FUNCNAME("CdlBuildable::add_property_parsers");
140 static CdlInterpreterCommandEntry commands[] =
142 CdlInterpreterCommandEntry("compile", &CdlBuildableBody::parse_compile ),
143 CdlInterpreterCommandEntry("object", &CdlBuildableBody::parse_object ),
144 CdlInterpreterCommandEntry("make_object", &CdlBuildableBody::parse_make_object),
145 CdlInterpreterCommandEntry("make", &CdlBuildableBody::parse_make ),
146 CdlInterpreterCommandEntry("build_proc", &CdlBuildableBody::parse_build_proc ),
147 CdlInterpreterCommandEntry("", 0 ),
150 for (int i = 0; commands[i].command != 0; i++) {
151 std::vector<CdlInterpreterCommandEntry>::const_iterator j;
152 for (j = parsers.begin(); j != parsers.end(); j++) {
153 if (commands[i].name == j->name) {
154 if (commands[i].command != j->command) {
155 CYG_FAIL("Property names are being re-used");
160 if (j == parsers.end()) {
161 parsers.push_back(commands[i]);
164 CdlNodeBody::add_property_parsers(parsers);
170 CdlBuildableBody::check_properties(CdlInterpreter interp)
172 CYG_REPORT_FUNCNAME("CdlBuildable::check_properties");
173 CYG_REPORT_FUNCARG2XV(this, interp);
174 CYG_PRECONDITION_THISC();
175 CYG_PRECONDITION_CLASSC(interp);
177 // There are no real constraints on the number of compile
179 // TODO: check that the relevant sources files exist,
180 // unless marked appropriately (build_proc can create
181 // new source files).
183 CdlNodeBody::check_properties(interp);
189 //{{{ Property parsers
191 // ----------------------------------------------------------------------------
192 // Syntax: compile <file1 file2 ...>
194 // There are a couple of checks that could be performed here:
196 // 1) does each listed file actually exist? Unfortunately that approach
197 // falls foul of build_proc, which is allowed to generate source files
200 // 2) does the file have a recognised suffix such as .c or .cxx. This
201 // relies libcdl having some way of knowing how to treat different
204 // For now there are no validity checks.
206 // A future extension may allow dependencies to be listed, as an
207 // option. This would allow component vendors to specify that
208 // particular custom build steps should happen before particular
209 // compilations, a more robust approach than the current priority
213 CdlBuildableBody::parse_compile(CdlInterpreter interp, int argc, const char* argv[])
215 CYG_REPORT_FUNCNAMETYPE("parse_compile", "result %d");
216 static char* options[] = {
221 int result = CdlParse::parse_stringvector_property(interp, argc, argv, CdlPropertyId_Compile, options, 0, true);
223 CYG_REPORT_RETVAL(result);
227 // ----------------------------------------------------------------------------
228 // A utility to break a custom build step down into its three components.
230 // A custom build step takes the form:
234 // This utility function takes a single string of this form and breaks
235 // it down into its constituent parts.
237 // NOTE: this will need lots of extra code in future to allow for
238 // escaped characters, spaces in filenames, etc. For now just keep
242 CdlBuildableBody::split_custom_build_step(std::string str_data, std::string& target, std::string& deps, std::string& rules,
243 std::string& error_msg)
245 CYG_REPORT_FUNCNAMETYPE("CdlBuildable::split_custom_build_step", "result %d");
252 const char* data = str_data.c_str();
254 // Skip any leading white space, and make sure that this leaves some real data.
255 while (('\0' != *data) && isspace(*data)) {
259 error_msg = "no data in custom build_step";
260 CYG_REPORT_RETVAL(false);
264 // Now extract the target. This consists of any sequence of characters
265 // upto space, tab, colon.
266 for ( ; ('\0' != *data) && (':' != *data) && (' ' != *data) && ('\t' != *data); data++) {
269 // Discard any spaces or tabs, they are of no interest
270 while ((' ' == *data) || ('\t' == *data)) {
273 // The current character should be a colon
275 error_msg = "expecting a colon `;' after the target `" + target + "'";
276 CYG_REPORT_RETVAL(false);
280 // Move past the colon, and skip any further spaces or tabs
282 while (('\0' != *data) && ((' ' == *data) || ('\t' == *data))) {
286 // Everything from here until the end of line should be part of the deps field,
287 // including white space.
288 while (('\0' != *data) && ('\n' != *data) && (';' != *data)) {
293 error_msg = "expecting dependency list after `" + target + ":'";
294 CYG_REPORT_RETVAL(false);
298 // Having some rules is compulsory.
300 error_msg = "expecting one or more rules after the dependency list";
301 CYG_REPORT_RETVAL(false);
304 // We are currently at \n or ;, move on to the actual rules
308 // Rules consist of one or more lines. Any leading white space on a given
309 // line should be discarded.
310 while ('\0' != *data) {
311 // Processing the current rule. Skip leading spaces and tabs
312 while ((' ' == *data) || ('\t' == *data)) {
315 // Now add everything up to the next newline or EOD to the rules.
316 while (('\0' != *data) && ('\n' != *data)) {
320 // Terminate this line of the rules with a newline, even if that
321 // character is absent from the raw data.
324 // And ignore the newline in the raw data itself
330 // Better make sure that there are some rules. All of the looping above
331 // may just have left white space
333 error_msg = "no rules provided";
334 CYG_REPORT_RETVAL(false);
340 CYG_REPORT_RETVAL(true);
345 // ----------------------------------------------------------------------------
346 // syntax: make <target> <rules>
348 // There is rather a lot of checking to be done.
350 // 1) the priority should be valid. In particular it should be a number
351 // within a reasonable range.
353 // 2) the rules should take the form:
354 // <target> : <deps> ;|\n rules
356 // Where the target should be a single file, identical to the
357 // first property argument.
360 parse_make_final_check(CdlInterpreter interp, CdlProperty_String prop)
362 CYG_REPORT_FUNCNAME("parse_make_final_check");
363 CYG_PRECONDITION_CLASSC(interp);
364 CYG_PRECONDITION_CLASSC(prop);
366 std::string prio_string = prop->get_option("priority");
367 if ("" != prio_string) {
369 if (!Cdl::string_to_integer(prio_string, tmp)) {
370 CdlParse::report_property_parse_error(interp, prop,
371 "Invalid priority option, priorities should be simple numbers.");
373 if ((tmp < 1) || (tmp > 1024)) {
374 CdlParse::report_property_parse_error(interp, prop,
375 "Invalid priority value, priorities should be in the range 1 to 1024.");
380 std::string data = prop->get_string();
384 std::string error_msg;
386 if (!CdlBuildableBody::split_custom_build_step(data, target, deps, rules, error_msg)) {
387 CdlParse::report_property_parse_error(interp, prop, "Invalid custom build step, " + error_msg);
392 CdlBuildableBody::parse_make(CdlInterpreter interp, int argc, const char* argv[])
394 CYG_REPORT_FUNCNAMETYPE("parse_make", "result %d");
395 static char* options[] = {
400 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Make, options, &parse_make_final_check);
402 CYG_REPORT_RETVAL(result);
407 // ----------------------------------------------------------------------------
408 // syntax: make_object <target> <rules>
410 // The rules here are much the same as for the "make" property.
413 parse_make_object_final_check(CdlInterpreter interp, CdlProperty_String prop)
415 CYG_REPORT_FUNCNAME("parse_make_object_final_check");
416 CYG_PRECONDITION_CLASSC(interp);
417 CYG_PRECONDITION_CLASSC(prop);
420 std::string prio_string = prop->get_option("priority");
421 if ("" != prio_string) {
423 if (!Cdl::string_to_integer(prio_string, tmp)) {
424 CdlParse::report_property_parse_error(interp, prop,
425 "Invalid priority option, priorities should be simple numbers.");
427 if ((tmp < 1) || (tmp > 1024)) {
428 CdlParse::report_property_parse_error(interp, prop,
429 "Invalid priority value, priorities should be in the range 1 to 1024.");
434 std::string data = prop->get_string();
438 std::string error_msg;
440 if (!CdlBuildableBody::split_custom_build_step(data, target, deps, rules, error_msg)) {
441 CdlParse::report_property_parse_error(interp, prop, "Invalid custom build step, " + error_msg);
446 CdlBuildableBody::parse_make_object(CdlInterpreter interp, int argc, const char* argv[])
448 CYG_REPORT_FUNCNAMETYPE("parse_make_object", "result %d");
449 static char* options[] = {
455 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_MakeObject, options,
456 &parse_make_object_final_check);
458 CYG_REPORT_RETVAL(result);
463 // ----------------------------------------------------------------------------
464 // Syntax: object <file1> <file2> ...
467 CdlBuildableBody::parse_object(CdlInterpreter interp, int argc, const char* argv[])
469 CYG_REPORT_FUNCNAMETYPE("parse_object", "result %d");
470 static char* options[] = {
475 int result = CdlParse::parse_stringvector_property(interp, argc, argv, CdlPropertyId_Object, options, 0, true);
477 CYG_REPORT_RETVAL(result);
481 // ----------------------------------------------------------------------------
482 // Syntax: build_proc { tcl code }
485 CdlBuildableBody::parse_build_proc(CdlInterpreter interp, int argc, const char* argv[])
487 CYG_REPORT_FUNCNAMETYPE("parse_build_proc", "result %d");
489 int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_BuildProc, 0, 0);
491 CYG_REPORT_RETVAL(result);
496 //{{{ update_build_info()
498 // ----------------------------------------------------------------------------
499 // Most of the work is done in update_all_build_info(). The update_build_info()
500 // merely checks the active and enabled state first.
502 CdlBuildableBody::update_build_info(CdlBuildInfo_Loadable& build_info, std::string library) const
504 CYG_REPORT_FUNCNAME("CdlBuildable::update_build_info");
505 CYG_REPORT_FUNCARG2XV(this, &build_info);
506 CYG_PRECONDITION_THISC();
507 CYG_PRECONDITIONC("" != library);
514 CdlConstValuable valuable = dynamic_cast<CdlConstValuable>(this);
516 if (!valuable->is_enabled()) {
522 update_all_build_info(build_info, library);
528 //{{{ update_all_build_info()
530 // ----------------------------------------------------------------------------
531 // There are four properties to be considered, each of which may occur
532 // multiple times: "compile", "object", "make_object", and "make".
533 // Each of these will result in separate additions to the build_info
537 CdlBuildableBody::update_all_build_info(CdlBuildInfo_Loadable& build_info, std::string package_library) const
539 CYG_REPORT_FUNCNAME("CdlBuildable::update_all_build_info");
540 CYG_REPORT_FUNCARG2XV(this, &build_info);
541 CYG_PRECONDITION_THISC();
542 CYG_PRECONDITIONC("" != package_library);
544 // Get some information about the owning loadable first.
545 CdlLoadable loadable = get_owner();
546 CYG_ASSERT_CLASSC(loadable);
547 std::string directory = loadable->get_directory();
548 CYG_ASSERTC("" != directory);
549 CdlInterpreter interp = loadable->get_interpreter();
550 CYG_ASSERT_CLASSC(interp);
552 // The interpreter needs some information about the locations
553 // of various things. This code has to be kept in step with
554 // CdlLoadable::find_relative_file()
555 interp->set_variable("::cdl_topdir", get_toplevel()->get_directory());
556 interp->set_variable("::cdl_pkgdir", directory);
558 // For many packages the sources will reside in a src subdirectory.
559 // For simple packages the sources may live directly at the toplevel
560 bool has_src_subdir = loadable->has_subdirectory("src");
562 // NOTE: the object property is not yet supported
563 std::vector<CdlProperty> compile_properties;
564 get_properties(CdlPropertyId_Compile, compile_properties);
565 std::vector<CdlProperty> makeobject_properties;
566 get_properties(CdlPropertyId_MakeObject, makeobject_properties);
567 std::vector<CdlProperty> make_properties;
568 get_properties(CdlPropertyId_Make, make_properties);
569 std::vector<CdlProperty>::const_iterator prop_i;
571 for (prop_i = compile_properties.begin(); prop_i != compile_properties.end(); prop_i++) {
572 CdlProperty_StringVector compile_prop = dynamic_cast<CdlProperty_StringVector>(*prop_i);
573 CYG_LOOP_INVARIANT_CLASSC(compile_prop);
575 // Does this property have a library option?
576 std::string current_library = compile_prop->get_option("library");
577 if ("" == current_library) {
578 current_library = package_library;
581 const std::vector<std::string>& files = compile_prop->get_strings();
582 std::vector<std::string>::const_iterator file_i;
584 for (file_i = files.begin(); file_i != files.end(); file_i++) {
586 // For each listed file, try to find it. If this is unsuccessful
587 // then assume that the file will be generated later on.
588 std::string path = loadable->find_relative_file(*file_i, "src");
590 if (has_src_subdir) {
591 path = "src/" + *file_i;
597 // Now check whether or not the specified file is already present.
598 std::vector<CdlBuildInfo_Compile>::const_iterator info_i;
599 for (info_i = build_info.compiles.begin(); info_i != build_info.compiles.end(); info_i++) {
600 if ((current_library == info_i->library) && (path == info_i->source)) {
604 if (info_i == build_info.compiles.end()) {
605 CdlBuildInfo_Compile new_info;
606 new_info.library = current_library;
607 new_info.source = path;
608 build_info.compiles.push_back(new_info);
613 for (prop_i = makeobject_properties.begin(); prop_i != makeobject_properties.end(); prop_i++) {
614 CdlProperty_String prop = dynamic_cast<CdlProperty_String>(*prop_i);
615 CYG_LOOP_INVARIANT_CLASSC(prop);
617 // Does thie property have a library option?
618 std::string current_library = prop->get_option("library");
619 if ("" == current_library) {
620 current_library = package_library;
623 // How about a priority field? The default priority for make_object is 100
624 // We can rely on the validation done during the parsing process
625 cdl_int priority = 100;
626 std::string priority_option = prop->get_option("priority");
627 if ("" != priority_option) {
628 Cdl::string_to_integer(priority_option, priority);
631 // What we need now is the separate target, deps, and rules. These
632 // can be obtained via a utility. The raw data will have been validated
634 std::string raw_data = prop->get_string();
638 std::string error_msg;
641 result = CdlBuildableBody::split_custom_build_step(raw_data, target, deps, rules, error_msg);
642 CYG_ASSERTC(true == result);
644 // Construct a local object, then copy it into the vector
645 CdlBuildInfo_MakeObject local_copy;
646 local_copy.priority = priority;
647 local_copy.library = current_library;
648 local_copy.object = target;
649 local_copy.deps = deps;
650 local_copy.rules = rules;
652 build_info.make_objects.push_back(local_copy);
655 for (prop_i = make_properties.begin(); prop_i != make_properties.end(); prop_i++) {
656 CdlProperty_String prop = dynamic_cast<CdlProperty_String>(*prop_i);
657 CYG_LOOP_INVARIANT_CLASSC(prop);
659 // Is there a priority field? The default priority for make is
660 // 300 We can rely on the validation done during the parsing
662 cdl_int priority = 300;
663 std::string priority_option = prop->get_option("priority");
664 if ("" != priority_option) {
665 Cdl::string_to_integer(priority_option, priority);
668 // What we need now is the separate target, deps, and rules. These
669 // can be obtained via a utility. The raw data will have been validated
671 std::string raw_data = prop->get_string();
675 std::string error_msg;
678 result = CdlBuildableBody::split_custom_build_step(raw_data, target, deps, rules, error_msg);
679 CYG_ASSERTC(true == result);
681 // Construct a local object, then copy it into the vector
682 CdlBuildInfo_Make local_copy;
683 local_copy.priority = priority;
684 local_copy.target = target;
685 local_copy.deps = deps;
686 local_copy.rules = rules;
688 build_info.makes.push_back(local_copy);
697 //{{{ CdlBuildLoadableBody
699 //{{{ Class variables
701 // ----------------------------------------------------------------------------
702 // This variable controls the default library that should be generated.
703 // Some applications may wish to override this.
704 char* CdlBuildLoadableBody::default_library_name = "libtarget.a";
706 // The pattern that should be used to identify header files.
707 // FIXME: this information should come out of a data file
708 char* CdlBuildLoadableBody::default_headers_glob_pattern = "*.h *.hxx *.inl *.si *.inc";
711 //{{{ The simple stuff
713 // ----------------------------------------------------------------------------
715 CdlBuildLoadableBody::CdlBuildLoadableBody()
718 CYG_REPORT_FUNCNAME("CdlBuildLoadable:: default constructor");
719 CYG_REPORT_FUNCARG1XV(this);
721 // There is no data to initialize
722 cdlbuildloadablebody_cookie = CdlBuildLoadableBody_Magic;
723 CYGDBG_MEMLEAK_CONSTRUCTOR();
725 CYG_POSTCONDITION_THISC();
729 CdlBuildLoadableBody::~CdlBuildLoadableBody()
731 CYG_REPORT_FUNCNAME("CdlBuildLoadable:: destructor");
732 CYG_REPORT_FUNCARG1XV(this);
733 CYG_PRECONDITION_THISC();
735 cdlbuildloadablebody_cookie = CdlBuildLoadableBody_Invalid;
736 CYGDBG_MEMLEAK_DESTRUCTOR();
741 // ----------------------------------------------------------------------------
744 CdlBuildLoadableBody::get_class_name() const
746 CYG_REPORT_FUNCNAME("CdlBuildLoadable::get_class_name");
747 CYG_PRECONDITION_THISC();
749 return "build_loadable";
752 // ----------------------------------------------------------------------------
755 CdlBuildLoadableBody::check_this(cyg_assert_class_zeal zeal) const
757 if (CdlBuildLoadableBody_Magic != cdlbuildloadablebody_cookie) {
760 CYGDBG_MEMLEAK_CHECKTHIS();
761 return CdlContainerBody::check_this(zeal) && CdlNodeBody::check_this(zeal);
765 //{{{ Property parsers
767 // ----------------------------------------------------------------------------
770 CdlBuildLoadableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers)
772 CYG_REPORT_FUNCNAME("CdlBuildLoadable::add_property_parsers");
774 static CdlInterpreterCommandEntry commands[] =
776 CdlInterpreterCommandEntry("library", &CdlBuildLoadableBody::parse_library ),
777 CdlInterpreterCommandEntry("makefile", &CdlBuildLoadableBody::parse_makefile ),
778 CdlInterpreterCommandEntry("include_dir", &CdlBuildLoadableBody::parse_include_dir ),
779 CdlInterpreterCommandEntry("include_files", &CdlBuildLoadableBody::parse_include_files ),
780 CdlInterpreterCommandEntry("", 0 )
783 for (int i = 0; commands[i].command != 0; i++) {
784 std::vector<CdlInterpreterCommandEntry>::const_iterator j;
785 for (j = parsers.begin(); j != parsers.end(); j++) {
786 if (commands[i].name == j->name) {
787 if (commands[i].command != j->command) {
788 CYG_FAIL("Property names are being re-used");
793 if (j == parsers.end()) {
794 parsers.push_back(commands[i]);
802 CdlBuildLoadableBody::check_properties(CdlInterpreter interp)
804 CYG_REPORT_FUNCNAME("CdlBuildLoadable::check_properties");
805 CYG_REPORT_FUNCARG2XV(this, interp);
806 CYG_PRECONDITION_THISC();
807 CYG_PRECONDITION_CLASSC(interp);
809 CdlNodeBody::check_properties(interp);
814 // ----------------------------------------------------------------------------
815 // syntax: library <filename>
817 // NOTE: there should probably be a check that the library name is in
818 // a valid format, i.e. libxxx.a
821 CdlBuildLoadableBody::parse_library(CdlInterpreter interp, int argc, const char* argv[])
823 CYG_REPORT_FUNCNAMETYPE("parse_library", "result %d");
825 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Library, 0, 0);
827 CYG_REPORT_RETVAL(result);
831 // ----------------------------------------------------------------------------
832 // syntax: makefile <filename>
834 // NOTE: possibly there should be a check that the makefile exists.
835 // Do we want to allow build_proc's to generate makefiles?
837 CdlBuildLoadableBody::parse_makefile(CdlInterpreter interp, int argc, const char* argv[])
839 CYG_REPORT_FUNCNAMETYPE("parse_makefile", "result %d");
841 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Makefile, 0, 0);
843 CYG_REPORT_RETVAL(result);
847 // ----------------------------------------------------------------------------
848 // syntax: include_dir <directory name>
850 CdlBuildLoadableBody::parse_include_dir(CdlInterpreter interp, int argc, const char* argv[])
852 CYG_REPORT_FUNCNAMETYPE("parse_include_dir", "result %d");
854 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_IncludeDir, 0, 0);
856 CYG_REPORT_RETVAL(result);
860 // ----------------------------------------------------------------------------
861 // Syntax: include_files <file1 file2 ...>
863 // This lists the header files that should be copied into the install tree
864 // as part of the build operation. In the absence of an include_files property
865 // there should be an include subdirectory, and all files in that subdirectory
866 // are assumed to be exportable headers.
868 // NOTE: add a finalizer to check that the files exist or get created.
871 CdlBuildLoadableBody::parse_include_files(CdlInterpreter interp, int argc, const char* argv[])
873 CYG_REPORT_FUNCNAMETYPE("parse_include_files", "result %d");
875 int result = CdlParse::parse_stringvector_property(interp, argc, argv, CdlPropertyId_IncludeFiles, 0, 0, true);
877 CYG_REPORT_RETVAL(result);
882 //{{{ update_build_info()
884 // ----------------------------------------------------------------------------
885 // This utility routine takes care of filling in a Buildinfo_Loadable
886 // structure with the appropriate header file information. This involves
889 // 1) there may be an include_dir property. This affects the destination
890 // of any header files that are listed.
892 // 2) the loadable may or may not have an include subdirectory. For
893 // non-trivial packages the include subdirectory provides a clean
894 // way of separating interface and implementation. For simple
895 // packages it is too heavyweight.
897 // 3) there may be one or more include_files property. If so then these
898 // specify all the files that should be exported.
900 // 4) otherwise if there is an include subdirectory then we need to
901 // know all the header files in that subdirectory. A Tcl script is
904 // 5) otherwise all the header files below the package directory itself
908 update_header_file_info(CdlConstBuildLoadable loadable, CdlBuildInfo_Loadable& build_info)
910 CYG_REPORT_FUNCNAME("update_header_file_info");
911 CYG_REPORT_FUNCARG2XV(loadable, &build_info);
912 CYG_PRECONDITION_CLASSC(loadable);
914 std::string dest_dir = "";
915 CdlProperty include_dir_prop = loadable->get_property(CdlPropertyId_IncludeDir);
916 if (0 != include_dir_prop) {
917 CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(include_dir_prop);
918 CYG_ASSERT_CLASSC(strprop);
919 dest_dir = strprop->get_string();
922 bool has_include_subdir = loadable->has_subdirectory("include");
924 std::vector<CdlProperty> include_file_properties;
925 loadable->get_properties(CdlPropertyId_IncludeFiles, include_file_properties);
926 if (include_file_properties.size() > 0) {
927 std::vector<CdlProperty>::const_iterator prop_i;
928 for (prop_i = include_file_properties.begin(); prop_i != include_file_properties.end(); prop_i++) {
930 CdlProperty_StringVector strvprop = dynamic_cast<CdlProperty_StringVector>(*prop_i);
931 CYG_ASSERT_CLASSC(strvprop);
933 const std::vector<std::string>& filenames = strvprop->get_strings();
934 std::vector<std::string>::const_iterator file_i;
935 for (file_i = filenames.begin(); file_i != filenames.end(); file_i++) {
936 std::string path = loadable->find_relative_file(*file_i, "include");
937 // Assume that the header file will be generated by a build_proc
939 if (has_include_subdir) {
940 path = "include/" + *file_i;
945 CdlBuildInfo_Header local_copy;
946 local_copy.source = path;
947 local_copy.destination = "";
948 if ("" != dest_dir) {
949 local_copy.destination = dest_dir + "/";
951 // At this stage "path" may begin with "include/", which should not
952 // be present in the destination.
953 const char* tmp = path.c_str();
954 if (0 == strncmp("include/", tmp, 8)) {
955 local_copy.destination += &(tmp[8]);
957 local_copy.destination += path;
959 build_info.headers.push_back(local_copy);
966 // It is necessary to search for the appropriate files.
967 CdlInterpreter interp = loadable->get_interpreter();
968 std::string path = loadable->get_toplevel()->get_directory() + "/" + loadable->get_directory();
969 if (has_include_subdir) {
970 std::vector<std::string> files;
971 std::vector<std::string>::const_iterator file_i;
972 interp->locate_all_files(path + "/include", files);
973 for (file_i = files.begin(); file_i != files.end(); file_i++) {
974 // NOTE: for now discard any header files in the pkgconf subdirectory
975 if (0 == strncmp("pkgconf/", file_i->c_str(), 8)) {
978 if ('~' == *(file_i->rbegin())) {
981 CdlBuildInfo_Header local_copy;
982 local_copy.source = "include/" + *file_i;
983 local_copy.destination = "";
984 if ("" != dest_dir) {
985 local_copy.destination = dest_dir + "/";
987 local_copy.destination += *file_i;
988 build_info.headers.push_back(local_copy);
991 // Look for all header files, which for now means files with
992 // a .h, .hxx, .inl or .inc extension.
993 // FIXME: the definition of what constitutes a header file
994 // should not be hard-wired here.
995 std::vector<std::string> files;
996 std::vector<std::string>::const_iterator file_i;
997 interp->locate_all_files(path, files);
998 for (file_i = files.begin(); file_i != files.end(); file_i++) {
1000 // Problems with libstdc++ versions, use C comparisons instead.
1001 const char* c_string = file_i->c_str();
1002 unsigned int len = strlen(c_string);
1003 if (((len >= 2) && (0 == strncmp(c_string + len - 2, ".h", 2))) ||
1004 ((len >= 4) && (0 == strncmp(c_string + len - 4, ".hxx", 4))) ||
1005 ((len >= 4) && (0 == strncmp(c_string + len - 4, ".inl", 4))) ||
1006 ((len >= 4) && (0 == strncmp(c_string + len - 4, ".inc", 4)))) {
1008 CdlBuildInfo_Header local_copy;
1009 local_copy.source = *file_i;
1010 local_copy.destination = "";
1011 if ("" != dest_dir) {
1012 local_copy.destination = dest_dir + "/";
1014 local_copy.destination += *file_i;
1015 build_info.headers.push_back(local_copy);
1020 CYG_REPORT_RETURN();
1024 // ----------------------------------------------------------------------------
1025 // Updating a loadable build's info involves two steps. First, there
1026 // is some information associated with the loadable as a whole such as
1027 // header files. Second, each buildable in the loadable (including itself)
1028 // may contain properties such as compile etc. This is all handled via
1029 // a CdlBuildable member function.
1032 CdlBuildLoadableBody::update_build_info(CdlBuildInfo& build_info) const
1034 CYG_REPORT_FUNCNAME("CdlBuildLoadable::update_build_info");
1035 CYG_REPORT_FUNCARG2XV(this, &build_info);
1036 CYG_PRECONDITION_THISC();
1038 // It is not possible to disable a loadable itself: either the
1039 // loadable is present or it is not (although in some cases users
1040 // may be able to change versions). However, because of reparenting
1041 // it is possible for a loadable to be below a disabled container,
1042 // and hence it is still necessary to check whether or not the
1043 // loadable is active.
1045 CYG_REPORT_RETURN();
1049 // Time to add a new CdlBuildInfo_Loadable object to the current
1050 // vector. The name and directory can be filled in straightaway,
1051 // the vectors will all be initialized to empty.
1052 CdlBuildInfo_Loadable tmp_info;
1053 build_info.entries.push_back(tmp_info);
1054 CdlBuildInfo_Loadable& this_info = *(build_info.entries.rbegin());
1055 this_info.name = get_name();
1056 this_info.directory = get_directory();
1058 // Take care of the header files
1059 update_header_file_info(this, this_info);
1061 // Work out the library name appropriate for this loadable.
1062 // There may be a library property, otherwise the global default
1064 std::string loadable_library = default_library_name;
1065 if (has_property(CdlPropertyId_Library)) {
1066 CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_Library));
1067 loadable_library = strprop->get_string();
1070 const std::vector<CdlNode>& contents = get_owned();
1071 std::vector<CdlNode>::const_iterator node_i;
1072 for (node_i = contents.begin(); node_i != contents.end(); node_i++) {
1073 CdlBuildable buildable = dynamic_cast<CdlBuildable>(*node_i);
1074 if (0 != buildable) {
1075 buildable->update_build_info(this_info, loadable_library);
1079 CYG_REPORT_RETURN();
1082 // This is much the same as the above, but there is no test for
1083 // active either at the loadable level or for the individual buildables.
1085 CdlBuildLoadableBody::update_all_build_info(CdlBuildInfo& build_info) const
1087 CYG_REPORT_FUNCNAME("CdlBuildLoadable::update_all_build_info");
1088 CYG_REPORT_FUNCARG2XV(this, &build_info);
1089 CYG_PRECONDITION_THISC();
1091 CdlBuildInfo_Loadable tmp_info;
1092 build_info.entries.push_back(tmp_info);
1093 CdlBuildInfo_Loadable& this_info = *(build_info.entries.rbegin());
1094 this_info.name = get_name();
1095 this_info.directory = get_directory();
1097 std::string loadable_library = default_library_name;
1098 if (has_property(CdlPropertyId_Library)) {
1099 CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_Library));
1100 loadable_library = strprop->get_string();
1103 const std::vector<CdlNode>& contents = get_owned();
1104 std::vector<CdlNode>::const_iterator node_i;
1105 for (node_i = contents.begin(); node_i != contents.end(); node_i++) {
1106 CdlBuildable buildable = dynamic_cast<CdlBuildable>(*node_i);
1107 if (0 != buildable) {
1108 buildable->update_build_info(this_info, loadable_library);
1112 CYG_REPORT_RETURN();
1113 CYG_REPORT_RETURN();
1119 //{{{ Version number #define's
1121 // ----------------------------------------------------------------------------
1122 // Given a package xxxPKG_A_B_C with a version V1_2_3, generate additional
1123 // #define's of the form:
1125 // #define xxxNUM_A_B_C_VERSION_MAJOR 1
1126 // #define xxxNUM_A_B_C_VERSION_MINOR 2
1127 // #define xxxNUM_A_B_C_VERSION_RELEASE 3
1129 // The goal here is to allow application code to cope with API
1130 // changes (which of course should be a rare event but cannot be
1131 // eliminated completely). C preprocessor #if statements are
1132 // essentially limited to numerical values, so there is no easy
1133 // way of coping with V1_2_3 at the preprocessor level. However it
1134 // is possible to cope with VERSION_NUMBER #define's.
1136 // Note that only application code and third party packages are
1139 // These #define's go into system.h, alongside the main definition of
1140 // the package. There seems to be little point in putting them in the
1141 // package's own configuration header.
1143 // There are three problems. First, what should be done for packages
1144 // which do not follow the naming conventions? Given a completely
1145 // random package rather than something like xxxPKG_..., what symbol
1146 // names should be used? Basically, if the package does not follow the
1147 // naming convention then there is no safe way of generating new
1148 // symbols. Any names that are chosen might clash. Of course even for
1149 // packages that do follow the naming convention a clash is still
1150 // possible, just a lot less likely.
1152 // Conclusion: if a package does not follow the naming convention, do
1153 // not generate version #define's for it.
1155 // Second, what happens if a different version numbering scheme is
1156 // used? For example the release number might be absent. Version
1157 // numbering schemes might change between releases, but application
1158 // code may still check the #define's.
1160 // Third and related, what should happen for "current" and anoncvs? Do
1161 // we want to look at what other versions are installed and bump one
1164 // Conclusion: the version #define's always have to be generated,
1165 // even if they are not present in the version string, to allow
1166 // application code to test these symbols anyway. A safe default is
1167 // necessary, and -1 is probably the best bet. For example, if
1168 // the version is bumped from 1.3.287 to 1.4 then the release number
1169 // for the latter is set to -1. Another possible default would be
1170 // 0, but that could cause problems for packages that start counting
1171 // from 0 (not a common practice, but...)
1173 // This leaves the question of what to do about "current". Chances are
1174 // that "current" comes from anoncvs and is always more recent than
1175 // any official release, so when comparing versions "current" should
1176 // always be greater than anything else. This can be achieved by using
1177 // a sufficiently large number for the major version. In practice
1178 // it is cleaner to have another #define to indicate the current
1179 // version, and then define package versions to match, i.e.:
1181 // #define CYGNUM_VERSION_CURRENT 0x7fffff00
1183 // #define xxxNUM_A_B_C_VERSION_MAJOR CYGNUM_VERSION_CURRENT
1184 // #define xxxNUM_A_B_C_VERSION_MINOR -1
1185 // #define xxxNUM_A_B_C_VERSION_RELEASE -1
1187 // All comparisons should now work sensibly. Leaving a little bit
1188 // of slack for VERSION_CURRENT seems like a good precaution.
1191 system_h_add_version_header(Tcl_Channel system_h)
1193 CYG_REPORT_FUNCNAME("system_h_add_version_header");
1194 Tcl_Write(system_h, "#define CYGNUM_VERSION_CURRENT 0x7fffff00\n", -1);
1195 CYG_REPORT_RETURN();
1199 system_h_add_package_versioning(Tcl_Channel system_h, std::string name, std::string value)
1201 CYG_REPORT_FUNCNAME("system_h_add_package_versioning");
1206 // The first thing to check is that the package name can be used
1207 // as the basis for the version symbols.
1210 for (i = 0; i < name.size(); i++) {
1211 if ('_' == name[i]) {
1213 if ((name[i-3] == 'P') && (name[i-2] == 'K') && (name[i-1] == 'G')) {
1220 if (name.size() >= 256) {
1224 CYG_REPORT_RETURN();
1228 strcpy(name_buf, name.c_str());
1230 // Change from xxxPKG to xxxNUM
1231 name_buf[i - 3] = 'N';
1232 name_buf[i - 2] = 'U';
1233 name_buf[i - 1] = 'M';
1235 // Now determine the version strings.
1236 std::string major = "-1";
1237 std::string minor = "-1";
1238 std::string release = "-1";
1239 if ("current" == value) {
1240 major = "CYGNUM_VERSION_CURRENT";
1242 Cdl::split_version_string(value, major, minor, release);
1245 sprintf(line_buf, "#define %s_VERSION_MAJOR %s\n", name_buf, major.c_str());
1246 Tcl_Write(system_h, line_buf, -1);
1247 sprintf(line_buf, "#define %s_VERSION_MINOR %s\n", name_buf, minor.c_str());
1248 Tcl_Write(system_h, line_buf, -1);
1249 sprintf(line_buf, "#define %s_VERSION_RELEASE %s\n", name_buf, release.c_str());
1250 Tcl_Write(system_h, line_buf, -1);
1252 CYG_REPORT_RETURN();
1256 //{{{ CdlDefinableBody
1260 // ----------------------------------------------------------------------------
1262 CdlDefinableBody::CdlDefinableBody()
1264 CYG_REPORT_FUNCNAME("CdlDefinable:: default constructor");
1265 CYG_REPORT_FUNCARG1XV(this);
1267 // There is no data to initialize
1268 cdldefinablebody_cookie = CdlDefinableBody_Magic;
1269 CYGDBG_MEMLEAK_CONSTRUCTOR();
1271 CYG_POSTCONDITION_THISC();
1272 CYG_REPORT_RETURN();
1275 CdlDefinableBody::~CdlDefinableBody()
1277 CYG_REPORT_FUNCNAME("CdlDefinable:: destructor");
1278 CYG_REPORT_FUNCARG1XV(this);
1279 CYG_PRECONDITION_THISC();
1281 cdldefinablebody_cookie = CdlDefinableBody_Invalid;
1282 CYGDBG_MEMLEAK_DESTRUCTOR();
1284 CYG_REPORT_RETURN();
1287 // ----------------------------------------------------------------------------
1290 CdlDefinableBody::get_class_name() const
1292 CYG_REPORT_FUNCNAME("CdlDefinable::get_class_name");
1293 CYG_PRECONDITION_THISC();
1294 CYG_REPORT_RETURN();
1298 // ----------------------------------------------------------------------------
1301 CdlDefinableBody::check_this(cyg_assert_class_zeal zeal) const
1303 if (CdlDefinableBody_Magic != cdldefinablebody_cookie) {
1306 CYGDBG_MEMLEAK_CHECKTHIS();
1307 return CdlNodeBody::check_this(zeal);
1311 //{{{ add_property_parser() and check_properties()
1313 // ----------------------------------------------------------------------------
1316 CdlDefinableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers)
1318 CYG_REPORT_FUNCNAME("CdlDefinable::add_property_parsers");
1320 static CdlInterpreterCommandEntry commands[] =
1322 CdlInterpreterCommandEntry("no_define", &parse_no_define ),
1323 CdlInterpreterCommandEntry("define", &parse_define ),
1324 CdlInterpreterCommandEntry("define_format", &parse_define_format ),
1325 CdlInterpreterCommandEntry("define_proc", &parse_define_proc ),
1326 CdlInterpreterCommandEntry("if_define", &parse_if_define ),
1327 CdlInterpreterCommandEntry("", 0 )
1330 for (int i = 0; commands[i].command != 0; i++) {
1331 std::vector<CdlInterpreterCommandEntry>::const_iterator j;
1332 for (j = parsers.begin(); j != parsers.end(); j++) {
1333 if (commands[i].name == j->name) {
1334 if (commands[i].command != j->command) {
1335 CYG_FAIL("Property names are being re-used");
1340 if (j == parsers.end()) {
1341 parsers.push_back(commands[i]);
1344 CdlNodeBody::add_property_parsers(parsers);
1346 CYG_REPORT_RETURN();
1350 CdlDefinableBody::check_properties(CdlInterpreter interp)
1352 CYG_REPORT_FUNCNAME("CdlDefinable::check_properties");
1353 CYG_REPORT_FUNCARG2XV(this, interp);
1354 CYG_PRECONDITION_THISC();
1355 CYG_PRECONDITION_CLASSC(interp);
1357 // There should be at most one each of no_define and define_format.
1358 if (count_properties(CdlPropertyId_NoDefine) > 1) {
1359 CdlParse::report_error(interp, "", "There should be at most one no_define property.");
1361 if (count_properties(CdlPropertyId_DefineFormat) > 1) {
1362 CdlParse::report_error(interp, "", "There should be at most one define_format property.");
1364 if (has_property(CdlPropertyId_NoDefine) && has_property(CdlPropertyId_DefineFormat)) {
1365 CdlParse::report_error(interp, "", "The no_define and define_format properties are mutually exclusive.");
1367 // FIXME: the define_format property only makes sense for certain
1368 // flavors. However the flavor property may not have been processed yet.
1370 CdlNodeBody::check_properties(interp);
1372 CYG_REPORT_RETURN();
1376 //{{{ Definable properties
1378 // ----------------------------------------------------------------------------
1379 // Syntax: no_define
1381 CdlDefinableBody::parse_no_define(CdlInterpreter interp, int argc, const char* argv[])
1383 CYG_REPORT_FUNCNAMETYPE("parse_no_define", "result %d");
1385 int result = CdlParse::parse_minimal_property(interp, argc, argv, CdlPropertyId_NoDefine, 0, 0);
1387 CYG_REPORT_RETVAL(result);
1391 // ----------------------------------------------------------------------------
1392 // syntax: define <symbol>
1394 // The argument to "define" should be a valid C preprocessor symbol.
1396 parse_define_final_check(CdlInterpreter interp, CdlProperty_String prop)
1398 CYG_REPORT_FUNCNAME("parse_define_final_check");
1399 CYG_PRECONDITION_CLASSC(prop);
1400 CYG_PRECONDITION_CLASSC(interp);
1402 const std::string& str = prop->get_string();
1404 if (!Cdl::is_valid_c_preprocessor_symbol(str)) {
1405 CdlParse::report_property_parse_error(interp, prop, str + " is not a valid C preprocessor symbol");
1408 // There may be a file option. At this stage the only valid filename
1409 // that can be used here is system.h
1410 std::string file_option = prop->get_option("file");
1411 if (("" != file_option) && ("system.h" != file_option)) {
1412 CdlParse::report_property_parse_error(interp, prop, "Invalid -file option " + file_option);
1415 // FIXME: validate the format string
1417 CYG_REPORT_RETURN();
1421 CdlDefinableBody::parse_define(CdlInterpreter interp, int argc, const char* argv[])
1423 CYG_REPORT_FUNCNAMETYPE("parse_define", "result %d");
1425 static char* options[] = {
1430 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Define, options, &parse_define_final_check);
1432 CYG_REPORT_RETVAL(result);
1437 // ----------------------------------------------------------------------------
1438 // syntax: define_format <string>
1440 // FIXME: it is possible to apply some checks to the string, e.g. that there
1441 // is only one conversion operation.
1443 // FIXME: also check that the flavor is sensible, define_format has no effect
1446 // FIXME: enforce mutual exclusion with no_define
1449 CdlDefinableBody::parse_define_format(CdlInterpreter interp, int argc, const char* argv[])
1451 CYG_REPORT_FUNCNAMETYPE("parse_format", "result %d");
1453 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_DefineFormat, 0, 0);
1455 CYG_REPORT_RETVAL(result);
1458 // ----------------------------------------------------------------------------
1459 // syntax: define_proc <tclcode>
1461 CdlDefinableBody::parse_define_proc(CdlInterpreter interp, int argc, const char* argv[])
1463 CYG_REPORT_FUNCNAMETYPE("parse_define_proc", "result %d");
1465 int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_DefineProc, 0, 0);
1467 CYG_REPORT_RETVAL(result);
1471 // ----------------------------------------------------------------------------
1472 // Syntax: if_define sym1 sym2
1475 parse_if_define_final_check(CdlInterpreter interp, CdlProperty_StringVector prop)
1477 CYG_REPORT_FUNCNAME("parse_if_define_final_check");
1478 CYG_PRECONDITION_CLASSC(interp);
1479 CYG_PRECONDITION_CLASSC(prop);
1481 // There should be exactly two entries in the vector, and both of them should be
1482 // valid preprocessor symbols.
1483 const std::vector<std::string>& strings = prop->get_strings();
1485 if (2 != strings.size()) {
1486 CdlParse::report_property_parse_error(interp, prop, "There should be exactly two arguments.");
1488 if (!Cdl::is_valid_c_preprocessor_symbol(strings[0])) {
1489 CdlParse::report_property_parse_error(interp, prop, strings[0] + " is not a valid C preprocessor symbol.");
1491 if (!Cdl::is_valid_c_preprocessor_symbol(strings[1])) {
1492 CdlParse::report_property_parse_error(interp, prop, strings[1] + " is not a valid C preprocessor symbol.");
1495 // There may be a file option. At this stage the only valid filename
1496 // that can be used here is system.h
1497 std::string file_option = prop->get_option("file");
1498 if (("" != file_option) && ("system.h" != file_option)) {
1499 CdlParse::report_property_parse_error(interp, prop, "Invalid -file option " + file_option);
1504 CdlDefinableBody::parse_if_define(CdlInterpreter interp, int argc, const char* argv[])
1506 CYG_REPORT_FUNCNAMETYPE("parse_if_define", "result %d");
1512 int result = CdlParse::parse_stringvector_property(interp, argc, argv, CdlPropertyId_IfDefine, options,
1513 &parse_if_define_final_check, false);
1515 CYG_REPORT_RETVAL(result);
1520 //{{{ generate_config_header()
1522 // ----------------------------------------------------------------------------
1523 // This code needs to allow for the following properties.
1525 // 1) no_define. This suppresses the default #define generation.
1527 // 2) define_format <format_string.
1529 // 3) define [-file <filename>][-format <format_string>] symbol
1536 CdlDefinableBody::generate_config_header(Tcl_Channel this_hdr, Tcl_Channel system_h) const
1538 CYG_REPORT_FUNCNAME("CdlDefinable::generate_config_header");
1539 CYG_REPORT_FUNCARG1XV(this);
1540 CYG_PRECONDITION_THISC();
1542 CdlLoadable loadable = get_owner();
1543 CdlInterpreter interp = loadable->get_interpreter();
1545 // This definable is known to be active. However it may or may not be enabled.
1546 CYG_PRECONDITIONC(is_active());
1548 std::string name = get_name();
1549 CdlValueFlavor flavor = CdlValueFlavor_Bool;
1550 std::string value = "1";
1551 CdlConstValuable valuable = dynamic_cast<CdlConstValuable>(this);
1552 if (0 != valuable) {
1553 // It is always possible to check the enabled() flag.
1554 if (!valuable->is_enabled()) {
1555 CYG_REPORT_RETURN();
1558 // The value is only valid for BoolData and Data flavors, and may
1559 // not have been provided. If there is no value then this option
1560 // should not generate a #define
1561 flavor = valuable->get_flavor();
1562 if ((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor)) {
1563 value = valuable->get_value();
1567 // Flavor and value are now both set to sensible strings.
1568 // First, check the no_define property. If this is present then the default
1569 // #define generation should be suppressed.
1570 if (!has_property(CdlPropertyId_NoDefine)) {
1572 // OK, it is necessary to generate at least one #define.
1573 // If this node is actually a loadable then the #define should go
1574 // into system.h, otherwise into the current header
1575 Tcl_Channel chan = this_hdr;
1576 if (dynamic_cast<CdlConstLoadable>((CdlConstNode)this) == loadable) {
1580 // For flavors None and Bool, there should be just one #define
1581 if ((CdlValueFlavor_None == flavor) || (CdlValueFlavor_Bool == flavor)) {
1582 std::string define = "#define " + name + " 1\n";
1583 Tcl_Write(chan, const_cast<char*>(define.c_str()), -1);
1585 // If there is a format string then that controls the default
1587 if (!has_property(CdlPropertyId_DefineFormat)) {
1588 std::string define = "#define " + name + " " + value + "\n";
1589 Tcl_Write(chan, const_cast<char*>(define.c_str()), -1);
1591 CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_DefineFormat));
1592 CYG_ASSERT_CLASSC(strprop);
1593 std::string format = strprop->get_string();
1594 std::string cmd = "return \"#define " + name + " [format " + format + " " + value + "]\n\"";
1596 if (TCL_OK != interp->eval(cmd, define)) {
1597 throw CdlInputOutputException("Internal error executing tcl fragment to process define_format property");
1599 Tcl_Write(chan, const_cast<char*>(define.c_str()), -1);
1602 // There may also be a separate #define of the form <name>_<value>,
1603 // if that is a valid preprocessor symbol.
1604 std::string tmp = name + "_" + value;
1605 if (Cdl::is_valid_c_preprocessor_symbol(tmp)) {
1606 tmp = "#define "+ tmp + "\n";
1607 Tcl_Write(chan, const_cast<char*>(tmp.c_str()), -1);
1610 // For loadables, add additional version information to system_h
1611 if (dynamic_cast<CdlConstLoadable>((CdlConstNode)this) == loadable) {
1612 system_h_add_package_versioning(system_h, name, value);
1617 // Next, check for any additional define properties
1618 std::vector<CdlProperty> define_props;
1619 get_properties(CdlPropertyId_Define, define_props);
1620 std::vector<CdlProperty>::const_iterator prop_i;
1621 for (prop_i = define_props.begin(); prop_i != define_props.end(); prop_i++) {
1622 CdlProperty_String strprop = dynamic_cast<CdlProperty_String>(*prop_i);
1623 CYG_ASSERT_CLASSC(strprop);
1624 std::string symbol = strprop->get_string();
1626 std::string file = strprop->get_option("file");
1627 Tcl_Channel chan = this_hdr;
1628 if (("" != file) && ("system.h" == file)) {
1632 if ((CdlValueFlavor_None == flavor) || (CdlValueFlavor_Bool == flavor)) {
1633 std::string define = "#define " + symbol + " 1\n";
1634 Tcl_Write(chan, const_cast<char*>(define.c_str()), -1);
1636 std::string format = strprop->get_option("format");
1638 std::string define = "#define " + symbol + " " + value + "\n";
1639 Tcl_Write(chan, const_cast<char*>(define.c_str()), -1);
1641 std::string cmd = "return \"#define " + symbol + " [format " + format + " " + value + "]\n\"";
1643 if (TCL_OK != interp->eval(cmd, define)) {
1644 throw CdlInputOutputException("Internal error executing tcl fragment to process format option");
1646 Tcl_Write(chan, const_cast<char*>(define.c_str()), -1);
1649 std::string tmp = symbol + "_" + value;
1650 if (Cdl::is_valid_c_preprocessor_symbol(tmp)) {
1651 tmp = "#define " + tmp + "\n";
1652 Tcl_Write(chan, const_cast<char*>(tmp.c_str()), -1);
1657 // Now check for if_define properties
1658 std::vector<CdlProperty> if_define_props;
1659 get_properties(CdlPropertyId_IfDefine, if_define_props);
1660 for (prop_i = if_define_props.begin(); prop_i != if_define_props.end(); prop_i++) {
1661 CdlProperty_StringVector strprop = dynamic_cast<CdlProperty_StringVector>(*prop_i);
1662 CYG_ASSERT_CLASSC(strprop);
1663 CYG_ASSERTC(2 == strprop->get_number_of_strings());
1665 std::string sym1 = strprop->get_string(0);
1666 std::string sym2 = strprop->get_string(1);
1668 Tcl_Channel chan = this_hdr;
1669 std::string file = strprop->get_option("file");
1670 if (("" != file) && ("system.h" == file)) {
1673 std::string data = "#ifdef " + sym1 + "\n# define " + sym2 + " 1\n#endif\n";
1674 Tcl_Write(chan, const_cast<char*>(data.c_str()), -1);
1677 // And define_proc properties
1678 std::vector<CdlProperty> define_proc_props;
1679 get_properties(CdlPropertyId_DefineProc, define_proc_props);
1680 for (prop_i = define_proc_props.begin(); prop_i != define_proc_props.end(); prop_i++) {
1681 CdlProperty_TclCode codeprop = dynamic_cast<CdlProperty_TclCode>(*prop_i);
1682 CYG_ASSERT_CLASSC(codeprop);
1684 cdl_tcl_code code = codeprop->get_code();
1686 if (TCL_OK != interp->eval(code, result)) {
1687 throw CdlInputOutputException("Error evaluating define_proc property for " + name + "\n" + result);
1692 CYG_REPORT_RETURN();
1698 //{{{ CdlDefineLoadableBody
1702 // ----------------------------------------------------------------------------
1704 CdlDefineLoadableBody::CdlDefineLoadableBody()
1706 CYG_REPORT_FUNCNAME("CdlDefineLoadable:: default constructor");
1707 CYG_REPORT_FUNCARG1XV(this);
1709 cdldefineloadablebody_cookie = CdlDefineLoadableBody_Magic;
1710 CYGDBG_MEMLEAK_CONSTRUCTOR();
1712 CYG_POSTCONDITION_THISC();
1713 CYG_REPORT_RETURN();
1716 CdlDefineLoadableBody::~CdlDefineLoadableBody()
1718 CYG_REPORT_FUNCNAME("CdlDefineLoadable:: destructor");
1719 CYG_REPORT_FUNCARG1XV(this);
1720 CYG_PRECONDITION_THISC();
1722 cdldefineloadablebody_cookie = CdlDefineLoadableBody_Invalid;
1723 CYGDBG_MEMLEAK_DESTRUCTOR();
1725 CYG_REPORT_RETURN();
1728 // ----------------------------------------------------------------------------
1731 CdlDefineLoadableBody::get_class_name() const
1733 CYG_REPORT_FUNCNAME("CdlDefineLoadable::get_class_name");
1734 CYG_PRECONDITION_THISC();
1735 CYG_REPORT_RETURN();
1736 return "define_loadable";
1739 // ----------------------------------------------------------------------------
1742 CdlDefineLoadableBody::check_this(cyg_assert_class_zeal zeal) const
1744 if (CdlDefineLoadableBody_Magic != cdldefineloadablebody_cookie) {
1747 CYGDBG_MEMLEAK_CHECKTHIS();
1748 return CdlLoadableBody::check_this(zeal) && CdlNodeBody::check_this(zeal);
1752 //{{{ Property parsing
1754 // ----------------------------------------------------------------------------
1757 CdlDefineLoadableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers)
1759 CYG_REPORT_FUNCNAME("CdlDefineLoadable::add_property_parsers");
1761 static CdlInterpreterCommandEntry commands[] =
1763 CdlInterpreterCommandEntry("define_header", &parse_define_header),
1764 CdlInterpreterCommandEntry("", 0 )
1767 for (int i = 0; commands[i].command != 0; i++) {
1768 std::vector<CdlInterpreterCommandEntry>::const_iterator j;
1769 for (j = parsers.begin(); j != parsers.end(); j++) {
1770 if (commands[i].name == j->name) {
1771 if (commands[i].command != j->command) {
1772 CYG_FAIL("Property names are being re-used");
1777 if (j == parsers.end()) {
1778 parsers.push_back(commands[i]);
1781 CdlNodeBody::add_property_parsers(parsers);
1783 CYG_REPORT_RETURN();
1787 CdlDefineLoadableBody::check_properties(CdlInterpreter interp)
1789 CYG_REPORT_FUNCNAME("CdlDefineLoadable::check_properties");
1790 CYG_REPORT_FUNCARG2XV(this, interp);
1791 CYG_PRECONDITION_THISC();
1792 CYG_PRECONDITION_CLASSC(interp);
1794 // There should be at most one define_header property
1795 int count = count_properties(CdlPropertyId_DefineHeader);
1797 CdlParse::report_error(interp, "", "There should be at most one define_header property.");
1799 // FIXME: filename validation
1801 CdlNodeBody::check_properties(interp);
1803 CYG_REPORT_RETURN();
1806 // ----------------------------------------------------------------------------
1807 // syntax: define_header <header file name>
1809 CdlDefineLoadableBody::parse_define_header(CdlInterpreter interp, int argc, const char* argv[])
1811 CYG_REPORT_FUNCNAMETYPE("parse_define_header", "result %d");
1813 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_DefineHeader, 0, 0);
1815 CYG_REPORT_RETVAL(result);
1820 //{{{ generate_config_header()
1822 // ----------------------------------------------------------------------------
1824 CdlDefineLoadableBody::generate_config_header(Tcl_Channel this_hdr, Tcl_Channel system_h) const
1826 CYG_REPORT_FUNCNAME("CdlDefineLoadable::generate_config_header");
1827 CYG_REPORT_FUNCARG1XV(this);
1828 CYG_PRECONDITION_THISC();
1830 CdlInterpreter interp = get_interpreter();
1831 Tcl_RegisterChannel(interp->get_tcl_interpreter(), this_hdr);
1832 Tcl_RegisterChannel(interp->get_tcl_interpreter(), system_h);
1834 CdlInterpreterBody::ContextSupport(interp, std::string("Package ") + this->get_name() + ", header file generation");
1837 interp->set_variable("::cdl_header", Tcl_GetChannelName(this_hdr));
1838 interp->set_variable("::cdl_system_header", Tcl_GetChannelName(system_h));
1840 const std::vector<CdlNode>& contents = get_owned();
1841 std::vector<CdlNode>::const_iterator node_i;
1842 for (node_i = contents.begin(); node_i != contents.end(); node_i++) {
1843 CdlDefinable definable = dynamic_cast<CdlDefinable>(*node_i);
1844 if (0 == definable) {
1847 if (!definable->is_active()) {
1850 definable->generate_config_header(this_hdr, system_h);
1853 interp->unset_variable("::cdl_header");
1854 interp->unset_variable("::cdl_system_header");
1856 Tcl_UnregisterChannel(interp->get_tcl_interpreter(), this_hdr);
1857 Tcl_UnregisterChannel(interp->get_tcl_interpreter(), system_h);
1861 Tcl_UnregisterChannel(interp->get_tcl_interpreter(), this_hdr);
1862 Tcl_UnregisterChannel(interp->get_tcl_interpreter(), system_h);
1864 CYG_REPORT_RETURN();
1868 //{{{ get_config_headers()
1870 // ----------------------------------------------------------------------------
1871 // What header file should be generated for this loadable?
1873 // If there is a define_header property then this should be used.
1874 // Otherwise a filename is constructed from the loadable's name.
1877 CdlDefineLoadableBody::get_config_header() const
1879 CYG_REPORT_FUNCNAME("CdlDefineLoadable::get_config_headers");
1880 CYG_REPORT_FUNCARG1XV(this);
1881 CYG_PRECONDITION_THISC();
1883 std::string result = "";
1884 CdlProperty prop = get_property(CdlPropertyId_DefineHeader);
1886 CdlProperty_String string_prop = dynamic_cast<CdlProperty_String>(prop);
1887 CYG_ASSERT_CLASSC(string_prop);
1888 result = string_prop->get_string();
1890 std::string tmp = get_name();
1891 result = Cdl::get_short_form(tmp);
1894 CYG_REPORT_RETURN();
1903 //{{{ CdlToplevel::get_build_info()
1905 // ----------------------------------------------------------------------------
1906 // Essentially this code involves iterating over the loadables vector,
1907 // looking for BuildLoadables and invoking their update_build_info()
1908 // member function. In addition, if there is currently some data in
1909 // the build_info vector (probably from a previous call) then that
1913 CdlToplevelBody::get_build_info(CdlBuildInfo& build_info)
1915 CYG_REPORT_FUNCNAME("CdlToplevel::get_build_info");
1916 CYG_REPORT_FUNCARG2XV(this, &build_info);
1917 CYG_PRECONDITION_THISC();
1919 if (0 != build_info.entries.size()) {
1920 build_info.entries.clear();
1923 const std::vector<CdlLoadable>& loadables = get_loadables();
1924 std::vector<CdlLoadable>::const_iterator load_i;
1925 for (load_i = loadables.begin(); load_i != loadables.end(); load_i++) {
1926 CdlConstBuildLoadable bl = dynamic_cast<CdlConstBuildLoadable>(*load_i);
1928 bl->update_build_info(build_info);
1932 CYG_REPORT_RETURN();
1936 //{{{ CdlToplevel::get_all_build_info()
1938 // ----------------------------------------------------------------------------
1939 // This is just like get_build_info(), but calls a different
1940 // BuildLoadable member.
1943 CdlToplevelBody::get_all_build_info(CdlBuildInfo& build_info)
1945 CYG_REPORT_FUNCNAME("CdlToplevel::get_all_build_info");
1946 CYG_REPORT_FUNCARG2XV(this, &build_info);
1947 CYG_PRECONDITION_THISC();
1949 if (0 != build_info.entries.size()) {
1950 build_info.entries.clear();
1953 const std::vector<CdlLoadable>& loadables = get_loadables();
1954 std::vector<CdlLoadable>::const_iterator load_i;
1955 for (load_i = loadables.begin(); load_i != loadables.end(); load_i++) {
1956 CdlConstBuildLoadable bl = dynamic_cast<CdlConstBuildLoadable>(*load_i);
1958 bl->update_all_build_info(build_info);
1962 CYG_REPORT_RETURN();
1966 //{{{ CdlToplevel::generate_config_headers()
1968 // ----------------------------------------------------------------------------
1969 // Generating the config headers. This involves the following steps:
1971 // 1) for every DefineLoadable, find out what header file should
1972 // be generated. Note that some loadables may share a header file.
1974 // 2) create a temporary version of system.h. Note that it is not
1975 // a good idea to just overwrite an existing system.h, chances
1976 // are pretty good that the file will not have changed, and
1977 // updating it unnecessarily will result in unnecessary rebuilds
1978 // due to header file dependencies.
1980 // 3) for each file that should be generated, create a temporary
1981 // version and allow all applicable loadables to update it.
1983 // A utility to compare two files and do the right thing.
1984 // This requires some simple Tcl code.
1986 compare_and_copy(CdlInterpreter interp, std::string file1, std::string file2)
1988 CYG_REPORT_FUNCNAME("compare_and_copy");
1989 CYG_PRECONDITION_CLASSC(interp);
1990 CYG_PRECONDITIONC("" != file1);
1991 CYG_PRECONDITIONC("" != file2);
1992 CYG_PRECONDITIONC(file1 != file2);
1994 static char compare_and_copy_script[] = "\
1995 if {[file exists \"$::cdl_compare_and_copy_file2\"] == 0} { \n\
1996 catch { file rename -- $::cdl_compare_and_copy_file1 $::cdl_compare_and_copy_file2} \n\
1999 set fd [open \"$::cdl_compare_and_copy_file1\" r] \n\
2000 set data1 [read $fd] \n\
2002 set fd [open \"$::cdl_compare_and_copy_file2\" r] \n\
2003 set data2 [read $fd] \n\
2005 if {$data1 == $data2} { \n\
2006 file delete \"$::cdl_compare_and_copy_file1\" \n\
2008 catch { file rename -force -- $::cdl_compare_and_copy_file1 $::cdl_compare_and_copy_file2 } \n\
2012 interp->set_variable("::cdl_compare_and_copy_file1", file1);
2013 interp->set_variable("::cdl_compare_and_copy_file2", file2);
2014 std::string tcl_result;
2015 if (TCL_OK != interp->eval(compare_and_copy_script, tcl_result)) {
2016 throw CdlInputOutputException("internal error manipulating temporary header " + file1 + " and target " + file2 +
2022 CdlToplevelBody::generate_config_headers(std::string directory)
2024 CYG_REPORT_FUNCNAME("CdlToplevel::generate_config_headers");
2025 CYG_REPORT_FUNCARG1XV(this);
2026 CYG_PRECONDITION_THISC();
2027 CYG_ASSERTC("" != directory);
2029 // Replace any backslashes in the path with forward slashes. The
2030 // latter are used throughout the library
2031 // NOTE: this is not i18n-friendly.
2032 for (unsigned int i = 0; i < directory.size(); i++) {
2033 if ('\\' == directory[i]) {
2038 CdlInterpreter interp = get_interpreter();
2039 std::string tcl_result;
2040 if ((TCL_OK != interp->eval("file isdirectory \"" + directory + "\"", tcl_result)) ||
2041 (tcl_result != "1")) {
2042 throw CdlInputOutputException("target " + directory + " is not a valid existing directory.");
2045 std::vector<std::pair<CdlDefineLoadable, std::string> > headers;
2046 const std::vector<CdlLoadable>& loadables = get_loadables();
2047 std::vector<CdlLoadable>::const_iterator load_i;
2048 for (load_i = loadables.begin(); load_i != loadables.end(); load_i++) {
2049 CdlDefineLoadable tmp = dynamic_cast<CdlDefineLoadable>(*load_i);
2051 std::string hdr = tmp->get_config_header();
2052 headers.push_back(std::make_pair(tmp, hdr));
2056 static char banner_format[] =
2057 "#ifndef CYGONCE_PKGCONF_%s\n\
2058 #define CYGONCE_PKGCONF_%s\n\
2060 * File <pkgconf/%s>\n\
2062 * This file is generated automatically by the configuration\n\
2063 * system. It should not be edited. Any changes to this file\n\
2064 * may be overwritten.\n\
2068 // Create three channels which Tcl will use for standard streams
2069 // if these streams do not already exist. This avoids a Tcl
2070 // problem which can prevent closure of system.h. (FIXME)
2071 Tcl_Channel stdin_chan = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), "nul", "w", 0666);
2072 Tcl_Channel stdout_chan = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), "nul", "w", 0666);
2073 Tcl_Channel stderr_chan = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), "nul", "w", 0666);
2074 Tcl_RegisterChannel(0, stdin_chan);
2075 Tcl_RegisterChannel(0, stdout_chan);
2076 Tcl_RegisterChannel(0, stderr_chan);
2078 // Assume for now that files __libcdl_file1 and __libcdl_file2 are
2079 // legal on all platforms of interest, and that nobody is going to
2081 std::string system_h_name = directory + "/__libcdl_file1";
2082 Tcl_Channel system_h = Tcl_OpenFileChannel(interp->get_tcl_interpreter(),
2083 const_cast<char*>(system_h_name.c_str()), "w", 0666);
2084 if (0 == system_h) {
2085 throw CdlInputOutputException("Unable to open file " + system_h_name + "\n" +
2086 interp->get_result());
2088 // The channel will be registered and unregistered in several
2089 // different interpreters. This call prevents the channel from
2090 // disappearing prematurely.
2091 Tcl_RegisterChannel(0, system_h);
2093 // Make sure that this operation is undone if necessary.
2095 // Now fill in system.h with the appropriate data. Start with the banner.
2096 char local_buf[512];
2097 sprintf(local_buf, banner_format, "SYSTEM_H", "SYSTEM_H", "system.h");
2098 Tcl_Write(system_h, local_buf, -1);
2100 // Add generic version information
2101 system_h_add_version_header(system_h);
2103 // The rest of system.h will be filled in by the following loop.
2105 // Walk down the previously constructed headers vector, create
2106 // appropriate files, and let each DefineLoadable fill in the
2108 std::vector<std::pair<CdlDefineLoadable, std::string> >::iterator outer_i;
2109 std::vector<std::pair<CdlDefineLoadable, std::string> >::iterator inner_i;
2110 for (outer_i = headers.begin(); outer_i != headers.end(); outer_i++) {
2111 if ("" == outer_i->second) {
2114 std::string target_name = outer_i->second;
2115 std::string header_name = directory + "/__libcdl_file2";
2116 Tcl_Channel header_h = Tcl_OpenFileChannel(interp->get_tcl_interpreter(),
2117 const_cast<char*>(header_name.c_str()), "w", 0666);
2118 if (0 == header_h) {
2119 throw CdlInputOutputException("Unable to open file " + header_name + "\n" +
2120 interp->get_result());
2122 // The channel may be used in several different interpreters, so
2123 // do an extra register operation
2124 Tcl_RegisterChannel(0, header_h);
2127 // Output the banner. This requires an all-upper-case version of the
2129 std::string upper_case;
2130 for (unsigned int i = 0; i < target_name.size(); i++) {
2131 if (islower(target_name[i])) {
2132 upper_case += toupper(target_name[i]);
2133 } else if ('.' == target_name[i]) {
2136 upper_case += target_name[i];
2139 sprintf(local_buf, banner_format, upper_case.c_str(), upper_case.c_str(), target_name.c_str());
2140 Tcl_Write(header_h, local_buf, -1);
2142 // Now iterate over all the loadables looking for ones which
2143 // should generate #define's for this header, and invoke the
2144 // appropriate member function.
2145 for (inner_i = outer_i; inner_i != headers.end(); inner_i++) {
2146 if (inner_i->second == target_name) {
2147 inner_i->first->generate_config_header(header_h, system_h);
2148 inner_i->second = "";
2152 // The header file has now been updated. Close it and decide whether
2153 // or not to replace the old version
2154 Tcl_Write(header_h, "\n#endif\n", -1);
2156 Tcl_UnregisterChannel(0, header_h);
2159 Tcl_UnregisterChannel(0, header_h);
2160 compare_and_copy(interp, header_name, directory + "/" + target_name);
2163 Tcl_Write(system_h, "\n#endif\n", -1);
2165 Tcl_UnregisterChannel(0, system_h);
2169 // This call to UnregisterChannel automatically closes the
2170 // channel, there is no need for an explicit Tcl_Close() call.
2171 Tcl_UnregisterChannel(0, system_h);
2173 Tcl_UnregisterChannel(0, stderr_chan);
2174 Tcl_UnregisterChannel(0, stdout_chan);
2175 Tcl_UnregisterChannel(0, stdin_chan);
2177 compare_and_copy(interp, system_h_name, directory +"/system.h");
2181 //{{{ CdlToplevel::get_config_headers()
2183 // ----------------------------------------------------------------------------
2184 // Return details of the header files that should be generated. This
2185 // allows higher-level code to detect files that should no longer
2186 // be present, amongst other uses.
2188 // The main complication is that some packages may wish to share the
2189 // same header file, especially hardware packages.
2192 CdlToplevelBody::get_config_headers(std::vector<std::string>& headers)
2194 CYG_REPORT_FUNCNAME("CdlToplevelBody::get_config_headers");
2195 CYG_REPORT_FUNCARG2XV(this, &headers);
2196 CYG_PRECONDITION_THISC();
2198 // Allow the vector argument to be re-used in multiple calls.
2199 // Strictly speaking this is better done at the application
2200 // level, but the behaviour is consistent with get_build_info();
2203 // There will always be a system.h header file with details
2204 // of the loadables.
2205 // FIXME: the name of this file should probably be controllable
2206 headers.push_back("system.h");
2208 // Now check each loadable and adds its header file, assuming
2210 const std::vector<CdlLoadable>& loadables = get_loadables();
2211 std::vector<CdlLoadable>::const_iterator i;
2212 for (i = loadables.begin(); i != loadables.end(); i++) {
2213 CdlDefineLoadable current = dynamic_cast<CdlDefineLoadable>(*i);
2215 std::string its_file = current->get_config_header();
2216 CYG_LOOP_INVARIANTC("" != its_file);
2217 if (std::find(headers.begin(), headers.end(), its_file) == headers.end()) {
2218 headers.push_back(its_file);
2223 CYG_REPORT_RETURN();
2227 //{{{ CdlToplevel::generate_build_tree()
2230 CdlToplevelBody::generate_build_tree(std::string build_tree, std::string install_tree)