1 package ProjectCreator
;
3 # ************************************************************
4 # Description : Base class for all project creators
5 # Author : Chad Elliott
6 # Create Date : 3/13/2002
7 # ************************************************************
9 # ************************************************************
11 # ************************************************************
19 use TemplateInputReader
;
30 # ************************************************************
32 # ************************************************************
34 ## The basic extensions known to a project creator
35 my $BaseClassExtension = 'mpb';
36 my $ProjectCreatorExtension = 'mpc';
37 my $TemplateExtension = 'mpd';
38 my $TemplateInputExtension = 'mpt';
40 ## This feature is enabled or disabled depending on whether
41 ## or not the -static option is used.
42 my $static_libs_feature = 'static_libs_only';
44 ## Valid names for assignments within a project
46 ## 0 Preserve the order for additions (1) or invert it (0)
47 ## 1 Add this value to template input value (if there is one)
48 ## 2 Preserve <% %> settings for evaluation within the template
49 my %validNames = ('after' => 1,
70 'recursive_includes' => 3,
71 'recursive_libpaths' => 3,
82 ## Custom definitions only
84 ## 0 Value is always an array
85 ## 1 Value is an array and name gets 'outputext' converted to 'files'
86 ## 2 Value is always scalar
87 ## 3 Name can also be used in an 'optional' clause
88 ## 4 Needs <%...%> conversion
89 my %customDefined = ('automatic_in' => 0x04,
90 'automatic_out' => 0x04,
92 'commandflags' => 0x14,
94 'dependent_libs' => 0x14,
96 'postcommand' => 0x14,
99 'output_follows_input' => 0x04,
100 'output_option' => 0x14,
101 'pch_postrule' => 0x04,
102 'pre_extension' => 0x08,
103 'source_pre_extension' => 0x08,
104 'template_pre_extension' => 0x08,
105 'header_pre_extension' => 0x08,
106 'inline_pre_extension' => 0x08,
107 'documentation_pre_extension' => 0x08,
108 'resource_pre_extension' => 0x08,
109 'generic_pre_extension' => 0x08,
110 'pre_filename' => 0x08,
111 'source_pre_filename' => 0x08,
112 'template_pre_filename' => 0x08,
113 'header_pre_filename' => 0x08,
114 'inline_pre_filename' => 0x08,
115 'documentation_pre_filename' => 0x08,
116 'resource_pre_filename' => 0x08,
117 'generic_pre_filename' => 0x08,
118 'pre_dirname' => 0x08,
119 'source_pre_dirname' => 0x08,
120 'template_pre_dirname' => 0x08,
121 'header_pre_dirname' => 0x08,
122 'inline_pre_dirname' => 0x08,
123 'documentation_pre_dirname' => 0x08,
124 'resource_pre_dirname' => 0x08,
125 'generic_pre_dirname' => 0x08,
126 'source_outputext' => 0x0a,
127 'template_outputext' => 0x0a,
128 'header_outputext' => 0x0a,
129 'inline_outputext' => 0x0a,
130 'documentation_outputext' => 0x0a,
131 'resource_outputext' => 0x0a,
132 'generic_outputext' => 0x0a,
135 ## Custom sections as well as definitions
137 ## 0 No modifications
138 ## 1 Needs <%...%> conversion
139 my %custom = ('command' => 1,
142 'dependent_libs'=> 1,
148 ## All matching assignment arrays will get these keywords
149 my @default_matching_assignments = ('recurse',
152 ## Deal with these components in a special way
153 my %specialComponents = ('header_files' => 1,
155 'template_files' => 1,
157 my %sourceComponents = ('source_files' => 1,
158 'template_files' => 1,
161 my $defgroup = 'default_group';
162 my $grouped_key = 'grouped_';
165 ## Matches with generic_outputext
166 my $generic_key = 'generic_files';
168 ## These constants are used with the "project info" and
169 ## must match the order that is defined by the call order
170 ## of ProjectCreator::update_project_info(). This called
171 ## order is determined by the TemplateParser.
173 ## NOTE: If you are going to add a new constant, you must make it the
174 ## numeric value of the CONFIGURATIONS constant and increment
175 ## the existing CONFIGURATIONS value.
176 use constant PROJECT_NAME
=> 0;
177 use constant DEPENDENCIES
=> 1;
178 use constant PROJECT_GUID
=> 2;
179 use constant LANGUAGE
=> 3;
180 use constant CUSTOM_ONLY
=> 4;
181 use constant NO_CROSS_COMPILE
=> 5;
182 use constant MANAGED_PROJECT
=> 6;
183 use constant MAKE_GROUP
=> 7;
184 use constant CONFIGURATIONS
=> 8;
186 # ************************************************************
187 # C++ Specific Component Settings
188 # ************************************************************
190 ## Resource files tag for C++
191 my $cppresource = 'resource_files';
193 ## Valid component names within a project along with the valid file extensions
194 my %cppvc = ('source_files' => [ "\\.cpp", "\\.cxx", "\\.cc", "\\.c", "\\.C", ],
195 'template_files' => [ "_T\\.cpp", "_T\\.cxx", "_T\\.cc", "_T\\.c", "_T\\.C", "_t\\.cpp", "_t\\.cxx", "_t\\.cc", "_t\\.c", "_t\\.C", "\\.tpp" ],
196 'header_files' => [ "\\.h", "\\.hpp", "\\.hxx", "\\.hh", ],
197 'inline_files' => [ "\\.i", "\\.ipp", "\\.inl", ],
198 'documentation_files' => [ "README", "readme", "\\.doc", "\\.txt", "\\.html" ],
199 $cppresource => [ "\\.rc", ],
202 ## Exclude these extensions when auto generating the component values
203 my %cppec = ('source_files' => $cppvc{'template_files'},
206 ## These matching assignment arrays will get added, but only to the
207 ## specific project component types.
208 my %cppma = ('source_files' => ['buildflags',
212 'header_files' => [ 'dependent_upon',
216 # ************************************************************
217 # C# Specific Component Settings
218 # ************************************************************
220 ## Resource files tag for C#
221 my $csresource = 'resx_files';
223 ## Valid component names within a project along with the valid file extensions
224 my %csvc = ('source_files' => [ "\\.cs" ],
225 'config_files' => [ "\\.config" ],
226 $csresource => [ "\\.resx", "\\.resources" ],
227 'aspx_files' => [ "\\.aspx" ],
228 'ico_files' => [ "\\.ico" ],
229 'documentation_files' => [ "README", "readme", "\\.doc", "\\.txt", "\\.html" ],
230 'embedded_resource_files' => [],
231 'resource_files' => [],
233 'appdef_files' => [],
234 'splash_files' => [],
237 my %csma = ('source_files' => [ 'dependent_upon',
240 $csresource => [ 'dependent_upon',
246 # ************************************************************
247 # Java Specific Component Settings
248 # ************************************************************
250 ## Valid component names within a project along with the valid file extensions
251 my %jvc = ('source_files' => [ "\\.java" ],
252 'documentation_files' => [ "README", "readme", "\\.doc", "\\.txt", "\\.html" ],
255 # ************************************************************
256 # Visual Basic Specific Component Settings
257 # ************************************************************
259 ## Resource files tag for VB
260 my $vbresource = 'resx_files';
262 ## Valid component names within a project along with the valid file extensions
263 my %vbvc = ('source_files' => [ "\\.vb" ],
264 'config_files' => [ "\\.config" ],
265 $vbresource => [ "\\.resx" ],
266 'aspx_files' => [ "\\.aspx" ],
267 'ico_files' => [ "\\.ico" ],
268 'documentation_files' => [ "README", "readme", "\\.doc", "\\.txt", "\\.html" ],
271 my %vbma = ('source_files' => [ 'subtype' ],
274 # ************************************************************
275 # Language Specific Component Settings
276 # ************************************************************
281 # 1 Files automatically excluded from source_files
282 # 2 Assignments available in standard file types
283 # 3 The entry point for executables
284 # 4 The language uses a C preprocessor
285 # 5 Name of the tag for 'resource_files' for this language
286 # * This is special because it gets treated like source_files in that
287 # a project with only these files is a library/exe not "custom only".
289 ## NOTE: We call the constant as a function to support Perl 5.6.
290 my %language = (Creator
::cplusplus
() => [ \
%cppvc, \
%cppec, \
%cppma, 'main',
293 Creator
::csharp
() => [ \
%csvc, {}, \
%csma, 'Main', 0,
296 Creator
::java
() => [ \
%jvc, {}, {}, 'main', 0 ],
298 Creator
::vb
() => [ \
%vbvc, {}, \
%vbma, 'Main', 0,
303 # ************************************************************
305 # ************************************************************
308 my($class, $global, $inc, $template, $ti, $dynamic, $static, $relative, $addtemp, $addproj, $progress, $toplevel, $baseprojs, $gfeature, $relative_f, $feature, $features, $hierarchy, $exclude, $makeco, $nmod, $applypj, $genins, $into, $language, $use_env, $expandvars, $gendot, $comments, $foreclipse, $pid) = @_;
309 my $self = $class->SUPER::new
($global, $inc,
310 $template, $ti, $dynamic, $static,
311 $relative, $addtemp, $addproj,
312 $progress, $toplevel, $baseprojs,
314 $hierarchy, $nmod, $applypj,
315 $into, $language, $use_env,
319 $self->{$self->{'type_check'}} = 0;
320 $self->{'feature_defined'} = 0;
321 $self->{'features_changed'} = undef;
322 $self->{'project_info'} = [];
323 $self->{'lib_locations'} = {};
324 $self->{'reading_parent'} = [];
325 $self->{'dll_exe_template_input'}= {};
326 $self->{'lib_exe_template_input'}= {};
327 $self->{'lib_template_input'} = {};
328 $self->{'dll_template_input'} = {};
329 $self->{'flag_overrides'} = {};
330 $self->{'custom_special_output'} = {};
331 $self->{'custom_special_depend'} = {};
332 $self->{'special_supplied'} = {};
333 $self->{'pctype'} = $self->extractType("$self");
334 $self->{'verbatim'} = {};
335 $self->{'verbatim_accessed'} = {$self->{'pctype'} => {}};
336 $self->{'defaulted'} = {};
337 $self->{'custom_types'} = {};
338 $self->{'parents_read'} = {};
339 $self->{'inheritance_tree'} = {};
340 $self->{'remove_files'} = {};
341 $self->{'expanded'} = {};
342 $self->{'dependency_attributes'} = {};
343 $self->{'gfeature_file'} = $gfeature;
344 $self->{'relative_file'} = $relative_f;
345 $self->{'feature_parser'} = $self->create_feature_parser($features,
347 $self->{'sort_files'} = $self->sort_files();
348 $self->{'source_callback'} = undef;
349 $self->{'dollar_special'} = $self->dollar_special();
350 $self->{'generate_ins'} = $genins;
351 $self->{'addtemp_state'} = undef;
352 $self->{'command_subs'} = $self->get_command_subs();
353 $self->{'escape_spaces'} = $self->escape_spaces();
354 $self->{'current_template'} = undef;
355 $self->{'make_coexistence'} = $makeco;
357 $self->add_default_matching_assignments();
358 $self->reset_generating_types();
360 $self->{'pid'} = $pid;
361 $self->{'llctr'} = 0; # counts the hash insertion order for mp-mpc
368 ## Is the name passed in a known keyword for a project. This includes
369 ## keywords mapped by Define_Custom or Modify_Custom.
370 my($self, $name) = @_;
371 return $self->{'valid_names'}->{$name};
375 sub read_global_configuration
{
377 my $input = $self->get_global_cfg();
380 if (defined $input) {
381 ## If it doesn't contain a path, search the include path
382 if ($input !~ /[\/\\]/) {
383 $input = $self->search_include_path($input);
384 $input = $self->get_global_cfg() if (!defined $input);
387 ## Read and parse the global project file
388 $self->{'reading_global'} = 1;
389 $status = $self->parse_file($input);
390 $self->{'reading_global'} = 0;
397 sub convert_to_template_assignment
{
398 my($self, $name, $value, $calledfrom) = @_;
400 ## If the value we are going to set for $name has been used as a
401 ## scoped template variable, we need to hijack the whole assignment
402 ## and turn it into a template variable assignment.
403 my $atemp = $self->get_addtemp();
404 foreach my $key (grep(/::$name$/, keys %$atemp)) {
405 $self->update_template_variable(0, $calledfrom, $key, $value);
410 sub create_recursive_settings
{
411 my($self, $name, $value, $assign) = @_;
413 ## Handle both recursive_includes and recursive_libpaths in one
414 ## search and replace.
415 if ($name =~ s/^recursive_//) {
416 ## This portion of code was lifted directly from Creator::relative()
417 ## but modified to always expand the variables. We will turn the
418 ## expanded values back into variables below and once they're passed
419 ## off to the assignment processing code, they will be turned into
420 ## relative values (if possible).
421 if (index($value, '$') >= 0) {
423 my($rel, $how) = $self->get_initial_relative_values();
424 $value = $self->expand_variables($value, $rel, 0, undef, 1);
426 if ($ovalue eq $value || index($value, '$') >= 0) {
427 ($rel, $how) = $self->get_secondary_relative_values();
428 $value = $self->expand_variables($value, $rel, 0, undef, 1, 1);
432 ## Create an array out of the recursive directory list. Convert all
433 ## of the relative or full path values back into $() values.
435 my $elems = $self->create_array($value);
436 foreach my $elem (@
$elems) {
437 my $dlist = $self->recursive_directory_list($elem, []);
439 ## This directory doesn't exist, just add the original value
443 ## Create an array out of the directory list and add it to our
445 my $array = $self->create_array($dlist);
446 push(@dirs, @
$array);
450 ## We need to return a string, so we join it all together space
452 $value = join(' ', $self->back_to_variable(\
@dirs));
455 return $name, $value;
458 sub process_assignment
{
459 my($self, $name, $value, $assign, $calledfrom) = @_;
460 $calledfrom = 0 if (!defined $calledfrom);
462 ## See if the name is one of the special "recursive" settings. If so,
463 ## fix up the value and change the name.
464 ($name, $value) = $self->create_recursive_settings($name, $value, $assign);
466 if (defined $value) {
467 if ($name eq 'after') {
468 mpc_debug
::chkpnt_pre_after_keyword_assignment
($name, $value, $assign, $calledfrom);
469 ## Support dependency attributes. They may or may not be used by
470 ## the project or workspace creator implementation. They are
471 ## stored separately from the dependencies themselves. Also, note
472 ## that a value to be added may contain more than one element to be
473 ## added. This function will be called for each one, so we only
474 ## need to handle one at a time.
475 if ($value =~ s/(\s*([^:]+)):([^\s]+)/$1/) {
476 ## The value may contain multiple projects. But, only one
477 ## dependency attribute will be present at any time. So, once we
478 ## get here, we need to remove any of the other projects from the
479 ## front of the key string.
483 $self->{'dependency_attributes'}->{$key} = $value;
486 ## Check the after value and warn the user in the event that it
487 ## contains a value that can not be used within a project name.
488 if (!$self->valid_project_name($value)) {
489 $self->warning("after '$value' contains an invalid project name in " .
490 $self->{'current_input'} . ' at line ' .
491 $self->get_line_number() . '.');
494 ## Support the '*' mechanism as in the project name, to allow
495 ## the user to correctly depend on another project within the same
497 if (index($value, '*') >= 0) {
498 $value = $self->fill_type_name($value,
499 $self->get_default_project_name());
501 mpc_debug
::chkpnt_post_after_keyword_assignment
($name, $value, $assign, $calledfrom);
503 ## Support the '*' mechanism for libs assignment as well.
504 elsif ($name eq 'libs' && index($value, '*') >= 0) {
505 $value = $self->fill_type_name($value, $self->get_default_project_name());
508 ## If this particular project type does not consider the dollar sign
509 ## special and the user has provided two dollarsigns as an escape, we
510 ## will turn it into a single dollar sign.
511 if (!$self->{'dollar_special'} && index($value, '$$') >= 0) {
512 $value =~ s/\$\$/\$/g;
515 ## If the assignment name is valid and requires parameter (<%...%>)
516 ## replacement, then do so. But, only do so on actual keywords.
517 ## User defined keywords must not have the parameters replaced in
518 ## order for them to get the correct replacement values later on.
519 if (defined $validNames{$name} &&
520 ($validNames{$name} & 0x04) == 0 && index($value, '<%') >= 0) {
521 $value = $self->replace_parameters($value, $self->{'command_subs'});
525 if ($calledfrom == 0) {
526 $self->convert_to_template_assignment($name, $value, $calledfrom);
529 ## Call the base process_assigment() after we have modified the name and
531 $self->SUPER::process_assignment
($name, $value, $assign);
533 ## Support keyword mapping here only at the project level scope. The
534 ## scoped keyword mapping is done through the parse_scoped_assignment()
536 if (!defined $assign || $assign == $self->get_assignment_hash()) {
537 my $mapped = $self->{'valid_names'}->{$name};
538 if (defined $mapped && UNIVERSAL
::isa
($mapped, 'ARRAY')) {
539 $self->parse_scoped_assignment($$mapped[0], 0,
541 $self->{'generated_exts'}->{$$mapped[0]});
547 sub process_assignment_add
{
548 my($self, $name, $value, $assign) = @_;
550 ## See if the name is one of the special "recursive" settings. If so,
551 ## fix up the value and change the name.
552 ($name, $value) = $self->create_recursive_settings($name, $value, $assign);
554 return $self->SUPER::process_assignment_add
($name, $value, $assign);
558 sub process_assignment_sub
{
559 my($self, $name, $value, $assign) = @_;
561 ## See if the name is one of the special "recursive" settings. If so,
562 ## fix up the value and change the name.
563 ($name, $value) = $self->create_recursive_settings($name, $value, $assign);
565 ## If the assignment name is valid and requires parameter (<%...%>)
566 ## replacement, then do so. But, only do so on actual keywords.
567 ## User defined keywords must not have the parameters replaced in
568 ## order for them to get the correct replacement values later on.
569 if (defined $validNames{$name} &&
570 ($validNames{$name} & 0x04) == 0 && index($value, '<%') >= 0) {
571 $value = $self->replace_parameters($value, $self->{'command_subs'});
574 return $self->SUPER::process_assignment_sub
($name, $value, $assign);
579 my($self, $name, $value, $nval, $assign) = @_;
581 ## If there is a previous value ($nval) and the keyword is going to be
582 ## evaled, we need to separate the values with a command separator.
583 ## This has to be done at the MPC level because it isn't always
584 ## possible for the user to know if a value has already been added to
585 ## the keyword (prebuild, postbuild and postclean).
587 defined $validNames{$name} && ($validNames{$name} & 4)) {
588 if ($self->preserve_assignment_order($name)) {
589 $value = '<%cmdsep%> ' . $value;
592 $value .= '<%cmdsep%>';
596 ## For an addition, we need to see if it is a project keyword being
597 ## used within a 'specific' section. If it is, we may need to update
598 ## scoped settings for that variable (which are in essence template
600 $self->convert_to_template_assignment($name, $value, 1);
602 ## Next, we just give everything to the base class method.
603 $self->SUPER::addition_core
($name, $value, $nval, $assign);
607 sub subtraction_core
{
608 my($self, $name, $value, $nval, $assign) = @_;
610 ## For a subtraction, we need to see if it is a project keyword being
611 ## used within a 'specific' section. If it is, we may need to update
612 ## scoped settings for that variable (which are in essence template
614 $self->convert_to_template_assignment($name, $value, -1);
616 ## Next, we just give everything to the base class method.
617 $self->SUPER::subtraction_core
($name, $value, $nval, $assign);
621 sub get_assignment_for_modification
{
622 my($self, $name, $assign, $subtraction) = @_;
624 ## If we weren't passed an assignment hash, then we need to
625 ## look one up that may possibly correctly deal with keyword mappings
626 if (!defined $assign) {
627 my $mapped = $self->{'valid_names'}->{$name};
629 if (defined $mapped && UNIVERSAL
::isa
($mapped, 'ARRAY')) {
631 $assign = $self->{'generated_exts'}->{$$mapped[0]};
635 ## Get the assignment value
636 my $value = $self->get_assignment($name, $assign);
638 ## If we are involved in a subtraction, we get back a value and
639 ## it's a scoped or mapped assignment, then we need to possibly
640 ## expand any template variables. Otherwise, the subtractions
641 ## may not work correctly.
642 if ($subtraction && defined $value && defined $assign) {
643 $value = $self->relative($value, 1);
651 my($self, $parents) = @_;
655 ## Deal with the inheritance hierarchy first
656 ## Add in the base projects from the command line
657 if (!$self->{'reading_global'} &&
658 !defined $self->{'reading_parent'}->[0]) {
659 my $baseprojs = $self->get_baseprojs();
661 if (defined $parents) {
662 StringProcessor
::merge
($parents, $baseprojs);
665 $parents = $baseprojs;
669 if (defined $parents) {
670 foreach my $parent (@
$parents) {
671 ## Read in the parent onto ourself
672 my $file = $self->search_include_path(
673 "$parent.$BaseClassExtension");
674 if (!defined $file) {
675 $file = $self->search_include_path(
676 "$parent.$ProjectCreatorExtension");
680 if (defined $self->{'reading_parent'}->[0]) {
681 if (StringProcessor
::fgrep
($file, $self->{'reading_parent'})) {
683 $error = 'Cyclic inheritance detected: ' . $parent;
688 if (!defined $self->{'parents_read'}->{$file}) {
689 $self->{'parents_read'}->{$file} = 1;
691 ## Push the base project file onto the parent stack
692 push(@
{$self->{'reading_parent'}}, $file);
694 ## Collect up some information about the inheritance tree
695 my $tree = $self->{'current_input'};
696 if (!defined $self->{'inheritance_tree'}->{$tree}) {
697 $self->{'inheritance_tree'}->{$tree} = {};
699 my $hash = $self->{'inheritance_tree'}->{$tree};
700 foreach my $p (@
{$self->{'reading_parent'}}) {
701 $$hash{$p} = {} if (!defined $$hash{$p});
705 ## Begin reading the parent
706 mpc_debug
::chkpnt_pre_parse_base_project
($file);
707 $status = $self->parse_file($file);
708 mpc_debug
::chkpnt_post_parse_base_project
($file, $status);
710 ## Take the base project file off of the parent stack
711 pop(@
{$self->{'reading_parent'}});
713 $error = "Invalid parent: $parent" if (!$status);
716 ## The base project has already been read. So, if
717 ## we are reading the original project (not a parent base
718 ## project), then the current base project is redundant.
719 if (!defined $self->{'reading_parent'}->[0]) {
720 $file =~ s/\.[^\.]+$//;
721 $self->information('Inheriting from \'' .
722 $self->mpc_basename($file) .
723 '\' in ' . $self->{'current_input'} .
724 ' is redundant at line ' .
725 $self->get_line_number() . '.');
732 $error = "Unable to locate parent: $parent";
737 ## Copy each value from global_assign into assign
738 if (!$self->{'reading_global'}) {
739 foreach my $key (keys %{$self->{'global_assign'}}) {
740 if (!defined $self->{'assign'}->{$key}) {
741 $self->{'assign'}->{$key} = $self->{'global_assign'}->{$key};
746 return $status, $error;
750 sub get_process_project_type
{
751 my($self, $types) = @_;
753 my $defcomp = $self->get_default_component_name();
755 foreach my $t (split(/\s*,\s*/, $types)) {
756 my $not = ($t =~ s/^!\s*//);
758 if ($t eq $self->{'pctype'}) {
763 $type = $self->{'pctype'};
766 elsif ($t eq $self->{'pctype'} || $t eq $defcomp) {
776 sub matches_specific_scope
{
777 my($self, $elements) = @_;
779 ## First check for properties that correspond to the current project
780 ## type. Elements that begin with "prop:" indicate a property.
782 my $props = $self->get_properties();
783 foreach my $prop (split(/\s*,\s*/, $elements)) {
784 my $not = ($prop =~ s/^!\s*//);
785 if ($prop =~/(.+):(.+)/) {
789 return $self->{'pctype'} if (!$$props{$prop});
792 return $self->{'pctype'} if ($$props{$prop});
796 $self->warning("$prop is not recognized.");
800 $list .= ($not ?
'!' : '') . $prop . ',';
804 ## If none of the elements match a property, then check the type
805 ## against the current project type or the default component name
806 ## (which is what it would be set to if a specific clause is used with
808 my $type = $self->get_process_project_type($list);
809 return $self->{'pctype'} if ($type eq $self->{'pctype'} ||
810 $type eq $self->get_default_component_name());
818 my($self, $ih, $line) = @_;
821 @values) = $self->parse_known($line, $ih);
823 ## parse_known() passes back an array of values
824 ## that make up the contents of the line parsed.
825 ## The array can have 0 to 4 items. The first,
826 ## if defined, is always an identifier of some
829 if ($status && defined $values[0]) {
830 if ($values[0] eq $self->{'grammar_type'}) {
831 my $name = $values[1];
832 my $typecheck = $self->{'type_check'};
833 if (defined $name && $name eq '}') {
835 if (!defined $self->{'reading_parent'}->[0] &&
836 !$self->{'reading_global'}) {
837 ## Fill in all the default values
838 $self->generate_defaults();
840 ## Perform any additions, subtractions
841 ## or overrides for the project values.
842 my $addproj = $self->get_addproj();
843 foreach my $ap (keys %$addproj) {
844 if (defined $self->{'valid_names'}->{$ap}) {
845 foreach my $val (@
{$$addproj{$ap}}) {
847 $self->process_assignment_add($ap, $$val[1]);
849 elsif ($$val[0] < 0) {
850 $self->process_assignment_sub($ap, $$val[1]);
853 $self->process_assignment($ap, $$val[1]);
858 $errorString = 'Invalid ' .
859 "assignment modification name: $ap";
865 ## Generate default target names after all source files are added
866 ## and after we've added in all of the options from the
867 ## command line. If the user set exename on the command line
868 ## and no "main" is found, sharedname will be set too and
869 ## most templates do not handle that well.
870 $self->generate_default_target_names();
872 ## End of project; Write out the file.
873 ($status, $errorString) = $self->write_project();
875 ## write_project() can return 0 for error, 1 for project
876 ## was written and 2 for project was skipped
878 ## Save the library name and location
879 foreach my $name ('sharedname', 'staticname') {
880 my $val = $self->get_assignment($name);
882 my $cwd = $self->getcwd();
883 my $start = $self->getstartdir();
885 if ($cwd eq $start) {
886 $amount = length($start);
888 elsif (index($cwd, $start) == 0) {
889 $amount = length($start) + 1;
891 if ($self->{'pid'} eq 'child') {
892 $self->{'lib_locations'}->{$val} =
893 ++$self->{'llctr'} . '|' .
894 substr($cwd, $amount);
898 $self->{'lib_locations'}->{$val} =
899 substr($cwd, $amount);
905 ## Check for unused verbatim markers
906 foreach my $key (keys %{$self->{'verbatim'}}) {
907 if (defined $self->{'verbatim_accessed'}->{$key}) {
908 foreach my $ikey (keys %{$self->{'verbatim'}->{$key}}) {
909 if (!defined $self->{'verbatim_accessed'}->{$key}->{$ikey}) {
910 $self->warning("Marker $ikey does not exist.");
917 ## Reset all of the project specific data. I am explicitly
918 ## not resetting dependency_attributes. It is necessary that
919 ## this information stay for the life of the ProjectCreator
920 ## object so that the WorkspaceCreator can have access to the
922 foreach my $key (keys %{$self->{'valid_components'}}) {
923 delete $self->{$key};
924 delete $self->{'defaulted'}->{$key};
926 if (defined $self->{'addtemp_state'}) {
927 $self->restore_state($self->{'addtemp_state'}, 'addtemp');
928 $self->{'addtemp_state'} = undef;
930 $self->{'assign'} = {};
931 $self->{'verbatim'} = {};
932 $self->{'verbatim_accessed'} = {$self->{'pctype'} => {}};
933 $self->{'special_supplied'} = {};
934 $self->{'flag_overrides'} = {};
935 $self->{'parents_read'} = {};
936 $self->{'inheritance_tree'} = {};
937 $self->{'remove_files'} = {};
938 $self->{'custom_special_output'} = {};
939 $self->{'custom_special_depend'} = {};
940 $self->{'expanded'} = {};
941 $self->reset_generating_types();
944 $self->{$typecheck} = 0;
948 ($status, $errorString) = $self->begin_project($values[2]);
950 ## Set up the default project name
953 if ($self->valid_project_name($name)) {
954 ## We should only set the project name if we are not
955 ## reading in a parent project.
956 if (!defined $self->{'reading_parent'}->[0]) {
959 $name = $self->transform_file_name($name);
961 ## Replace any *'s with the default name
962 if (index($name, '*') >= 0) {
963 $name = $self->fill_type_name(
965 $self->get_default_project_name());
968 $self->set_project_name($name);
971 $self->warning("Ignoring project name " .
972 "$name in a base project.");
977 $errorString = 'Projects can not have the following in ' .
978 'the name: / \\ = ? : & " < > | # %';
983 ## Signify that we have a valid project
984 $self->{$typecheck} = 1 if ($status);
987 elsif ($values[0] eq '0') {
988 ## $values[1] = name; $values[2] = value
989 if (defined $self->{'valid_names'}->{$values[1]}) {
990 $self->process_assignment($values[1], $values[2]);
993 $errorString = "Invalid assignment name: '$values[1]'";
997 elsif ($values[0] eq '1') {
998 ## $values[1] = name; $values[2] = value
999 if (defined $self->{'valid_names'}->{$values[1]}) {
1000 $self->process_assignment_add($values[1], $values[2]);
1003 $errorString = "Invalid addition name: $values[1]";
1007 elsif ($values[0] eq '-1') {
1008 ## $values[1] = name; $values[2] = value
1009 if (defined $self->{'valid_names'}->{$values[1]}) {
1010 $self->process_assignment_sub($values[1], $values[2]);
1013 $errorString = "Invalid subtraction name: $values[1]";
1017 elsif ($values[0] eq 'component') {
1018 my $comp = $values[1];
1019 my $name = $values[2];
1020 my @inhr = defined $values[3] ? @
{$values[3]} : ();
1021 my $vc = $self->{'valid_components'};
1023 if ($comp ne 'define_custom' && @inhr != 0) {
1024 return 0, "$comp does not allow an inheritance list";
1027 if (defined $$vc{$comp}) {
1028 ($status, $errorString) = $self->parse_components($ih, $comp, $name);
1031 if ($comp eq 'verbatim') {
1032 my($type, $loc, $add) = split(/\s*,\s*/, $name);
1033 ($status, $errorString) = $self->parse_verbatim($ih, $type,
1036 elsif ($comp eq 'specific') {
1037 my $type = $self->matches_specific_scope($name);
1038 if (defined $type) {
1039 ($status, $errorString) = $self->parse_scope(
1041 $self->{'valid_names'},
1042 $self->get_assignment_hash(),
1046 ## We still need to parse the scope, but we will be
1047 ## throwing away whatever is processed. However, it
1048 ## could still be invalid code that will cause an error.
1049 ($status, $errorString) = $self->parse_scope(
1051 $self->{'valid_names'},
1053 $self->get_assignment_hash());
1056 elsif ($comp eq 'define_custom') {
1057 ($status, $errorString) = $self->parse_define_custom($ih, $name, 0,
1060 elsif ($comp eq 'modify_custom') {
1061 ($status, $errorString) = $self->parse_define_custom($ih, $name, 1);
1063 elsif ($comp eq 'expand') {
1064 $self->{'parsing_expand'} = 1;
1065 ($status, $errorString) = $self->parse_scope($ih, $comp, $name, undef);
1066 $self->{'parsing_expand'} = undef;
1069 $errorString = "Invalid component name: $comp";
1074 elsif ($values[0] eq 'feature') {
1075 $self->{'feature_defined'} = 1;
1076 ($status, $errorString) = $self->process_feature($ih,
1079 if ($status && $self->{'feature_defined'}) {
1080 $errorString = "Did not find the end of the feature";
1085 $errorString = "Unrecognized line: $line";
1089 elsif ($status == -1) {
1093 return $status, $errorString;
1097 sub parse_scoped_assignment
{
1098 my($self, $tag, $type, $name, $value, $flags) = @_;
1100 ## Map the assignment name on a scoped assignment
1101 my $mapped = $self->{'valid_names'}->{$name};
1102 if (defined $mapped && UNIVERSAL
::isa
($mapped, 'ARRAY')) {
1103 $name = $$mapped[1];
1106 if (defined $self->{'matching_assignments'}->{$tag} &&
1107 StringProcessor
::fgrep
($name, $self->{'matching_assignments'}->{$tag})) {
1109 if (defined $self->{'flag_overrides'}->{$tag}) {
1110 $over = $self->{'flag_overrides'}->{$tag};
1113 $self->{'flag_overrides'}->{$tag} = $over;
1117 $self->process_assignment($name, $value, $flags);
1119 elsif ($type == 1) {
1120 ## If there is no value in $$flags, then we need to get
1121 ## the outer scope value and put it in there.
1122 if (!defined $self->get_assignment($name, $flags)) {
1123 my $outer = $self->get_assignment($name);
1124 $self->process_assignment($name, $outer, $flags);
1126 $self->process_assignment_add($name, $value, $flags);
1128 elsif ($type == -1) {
1129 ## If there is no value in $$flags, then we need to get
1130 ## the outer scope value and put it in there.
1131 if (!defined $self->get_assignment($name, $flags)) {
1132 my $outer = $self->get_assignment($name);
1133 $self->process_assignment($name, $outer, $flags);
1135 $self->process_assignment_sub($name, $value, $flags);
1144 sub update_template_variable
{
1149 ## Save the addtemp state if we haven't done so before
1150 if (!defined $self->{'addtemp_state'}) {
1151 my %state = $self->save_state('addtemp');
1152 $self->{'addtemp_state'} = \
%state;
1155 ## If the name that is used within a specific is a mapped keyword
1156 ## then we need to translate it into the mapped keyword as it will
1157 ## be used by the TemplateParser.
1159 if ($values[1] =~ /(.*::)(.*)/) {
1161 my $mapped = $self->{'valid_names'}->{$2};
1162 if (defined $mapped && UNIVERSAL
::isa
($mapped, 'ARRAY')) {
1164 $values[1] = $base . 'custom_type->' . $$mapped[1];
1168 ## Now modify the addtemp values
1169 my $atemp = $self->get_addtemp();
1170 $self->information("'$values[1]' was used as a template modifier.");
1172 if ($check && !defined $atemp->{$values[1]}) {
1173 $name = $values[1] if (!defined $name);
1174 if ($name =~ s/.*:://) {
1175 my $value = $self->get_assignment($name);
1176 ## Regardless of whether there was and assignment value, we need to
1177 ## look at the template value of the base so that modification of a
1178 ## scoped variable includes the base values.
1179 if (defined $atemp->{$name}) {
1180 foreach my $arr (@
{$atemp->{$name}}) {
1182 push(@
{$atemp->{$values[1]}}, \
@copy);
1185 unshift(@
{$atemp->{$values[1]}},
1186 [0, $value, undef, $name]) if (defined $value);
1190 ## Subsitute all pseudo variables for the project specific characters.
1191 $values[2] = $self->replace_parameters($values[2], $self->{'command_subs'})
1192 if (index($values[2], '<%') >= 0);
1194 if (defined $atemp->{$values[1]}) {
1195 ## If there are template variable settings, then we need to add
1196 ## this new one to the end of the settings that did not come from
1197 ## the command line. That way, adjust_value() does not need to
1198 ## sort the values (and have knowledge about which came from the
1199 ## command line and which didn't).
1200 my $max = scalar(@
{$atemp->{$values[1]}});
1201 for(my $i = 0; $i < $max; $i++) {
1202 if ($atemp->{$values[1]}->[$i]->[2]) {
1203 splice(@
{$atemp->{$values[1]}}, $i, 0,
1204 [$values[0], $values[2], undef, $name]);
1210 $atemp->{$values[1]} = [];
1213 ## If the variable name is not scoped, we need to look through existing
1214 ## scoped variables that match the base. If we find one, we need to
1215 ## propagate this value into the scoped settings.
1216 if (index($values[1], '::') == -1) {
1217 $name = $values[1] if (!defined $name);
1218 foreach my $key (keys %$atemp) {
1219 if ($key ne $name) {
1220 foreach my $entry (@
{$atemp->{$key}}) {
1221 if (defined $$entry[3] && $$entry[3] eq $name) {
1222 push(@
{$atemp->{$key}}, [$values[0], $values[2], undef, $name]);
1230 ## 0: (0 set, 1 add, -1 subtract)
1231 ## 1: The text value
1232 ## 2: (true set on command line, false set in project)
1233 ## 3: The original variable name if it's scoped or mapped
1234 push(@
{$atemp->{$values[1]}}, [$values[0], $values[2], undef, $name]);
1238 sub handle_unknown_assignment
{
1243 ## Unknown assignments within a 'specific' section are handled as
1244 ## template value modifications. These are handled exactly as the
1245 ## -value_template option in Options.pm.
1247 ## If $type is not defined, then we are skipping this section
1248 $self->update_template_variable(1, @values) if (defined $type);
1254 sub handle_scoped_unknown
{
1255 my($self, $fh, $type, $flags, $line) = @_;
1257 if (defined $type && $self->{'parsing_expand'}) {
1258 if ($type eq $self->get_default_component_name()) {
1259 return 0, 'Can not set expansion in this context';
1262 if (!defined $self->{'expanded'}->{$type}) {
1263 my $undef = $self->replace_env_vars(\
$line);
1265 ## This is a special concession for Windows. It will not allow
1266 ## you to set an empty environment variable. If an empty
1267 ## double quoted string is found, we will assume that the user
1268 ## wanted an empty string.
1269 $line = '' if ($line eq '""');
1271 $self->{'expanded'}->{$type} = $line;
1278 ## If the type is not defined, then this is something other than an
1279 ## assignment in a 'specific' section and should be flagged as an error
1280 return 0, "Unrecognized line: $line";
1283 sub add_custom_depend
{
1284 my($self, $tag, $key, $aref) = @_;
1287 if ($self->{'convert_slashes'}) {
1288 foreach my $dep (@deps) {
1293 $self->{'custom_special_depend'}->{$tag}->{$key} = []
1294 unless defined $self->{'custom_special_depend'}->{$tag}->{$key};
1295 StringProcessor
::merge
($self->{'custom_special_depend'}->{$tag}->{$key},
1299 sub process_component_line
{
1300 my($self, $tag, $line, $fh, $flags,
1301 $grname, $current, $excarr, $comps, $count) = @_;
1307 ## If this returns true, then we've found an assignment
1308 if ($self->parse_assignment($line, \
@values, $fh)) {
1309 $status = $self->parse_scoped_assignment($tag, @values, $flags);
1311 $error = 'Unknown keyword: ' . $values[1];
1315 ## If we successfully remove a '!' from the front, then
1316 ## the file(s) listed are to be excluded
1317 my $rem = ($line =~ s/^\^\s*//);
1318 my $exc = $rem || ($line =~ s/^!\s*//);
1320 ## Convert any $(...) in this line before we process any
1321 ## wild card characters. If we do not, scoped assignments will
1322 ## not work nor will we get the correct wild carded file list.
1323 ## We also need to make sure that any back slashes are converted to
1324 ## slashes to ensure that later flag_overrides checks will happen
1326 $line = $self->relative($line);
1327 $line =~ s/\\/\//g
if ($self->{'convert_slashes'});
1329 ## Now look for specially listed files.
1330 ## Regular expressions are very slow. Searching the line twice with
1331 ## index() is 328 times faster than searching with just the regular
1332 ## expression when it doesn't match (which is likely to be the case).
1333 if ((index($line, '>>') >= 0 || index($line, '<<') >= 0) &&
1334 $line =~ /(.*)\s+(>>|<<)\s+(.*)/) {
1337 my $iop = ($oop eq '>>' ?
'<<' : '>>');
1338 my $out = ($oop eq '>>' ?
$3 : undef);
1339 my $dep = ($oop eq '<<' ?
$3 : undef);
1342 if (index($line, $iop) >= 0 && $line =~ /(.*)\s+$iop\s+(.*)/) {
1344 $out = $2 if ($iop eq '>>');
1345 $dep = $2 if ($iop eq '<<');
1349 ## Check for both possible error conditions
1350 if (index($line, $oop) >= 0) {
1352 $error = "Duplicate $oop used";
1354 elsif (index($line, $iop) >= 0) {
1356 $error = "Duplicate $iop used";
1359 ## Keys used internally to MPC need to be in forward slash format.
1361 $key =~ s/\\/\//g
if ($self->{'convert_slashes'});
1363 if (!defined $self->{'custom_special_output'}->{$tag}) {
1364 $self->{'custom_special_output'}->{$tag} = {};
1366 ## We can not convert slashes here as we do for dependencies
1367 ## (below). The files specified here need to retain the forward
1368 ## slashes as they are used elsewhere.
1369 $self->{'custom_special_output'}->{$tag}->{$key} = $self->create_array($out);
1372 $self->add_custom_depend($tag, $key, $self->create_array($dep));
1376 ## If there is a command helper, we need to add the output files
1377 ## here. It is possible that helper determined output files are
1378 ## the only files added by this component type.
1379 my $cmdHelper = $self->find_command_helper($tag);
1380 if (defined $cmdHelper) {
1382 $key =~ s/\\/\//g
if ($self->{'convert_slashes'});
1383 my $cmdflags = $$flags{'commandflags'};
1384 my($add_out, $deps) = $cmdHelper->get_output($key, $cmdflags);
1386 push(@
{$self->{'custom_special_output'}->{$tag}->{$key}}, @
$add_out);
1387 foreach my $depTag (keys %$deps) {
1388 foreach my $depFile (keys %{$deps->{$depTag}}) {
1389 $self->add_custom_depend($depTag, $depFile,
1390 $deps->{$depTag}->{$depFile});
1395 ## Set up the files array. If the line contains a wild card
1396 ## character use CORE::glob() to get the files specified.
1398 if ($line =~ /^"([^"]+)"$/) {
1401 ## Don't glob the line if we're wanting to remove the file. Wait
1402 ## until later to do the wildcard expansion (in remove_excluded).
1403 elsif (!$rem && $line =~ /[\?\*\[\]]/) {
1404 @files = $self->mpc_glob($line);
1407 push(@files, $line);
1410 ## If we want to remove these files at the end too, then
1411 ## add them to our remove_files hash array.
1413 if (!defined $self->{'remove_files'}->{$tag}) {
1414 $self->{'remove_files'}->{$tag} = {};
1416 foreach my $file (@files) {
1417 $self->{'remove_files'}->{$tag}->{$file} = 1;
1421 ## If we're excluding these files, then put them in the hash
1423 $$grname = $current;
1424 @exclude{@files} = (@files);
1425 push(@
$excarr, @files);
1428 ## Set the flag overrides for each file
1429 my $over = $self->{'flag_overrides'}->{$tag};
1430 if (defined $over) {
1431 foreach my $file (@files) {
1432 ## We are giving these flag overrides to multiple files. We must
1433 ## do so because these files are all in the same group.
1434 $$over{$file} = $flags;
1438 foreach my $file (@files) {
1439 ## Add the file if we're not excluding it
1440 push(@
{$$comps{$current}}, $file) if (!defined $exclude{$file});
1442 ## The user listed a file explicitly, whether we
1443 ## excluded it or not.
1449 return $status, $error;
1453 sub parse_conditional
{
1454 my($self, $fh, $types, $tag, $flags,
1455 $grname, $current, $exclude, $comps, $count) = @_;
1458 my $type = $self->matches_specific_scope($types);
1459 my $add = (defined $type ?
1 : 0);
1462 my $line = $self->preprocess_line($fh, $_);
1466 elsif ($line =~ /^}\s*else\s*{$/) {
1469 elsif ($line =~ /^}$/) {
1473 ($status, $error) = $self->process_component_line(
1474 $tag, $line, $fh, $flags,
1476 $exclude, $comps, $count);
1481 return $status, $error;
1484 sub parse_components
{
1485 my($self, $fh, $tag, $name) = @_;
1486 my $current = $defgroup;
1494 my $custom = defined $self->{'generated_exts'}->{$tag};
1495 my $grtag = $grouped_key . $tag;
1499 ## For the custom scoped assignments, we want to put a copy of
1500 ## the original custom defined values in our flags associative array.
1501 foreach my $key (keys %custom) {
1502 if (defined $self->{'generated_exts'}->{$tag}->{$key}) {
1503 $flags{$key} = $self->{'generated_exts'}->{$tag}->{$key};
1508 if (defined $self->{$tag}) {
1509 $names = $self->{$tag};
1512 $self->{$tag} = $names;
1514 if (defined $$names{$name}) {
1515 $comps = $$names{$name};
1518 $$names{$name} = $comps;
1520 $$comps{$current} = [] if (!defined $$comps{$current});
1523 #tie %$names, "Tie::IxHash";
1524 #tie %$comps, "Tie::IxHash";
1528 my $line = $self->preprocess_line($fh, $_);
1532 elsif ($line =~ /^(\w+)\s*{$/) {
1536 $$comps{$current} = [] if (!defined $$comps{$current});
1540 $error = 'Can not nest groups';
1544 elsif ($line =~ /^conditional\s*(\(([^\)]+)\))\s*{$/) {
1545 ($status, $error) = $self->parse_conditional(
1546 $fh, $2, $tag, \
%flags, \
$grname,
1547 $current, \
@exclude, $comps,
1551 elsif ($line =~ /^}$/) {
1552 if (!defined $$comps{$current}->[0] && !defined $exclude[0]) {
1553 ## The default components name was never used
1554 ## so we remove it from the components
1555 delete $$comps{$current};
1557 ## For custom_only projects, an empty section is functionally
1558 ## equivalent to not defining it at all.
1559 $self->{'defaulted'}->{$tag} = 1
1560 if (!defined $self->{'defaulted'}->{$tag} &&
1561 $self->get_assignment('custom_only'));
1564 ## It was used, so we need to add that name to
1565 ## the set of group names unless it's already been added.
1566 $self->process_assignment_add($grtag, $current);
1568 ## Define the defaulted section value so that if a following
1569 ## empty section of the same type is found, it will not cause the
1570 ## defaulted value to be overwritten.
1571 $self->{'defaulted'}->{$tag} = 0;
1574 $current = $defgroup;
1578 ## We are at the end of a component. If the only group
1579 ## we added was the default group, then we need to remove
1580 ## the group setting altogether.
1581 my $groups = $self->get_assignment($grtag);
1582 if (defined $groups) {
1583 my $grarray = $self->create_array($groups);
1584 if (scalar(@
$grarray) == 1 && $$grarray[0] eq $defgroup) {
1585 $self->process_assignment($grtag, undef);
1589 ## This is not an error,
1590 ## this is the end of the components
1595 ($status, $error) = $self->process_component_line($tag, $line, $fh, \
%flags,
1603 ## If this is a "special" component, we need to see if the
1604 ## user provided all directories. If they have, then we need to
1605 ## store an array of directories that the user supplied. Otherwise,
1606 ## we just store a 1.
1607 if (defined $specialComponents{$tag}) {
1609 foreach my $name (keys %$names) {
1610 my $comps = $$names{$name};
1611 foreach my $comp (keys %$comps) {
1612 foreach my $item (@
{$$comps{$comp}}) {
1623 if (defined $dirs[0]) {
1624 $self->{'special_supplied'}->{$tag} = \
@dirs;
1627 $self->{'special_supplied'}->{$tag} = 1;
1631 ## If we didn't encounter an error, didn't have any files explicitly
1632 ## listed and we attempted to exclude files, then we need to find the
1633 ## set of files that don't match the excluded files and add them.
1634 if ($status && defined $exclude[0] && defined $grname) {
1635 my $alldir = $self->get_assignment('recurse') || $flags{'recurse'};
1638 foreach my $exc (@exclude) {
1639 my $dname = $self->mpc_dirname($exc);
1640 if (!defined $checked{$dname}) {
1641 $checked{$dname} = 1;
1642 push(@files, $self->generate_default_file_list($dname,
1648 $self->sift_files(\
@files,
1649 $self->{'valid_components'}->{$tag},
1650 $self->get_assignment('pch_header'),
1651 $self->get_assignment('pch_source'),
1656 return $status, $error;
1660 sub parse_verbatim
{
1661 my($self, $fh, $type, $loc, $add) = @_;
1663 if (!defined $loc) {
1664 return 0, 'You must provide a location parameter to verbatim';
1667 ## All types are lower case
1670 if (!defined $self->{'verbatim'}->{$type}) {
1671 $self->{'verbatim'}->{$type} = {};
1674 ## Instead of always creating a new array for a particular type and
1675 ## location, create a new array if there isn't one already or the user
1676 ## does not want to add to the existing verbatim settings.
1677 $self->{'verbatim'}->{$type}->{$loc} = []
1678 if (!$add || !defined $self->{'verbatim'}->{$type}->{$loc});
1679 my $array = $self->{'verbatim'}->{$type}->{$loc};
1682 my $line = $self->preprocess_line($fh, $_);
1684 ## This is not an error,
1685 ## this is the end of the verbatim
1686 last if ($line =~ /^}$/);
1687 push(@
$array, $line);
1694 sub process_feature
{
1695 my($self, $fh, $names, $parents) = @_;
1701 foreach my $name (@
$names) {
1702 if ($name =~ /^!\s*(.*)$/) {
1703 $avoids .= ' ' if ($avoids ne '');
1707 $requires .= ' ' if ($requires ne '');
1712 if ($self->check_features($requires, $avoids)) {
1713 ## The required features are enabled, so we say that
1714 ## a project has been defined and we allow the parser to
1715 ## find the data held within the feature.
1716 ($status, $error) = $self->begin_project($parents);
1718 $self->{'feature_defined'} = 0;
1719 $self->{$self->{'type_check'}} = 1;
1723 ## Otherwise, we read in all the lines until we find the
1724 ## closing brace for the feature and it appears to the parser
1725 ## that nothing was defined.
1728 my $line = $self->preprocess_line($fh, $_);
1730 ## This is a very simplistic way of finding the end of
1731 ## the feature definition. It will work as long as no spurious
1732 ## open curly braces are counted.
1733 ++$curly if ($line =~ /{$/);
1734 --$curly if ($line =~ /^}/);
1737 $self->{'feature_defined'} = 0;
1743 return $status, $error;
1747 sub process_array_assignment
{
1748 my($self, $aref, $type, $array) = @_;
1750 if (!defined $$aref || $type == 0) {
1757 push(@
{$$aref}, @
$array);
1759 elsif ($type == -1) {
1760 my $count = scalar(@
{$$aref});
1761 for(my $i = 0; $i < $count; ++$i) {
1762 if (StringProcessor
::fgrep
($$aref->[$i], $array)) {
1763 splice(@
{$$aref}, $i, 1);
1773 sub parse_define_custom
{
1774 my($self, $fh, $tag, $modify, $parentsRef) = @_;
1776 ## Make the tag something _files
1777 $tag = lc($tag) . '_files';
1779 ## We can not have a custom type named "generic"
1780 return 0, "$tag is reserved" if ($tag eq $generic_key);
1782 if (defined $self->{'valid_components'}->{$tag}) {
1784 return 0, "$tag has already been defined";
1788 return 0, "$tag has not yet been defined and can not be modified";
1791 if (defined $parentsRef && @
$parentsRef > 0) {
1792 if (@
$parentsRef > 1) {
1793 return 0, "$tag: multiple inheritance is not allowed";
1795 my $parent = lc($$parentsRef[0]) . '_files';
1796 if (!defined $self->{'valid_components'}->{$parent}) {
1797 return 0, "$parent is not a valid custom file type";
1799 for my $k ('matching_assignments', 'generated_exts', 'valid_components') {
1800 $self->{$k}->{$tag} = $self->clone($self->{$k}->{$parent});
1802 $self->{'define_custom_parent'}->{$tag} = $parent;
1806 my $errorString = "Unable to process $tag";
1808 ## Update the custom_types assignment
1809 $self->process_assignment_add('custom_types', $tag) if (!$modify);
1811 if (!defined $self->{'matching_assignments'}->{$tag}) {
1812 my @keys = keys %custom;
1813 push(@keys, @default_matching_assignments);
1814 $self->{'matching_assignments'}->{$tag} = \
@keys;
1820 my $line = $self->preprocess_line($fh, $_);
1824 elsif ($line =~ /optional\s*\(([^\)]+)\)\s*{/) {
1826 $optname =~ s/^\s+//;
1827 $optname =~ s/\s+$//;
1828 if (defined $customDefined{$optname} &&
1829 ($customDefined{$optname} & 0x08) != 0) {
1831 if ($inscope != 1) {
1833 $errorString = 'Can not nest \'optional\' sections';
1839 $errorString = "Invalid optional name: $optname";
1844 if ($line =~ /^}$/) {
1849 if ($line =~ /(\w+)\s*\(([^\)]+)\)\s*(\+)?=\s*(.*)/) {
1853 my @val = split(/\s*,\s*/, $4);
1856 $opt =~ s/(\&\&|\|\|)/ $1 /g;
1859 ## Set up the 'optional' hash table
1860 if (!$add || !defined $self->{'generated_exts'}->{$tag}->
1861 {'optional'}->{$optname}->{$name}->{$opt}) {
1862 $self->{'generated_exts'}->{$tag}->
1863 {'optional'}->{$optname}->{$name}->{$opt} = \
@val;
1866 push(@
{$self->{'generated_exts'}->{$tag}->{'optional'}->
1867 {$optname}->{$name}->{$opt}}, @val);
1872 $errorString = "Unrecognized optional line: $line";
1877 elsif ($line =~ /^}$/) {
1879 $errorString = undef;
1881 ## Propagate the custom defined values into the mapped values
1882 foreach my $key (keys %{$self->{'valid_names'}}) {
1883 if (UNIVERSAL
::isa
($self->{'valid_names'}->{$key}, 'ARRAY')) {
1884 my $value = $self->{'generated_exts'}->{$tag}->{
1885 $self->{'valid_names'}->{$key}->[1]};
1887 ## Bypass the process_assignment() defined in this class
1888 ## to avoid unwanted keyword mapping.
1889 $self->SUPER::process_assignment
($key, $value) if (defined $value);
1893 ## Set some defaults (if they haven't already been set)
1894 if (!defined $self->{'generated_exts'}->{$tag}->{'pre_filename'}) {
1895 $self->{'generated_exts'}->{$tag}->{'pre_filename'} = [ '' ];
1897 if (!defined $self->{'generated_exts'}->{$tag}->{'pre_dirname'}) {
1898 $self->{'generated_exts'}->{$tag}->{'pre_dirname'} = [ '' ];
1900 if (!defined $self->{'generated_exts'}->{$tag}->{'pre_extension'}) {
1901 $self->{'generated_exts'}->{$tag}->{'pre_extension'} = [ '' ];
1903 if (!defined $self->{'generated_exts'}->{$tag}->{'automatic_in'}) {
1904 $self->{'generated_exts'}->{$tag}->{'automatic_in'} = 1;
1906 if (!defined $self->{'generated_exts'}->{$tag}->{'automatic_out'}) {
1907 $self->{'generated_exts'}->{$tag}->{'automatic_out'} = 1;
1909 if (!defined $self->{'generated_exts'}->{$tag}->{'output_follows_input'}) {
1910 $self->{'generated_exts'}->{$tag}->{'output_follows_input'} = 1;
1912 if (!defined $self->{'valid_components'}->{$tag}) {
1913 $self->{'valid_components'}->{$tag} = [];
1919 ## If this returns true, then we've found an assignment
1920 if ($self->parse_assignment($line, \
@values, $fh)) {
1921 my($type, $name, $value) = @values;
1922 ## The 'automatic' keyword has always contained two distinct
1923 ## functions. The first is to automatically add input files of
1924 ## the specified extension. And the second is to automatically
1925 ## add generated files to the right components. It has now been
1926 ## split into separate functionality and we map the 'automatic'
1927 ## keyword to the two new ones here.
1929 my @names = $name eq 'automatic' ?
1930 ('automatic_in', 'automatic_out') : $name;
1931 foreach $name (@names) {
1932 if (defined $customDefined{$name}) {
1933 if (($customDefined{$name} & 0x01) != 0) {
1934 $value = $self->escape_regex_special($value);
1935 my @array = split(/\s*,\s*/, $value);
1936 $self->process_array_assignment(
1937 \
$self->{'valid_components'}->{$tag}, $type, \
@array);
1940 if (!defined $self->{'generated_exts'}->{$tag}) {
1941 $self->{'generated_exts'}->{$tag} = {};
1943 ## Try to convert the value into a relative path
1944 $value = $self->relative($value);
1946 if (($customDefined{$name} & 0x04) != 0) {
1948 $self->process_assignment(
1950 $self->{'generated_exts'}->{$tag});
1952 elsif ($type == 1) {
1953 $self->process_assignment_add(
1955 $self->{'generated_exts'}->{$tag});
1957 elsif ($type == -1) {
1958 $self->process_assignment_sub(
1960 $self->{'generated_exts'}->{$tag});
1964 if (($customDefined{$name} & 0x02) != 0) {
1965 ## Transform the name from something outputext to
1966 ## something files. We expect this to match the
1967 ## names of valid_assignments.
1968 $name =~ s/outputext/files/g;
1971 ## Get it ready for regular expressions
1972 $value = $self->escape_regex_special($value);
1974 ## Split the value into an array using a comma as the
1975 ## separator. If there are no elements in the array we're
1976 ## going to add an empty element to the array. This way,
1977 ## assignments of blank values are useful.
1978 my @array = split(/\s*,\s*/, $value);
1979 push(@array, '') if ($#array == -1);
1981 ## Process the array assignment after adjusting the values
1982 $self->process_array_assignment(
1983 \
$self->{'generated_exts'}->{$tag}->{$name},
1991 $errorString = "Invalid assignment name: '$name'";
1996 ## $status is zero until the end of the define custom block, so
1997 ## we can't use it for this check.
2000 elsif ($line =~ /^keyword\s+(\w+)(?:\s*=\s*(\w+)?)?/) {
2001 ## Check for keyword mapping here
2004 if (defined $self->{'valid_names'}->{$newkey}) {
2006 $errorString = "Cannot map $newkey onto an " .
2010 elsif (!defined $mapkey) {
2011 $self->{'valid_names'}->{$newkey} = 1;
2013 elsif ($newkey ne $mapkey) {
2014 if (defined $customDefined{$mapkey}) {
2015 $self->{'valid_names'}->{$newkey} = [ $tag, $mapkey ];
2019 $errorString = "Cannot map $newkey to an " .
2020 "undefined custom keyword: $mapkey";
2026 $errorString = "Cannot map $newkey to $mapkey";
2032 $errorString = "Unrecognized line: $line";
2038 return $status, $errorString;
2042 sub back_to_variable
{
2043 my($self, $values) = @_;
2044 my $cwd = $self->getcwd();
2045 my $case_tolerant = $self->case_insensitive();
2048 ## Get both of the relative value hash maps and put them in an array
2050 my($rel, $how) = $self->get_initial_relative_values();
2052 ($rel, $how) = $self->get_secondary_relative_values();
2055 ## Go through each value and try to convert it to a variable setting
2056 foreach my $ovalue (@
$values) {
2057 ## Fix up the value, replacing '.' with the current working
2059 my $value = $ovalue;
2060 $value =~ s/\\/\//g
;
2061 if ($value eq '.') {
2065 $value =~ s/^.\//$cwd\
//;
2067 my $valuelen = length($value);
2069 ## Go through each relative value hash map and see if any of the
2070 ## values match the value that we're currently inspecting.
2072 foreach my $rel (@rels) {
2073 foreach my $key (keys %$rel) {
2074 ## Get the relative replacement value and convert back-slashes
2075 my $val = $$rel{$key};
2078 ## We only need to check for reverse replacement if the length
2079 ## of the value is greater than or equal to the length of our
2080 ## replacement value.
2081 my $vlen = length($val);
2082 if ($valuelen >= $vlen) {
2083 ## Cut the string down by the length of the replacement value
2084 my $lval = substr($value, 0, $vlen);
2086 ## Check for equivalence, taking into account file system
2087 ## case-insenitivity.
2088 if ($case_tolerant) {
2089 $found = (lc($lval) eq lc($val));
2092 $found = ($lval eq $val);
2095 ## If they match, replace the value and save it in our array.
2097 substr($value, 0, length($val)) = "\$($key)";
2098 push(@values, $value);
2104 ## Once it's been found, there's no reason to continue on through
2105 ## the relative hash maps.
2109 push(@values, $ovalue) if (!$found);
2116 sub remove_duplicate_addition
{
2117 my($self, $name, $value, $nval) = @_;
2119 if (defined $nval) {
2120 ## If we are modifying the libs, libpaths, macros or includes
2121 ## assignment with either addition or subtraction, we are going to
2122 ## perform a little fix on the value to avoid multiple
2123 ## libraries and to try to insure the correct linking order
2124 if ($name eq 'macros' || $name eq 'libpaths' ||
2125 $name eq 'includes' || $name =~ /libs$/ ||
2126 index($name, $grouped_key) == 0) {
2130 ## Convert the array into keys for a hash table
2131 @parts{@
{$self->create_array($nval)}} = ();
2133 ## In order to ensure that duplicates are correctly removed, we
2134 ## need to get the modified assignment value before we attempt to
2136 $value = $self->modify_assignment_value($name, $value);
2137 foreach my $val (@
{$self->create_array($value)}) {
2138 if (!exists $parts{$val}) {
2139 ## We need to supply quotes if there is a space in the value or
2140 ## a variable. The variable may contain spaces.
2141 if ($val =~ /\s/ || $val =~ /\$\(.+\)/) {
2142 ## If we're going to add quotes around this item and the
2143 ## value ends in a backslash we need to append another
2144 ## backslash so that when it's used with
2145 ## StringProcessor::create_array() the function will not think
2146 ## that the trailing quote is escaped.
2147 $val .= '\\' if ($val =~ /\\$/);
2148 $allowed .= '"' . $val . '" ';
2151 $allowed .= $val . ' ';
2155 $allowed =~ s/\s+$//;
2164 sub read_template_input
{
2165 my($self, $tkey) = @_;
2170 my $ti = $self->get_ti_override();
2171 my $lang = $self->get_language();
2174 if ($self->exe_target()) {
2175 if ($self->get_static() == 1) {
2176 $tag = 'lib_exe_template_input';
2177 ## Check for the TemplateInputReader for the template key provided.
2178 if (!defined $self->{$tag}->{$lang}->{$tkey}) {
2179 if (defined $$ti{'lib_exe'}) {
2180 $file = $$ti{'lib_exe'};
2184 $file = $self->get_lib_exe_template_input_file($tkey);
2189 $tag = 'dll_exe_template_input';
2190 ## Check for the TemplateInputReader for the template key provided.
2191 if (!defined $self->{$tag}->{$lang}->{$tkey}) {
2192 if (defined $$ti{'dll_exe'}) {
2193 $file = $$ti{'dll_exe'};
2197 $file = $self->get_dll_exe_template_input_file($tkey);
2203 if ($self->get_static() == 1) {
2204 $tag = 'lib_template_input';
2205 ## Check for the TemplateInputReader for the template key provided.
2206 if (!defined $self->{$tag}->{$lang}->{$tkey}) {
2207 if (defined $$ti{'lib'}) {
2208 $file = $$ti{'lib'};
2212 $file = $self->get_lib_template_input_file($tkey);
2217 $tag = 'dll_template_input';
2218 ## Check for the TemplateInputReader for the template key provided.
2219 if (!defined $self->{$tag}->{$lang}->{$tkey}) {
2220 if (defined $$ti{'dll'}) {
2221 $file = $$ti{'dll'};
2225 $file = $self->get_dll_template_input_file($tkey);
2231 if (defined $self->{$tag}->{$lang}->{$tkey}) {
2232 ## We have a TemplateInputReader for this template key, so we need
2233 ## to set the entry corresponding to $tikey to it for use in the
2234 ## get_template_input() method.
2235 $self->{$tag}->{$lang}->{$tikey} = $self->{$tag}->{$lang}->{$tkey};
2238 ## We haven't read this file yet, so we will create the template
2239 ## input reader and store it in the entry for the template key
2240 ## ($tkey) and the template input key ($tikey).
2241 my $ti = new TemplateInputReader
($self->get_include_path());
2242 $self->{$tag}->{$lang}->{$tkey} = $ti;
2243 $self->{$tag}->{$lang}->{$tikey} = $ti;
2245 ## Process the template input file
2246 if (defined $file) {
2247 my $tfile = $self->search_include_path("$file.$TemplateInputExtension");
2248 if (defined $tfile) {
2249 ($status, $errorString) = $ti->read_file($tfile);
2252 ## Not finding a template input file is only an error if the user
2253 ## specifically provided a template input file override.
2256 $errorString = "Unable to locate template input file: $file";
2261 ## Now that we've read in the template input file, set up our
2262 ## automatic template variables.
2263 if ($self->{'make_coexistence'}) {
2264 $ti->parse_line(undef,
2265 "make_coexistence = $self->{'make_coexistence'}");
2269 ## We do this regardless of whether or not this parser is cached or
2270 ## not. If the features have changed (through a workspace cmdline
2271 ## setting), we need to reflect it.
2273 ## Put the features into the template input set
2274 my $features = $self->{'feature_parser'}->get_names();
2275 $self->{$tag}->{$lang}->{$tikey}->parse_line(undef,
2276 "features = @$features");
2279 return $status, $errorString;
2284 my($self, $array, $name) = @_;
2285 my $case_tolerant = $self->case_insensitive();
2287 ## This method expects that the file name will be unix style
2288 $name =~ s/\\/\//g
if ($self->{'convert_slashes'});
2290 ## Remove the leading ./
2292 my $dsname = "./$name";
2294 ## Take into account file system case-insenitivity.
2295 if ($case_tolerant) {
2297 $dsname = lc($dsname);
2300 foreach my $file (@
$array) {
2301 my $my_file = ($case_tolerant ?
lc($file) : $file);
2303 return 1 if ($my_file eq $name || $my_file eq $dsname);
2310 sub get_applied_custom_keyword
{
2311 my($self, $name, $type, $file) = @_;
2313 if (defined $self->{'flag_overrides'}->{$type} &&
2314 defined $self->{'flag_overrides'}->{$type}->{$file} &&
2315 defined $self->{'flag_overrides'}->{$type}->{$file}->{$name}) {
2316 return $self->relative(
2317 $self->{'flag_overrides'}->{$type}->{$file}->{$name}, 1);
2320 return $self->relative($self->get_assignment(
2322 $self->{'generated_exts'}->{$type}), 1);
2326 sub evaluate_optional_option
{
2327 my($self, $opt, $value) = @_;
2329 if ($opt =~ /^!\s*(.*)/) {
2330 return (!exists $$value{$1} ?
1 : 0);
2333 return (exists $$value{$opt} ?
1 : 0);
2338 sub process_optional_option
{
2339 my($self, $opt, $value) = @_;
2341 my @parts = grep(!/^$/, split(/\s+/, $opt));
2342 my $pcount = scalar(@parts);
2344 for(my $i = 0; $i < $pcount; $i++) {
2345 if ($parts[$i] eq '&&' || $parts[$i] eq '||') {
2346 if (defined $status) {
2347 if (defined $parts[$i + 1]) {
2348 if ($parts[$i] eq '&&') {
2349 $status &&= $self->evaluate_optional_option($parts[$i + 1],
2353 ## We are coming into an '||', if status is already true
2354 ## then we can leave immediately
2357 $status ||= $self->evaluate_optional_option($parts[$i + 1],
2362 $self->warning("Expected token in optional after $parts[$i]");
2366 $self->warning("Unexpected token in optional: $parts[$i]");
2371 if (!defined $status) {
2372 $status = $self->evaluate_optional_option($parts[$i], $value);
2375 $self->warning("Unexpected token in optional: $parts[$i]");
2384 sub add_optional_filename_portion
{
2385 my($self, $gentype, $tag, $file, $array) = @_;
2387 if (defined $self->{'generated_exts'}->{$gentype}->{'optional'}->{$tag}) {
2388 foreach my $name (keys %{$self->{'generated_exts'}->{$gentype}->{'optional'}->{$tag}}) {
2389 foreach my $opt (keys %{$self->{'generated_exts'}->{$gentype}->{'optional'}->{$tag}->{$name}}) {
2390 ## Get the name value
2391 my $value = $self->get_applied_custom_keyword($name,
2394 ## Convert the value into a hash map for easy lookup
2396 @values{split(/\s+/, $value)} = () if (defined $value);
2398 ## See if the option or options are contained in the value. We
2399 ## need to call this even if $value is not defined due to the
2400 ## ability to negate optional parameters.
2401 if ($self->process_optional_option($opt, \
%values)) {
2402 ## Add the optional portion
2403 push(@
$array, @
{$self->{'generated_exts'}->{$gentype}->{'optional'}->{$tag}->{$name}->{$opt}});
2411 sub get_pre_keyword_array
{
2412 my($self, $keyword, $gentype, $tag, $file) = @_;
2414 ## Get the general pre extension array.
2415 ## $self->{'generated_exts'}->{$gentype}->{$keyword} is guaranteed to
2416 ## be defined due to the defaulting that is done in
2417 ## parse_define_custom() and the only three calls to this method use
2418 ## valid $keyword values.
2419 my @array = @
{$self->{'generated_exts'}->{$gentype}->{$keyword}};
2421 ## Add the component specific pre extension array
2423 $tag =~ s/files$/$keyword/;
2424 if (defined $self->{'generated_exts'}->{$gentype}->{$tag}) {
2425 push(@additional, @
{$self->{'generated_exts'}->{$gentype}->{$tag}});
2428 ## Add in any optional portion to the array
2429 foreach my $itag ($keyword, $tag) {
2430 $self->add_optional_filename_portion($gentype, $itag,
2431 $file, \
@additional);
2434 ## If the current array only has the default,
2435 ## then we need to remove it
2436 if (defined $additional[0]) {
2437 if ($#array == 0 && $array[0] eq '') {
2440 push(@array, @additional);
2447 sub add_explicit_output
{
2448 my($self, $file, $type, $tag, $array, $arrs) = @_;
2450 if (defined $self->{'custom_special_output'}->{$type} &&
2451 defined $self->{'custom_special_output'}->{$type}->{$file}) {
2452 if (defined $self->{'valid_components'}->{$tag}) {
2454 foreach my $check (@
{$self->{'custom_special_output'}->{$type}->{$file}}) {
2455 foreach my $regext (@
{$self->{'valid_components'}->{$tag}}) {
2456 if ($check =~ /$regext$/) {
2458 if ($tag eq 'source_files') {
2459 foreach my $tregext (@
{$self->{'valid_components'}->{'template_files'}}) {
2460 if ($check =~ /$tregext$/) {
2467 ## If gendir was specified, then we need to account for that
2469 if (defined $self->{'flag_overrides'}->{$type} &&
2470 defined $self->{'flag_overrides'}->{$type}->{$file} &&
2471 defined $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} &&
2472 $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} ne '.') {
2473 $dir = $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} . '/';
2474 $dir =~ s/\\/\//g
if ($self->{'convert_slashes'});
2477 push(@files, "$dir$check");
2483 if (defined $files[0]) {
2485 push(@
$array, \
@files);
2488 push(@
$array, @files);
2495 sub generated_filenames
{
2496 my($self, $part, $type, $tag, $file, $noext, $arrs) = @_;
2497 ## $part - The full path of the input file minus the extension
2498 ## $type - The input file type (e.g., 'java_files')
2499 ## $file - The full path of the input file
2500 ## $noext - bool indicating an inverse need for an extension
2501 ## $arrs - bool indicating that the return array should be made of arrays
2503 ## A custom type is not allowed to generate it's own input files
2504 return () if ($type eq $tag);
2506 ## See if the type for which we are generating ($tag) is also a custom
2507 ## file type. If it is, we need to do some massaging.
2509 if (defined $self->{'generated_exts'}->{$tag}) {
2510 ## If the custom type ($type) doesn't specify that it generates
2511 ## generic files, we need to see if there is a command helper for
2512 ## this type and see what sort of output it knows about.
2513 my $inputexts = $self->{'generated_exts'}->{$type}->{$generic_key};
2514 if (!defined $inputexts) {
2515 my $cmdHelper = $self->find_command_helper($type);
2516 $inputexts = $cmdHelper->get_outputexts() if (defined $cmdHelper);
2519 ## We will need to use 'generic_files' instead of $tag if $tag is
2520 ## defined in 'generated_exts', but only for the type that will
2521 ## actually generate the right type of generic file.
2523 if (defined $inputexts) {
2524 foreach my $inputext (@
$inputexts) {
2525 my $ext = $inputext;
2527 foreach my $extreg (@
{$self->{'valid_components'}->{$tag}}) {
2528 if ($ext =~ /$extreg$/) {
2529 $tag = $generic_key;
2538 ## If we were not able to find the right file type, then we can get
2539 ## out early. However, if the type for which we are generating
2540 ## ($tag) is a built-in type, we need to continue on as there is a
2541 ## possibility that the input type ($type) will generate files for
2542 ## the generating type.
2543 return () if (!$good &&
2544 !defined $language{$self->get_language()}->[0]->{$tag});
2547 my @pearr = $self->get_pre_keyword_array('pre_extension',
2548 $type, $tag, $file);
2549 my @pfarr = $self->get_pre_keyword_array('pre_filename',
2550 $type, $tag, $file);
2551 my @pdarr = $self->get_pre_keyword_array('pre_dirname',
2552 $type, $tag, $file);
2553 my @exts = (defined $self->{'generated_exts'}->{$type}->{$tag} ?
2554 @
{$self->{'generated_exts'}->{$type}->{$tag}} : ());
2556 if (!defined $exts[0]) {
2558 if ($backtag =~ s/files$/outputext/) {
2559 $self->add_optional_filename_portion($type, $backtag,
2565 if (!defined $exts[0] && $#pearr == 0 && $#pfarr == 0 && $#pdarr == 0 &&
2566 $pearr[0] eq '' && $pfarr[0] eq '' && $pdarr[0] eq '') {
2567 ## If both arrays are defined to be the defaults, then there
2568 ## is nothing for us to do.
2574 ## Correctly deal with pre filename and directories
2575 if ($part =~ /(.*[\/\\])([^\
/\\]+)$/) {
2576 ## Split the directory and base name of the file. Only set the
2577 ## directory if the output follows the input directory.
2579 if ($self->{'generated_exts'}->{$type}->{'output_follows_input'});
2586 ## If gendir was specified, then we need to account for that
2587 if (defined $self->{'flag_overrides'}->{$type} &&
2588 defined $self->{'flag_overrides'}->{$type}->{$file} &&
2589 defined $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'}) {
2590 if ($self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} eq '.') {
2594 $dir = $self->{'flag_overrides'}->{$type}->{$file}->{'gendir'} . '/';
2595 $dir =~ s/\\/\//g
if ($self->{'convert_slashes'});
2599 ## Loop through creating all of the possible file names
2600 foreach my $pe (@pearr) {
2603 foreach my $pf (@pfarr) {
2605 foreach my $pd (@pdarr) {
2607 push(@genfile, "$pd$dir$pf$base$pe");
2610 foreach my $ext (@exts) {
2612 push(@genfile, "$pd$dir$pf$base$pe$ext");
2618 push(@array, \
@genfile);
2621 push(@array, @genfile);
2626 ## Now add the explicit output. We need to use the original tag value
2627 ## ($otag) so that we can find the custom output files.
2628 $self->add_explicit_output($file, $type, $otag, \
@array, $arrs);
2633 sub add_generated_files
{
2634 my($self, $gentype, $tag, $group, $arr) = @_;
2636 ## This method is called by list_default_generated. It performs the
2637 ## actual file insertion and grouping.
2638 ## Get the generated filenames
2640 foreach my $file (keys %$arr) {
2641 foreach my $gen ($self->generated_filenames($$arr{$file}, $gentype,
2643 $self->list_generated_file($gentype, $tag, \
@added, $gen, $$arr{$file});
2647 if (defined $added[0]) {
2648 my $names = $self->{$tag};
2650 ## Get all files in one list and save the directory
2651 ## and component group in a hashed array.
2654 foreach my $name (keys %$names) {
2655 foreach my $key (keys %{$$names{$name}}) {
2656 push(@all, @
{$$names{$name}->{$key}});
2657 foreach my $file (@
{$$names{$name}->{$key}}) {
2658 $dircomp{$self->mpc_dirname($file)} = $key;
2663 ## Create a small array of only the files we want to add.
2664 ## We put them all together so we can keep them in order when
2665 ## we put them at the front of the main file list.
2667 foreach my $file (@added) {
2668 push(@oktoadd, $file) if (!$self->already_added(\
@all, $file));
2671 ## If we have files to add, make sure we add them to a group
2672 ## that has the same directory location as the files we're adding.
2673 if (defined $oktoadd[0]) {
2674 my $key = (defined $group ?
$group :
2675 $dircomp{$self->mpc_dirname($oktoadd[0])});
2676 if (!defined $key) {
2677 my $check = $oktoadd[0];
2678 foreach my $regext (@
{$self->{'valid_components'}->{$tag}}) {
2679 last if ($check =~ s/$regext$//);
2681 foreach my $vc (keys %{$self->{'valid_components'}}) {
2682 ## If this component name does not match the component name for
2683 ## which we are adding files and there are components defined
2684 ## for it, we will look to see if we can find a matching group
2685 ## name. We have to make sure that we do not use the hash map
2686 ## ($self->{$vc}) unless it's defined. Doing so will
2687 ## automatically create the map and that will cause MPC to
2688 ## think that the user provided the empty setting (when it
2690 if ($vc ne $tag && defined $self->{$vc}) {
2691 foreach my $name (keys %{$self->{$vc}}) {
2692 foreach my $ckey (keys %{$self->{$vc}->{$name}}) {
2693 if ($ckey ne $defgroup) {
2694 foreach my $ofile (@
{$self->{$vc}->{$name}->{$ckey}}) {
2696 foreach my $regext (@
{$self->{'valid_components'}->{$vc}}) {
2697 last if ($file =~ s/$regext$//);
2699 if ($file eq $check) {
2705 last if (defined $key);
2708 last if (defined $key);
2711 $key = $defgroup if (!defined $key);
2713 foreach my $name (keys %$names) {
2714 if (!defined $$names{$name}->{$key}) {
2715 if ($key ne $defgroup &&
2716 defined $$names{$name}->{$defgroup} &&
2717 defined $$names{$name}->{$defgroup}->[0]) {
2718 $self->process_assignment_add($grouped_key . $tag, $defgroup);
2720 $$names{$name}->{$key} = [];
2721 $self->process_assignment_add($grouped_key . $tag, $key);
2723 unshift(@
{$$names{$name}->{$key}}, @oktoadd);
2730 sub search_for_entry
{
2731 my($self, $file, $marray, $preproc) = @_;
2733 my $fh = new FileHandle
();
2735 if (open($fh, $file)) {
2740 ## Remove c++ style comments
2741 $_ =~ s/\/\/.*// if (!$commented);
2743 ## Remove one line c style comments
2744 $_ =~ s/\/\*.*\*\///g;
2748 ## Found the end of a multi-line c style comment
2754 ## Found the beginning of a multi-line c style comment
2758 ## If the current language supports a c preprocessor, we
2759 ## will perform a minimal check for #if 0
2761 ## Found the beginning of a #if 0
2764 elsif ($poundifed) {
2766 ## We need to keep track of any other #if directives
2767 ## to be sure that when we see an #endif we don't
2768 ## count the wrong one.
2771 elsif (/#\s*endif/) {
2772 ## Found a #endif, so decrement our count
2779 ## Check for main; Make sure it's not #if 0'ed and not commented out
2780 if (!$poundifed && !$commented) {
2782 foreach my $main (@
$marray) {
2783 if (/\s+$main\s*\(/ || /^\s*$main\s*\(/) {
2784 ## If we've found a main, set the exename to the basename
2785 ## of the cpp file with the extension removed
2786 $name = $self->mpc_basename($file);
2787 $name =~ s/\.[^\.]+$//;
2801 sub find_main_file
{
2802 my($self, $sources) = @_;
2803 my $lang = $self->get_language();
2804 my @main = $language{$lang}->[3];
2805 my $preproc = $language{$lang}->[4];
2807 ## If additional main's have been supplied by the user for this
2808 ## language type, then just push them onto the array.
2809 push(@main, @
{$mains{$lang}}) if (defined $mains{$lang});
2811 ## Now search each source file until we've found a main function.
2812 foreach my $file (@
$sources) {
2813 my $exename = $self->search_for_entry($file, \
@main, $preproc);
2814 return $exename if (defined $exename);
2821 sub generate_default_target_names
{
2824 ## If this is a custom_only project, we need not waste time setting the
2825 ## sharedname, staticname or exename. Searching all of the files for a
2826 ## main function is very time consuming and unnecessary.
2827 return undef if ($self->get_assignment('custom_only'));
2829 if (!$self->exe_target()) {
2830 my $sharedname = $self->get_assignment('sharedname');
2831 my $staticname = $self->get_assignment('staticname');
2834 if (defined $sharedname) {
2835 if ($sharedname eq '') {
2837 $sharedname = undef;
2838 $self->process_assignment('sharedname', $sharedname);
2840 elsif (!defined $staticname) {
2841 $staticname = $sharedname;
2842 $self->process_assignment('staticname', $staticname);
2845 if (defined $staticname && !$shared_empty && !defined $sharedname) {
2846 $sharedname = $staticname;
2847 $self->process_assignment('sharedname', $sharedname);
2850 ## If it's neither an exe or library target, we will search
2851 ## through the source files for a main()
2852 if (!$self->lib_target()) {
2853 ## Set the exename assignment
2854 my @sources = $self->get_component_list('source_files', 1);
2855 my $exename = $self->find_main_file(\
@sources);
2856 $self->process_assignment('exename', $exename) if (defined $exename);
2858 ## If we still don't have a project type, then we will
2859 ## default to a library if there are source or resource files
2860 if (!defined $exename) {
2861 if (!defined $sources[0]) {
2862 @sources = $self->get_component_list($self->get_resource_tag(), 1);
2864 if (defined $sources[0]) {
2865 if (!$shared_empty) {
2866 $self->process_assignment('sharedname',
2867 $self->{'unmodified_project_name'});
2869 $self->process_assignment('staticname',
2870 $self->{'unmodified_project_name'});
2876 ## If we are generating only static projects, then we need to
2877 ## unset the sharedname, so that we can insure that projects of
2878 ## various types only generate static targets.
2879 if ($self->get_static() == 1) {
2880 my $sharedname = $self->get_assignment('sharedname');
2881 if (defined $sharedname) {
2882 $self->process_assignment('sharedname', undef);
2886 ## Check for the use of an asterisk in the name
2887 foreach my $key ('exename', 'sharedname', 'staticname') {
2888 my $value = $self->get_assignment($key);
2889 if (defined $value && index($value, '*') >= 0) {
2890 $value = $self->fill_type_name($value,
2891 $self->{'unmodified_project_name'});
2892 $self->process_assignment($key, $value);
2898 sub generate_default_pch_filenames
{
2899 my($self, $files) = @_;
2900 my $pchhdef = (defined $self->get_assignment('pch_header'));
2901 my $pchcdef = (defined $self->get_assignment('pch_source'));
2903 if (!$pchhdef || !$pchcdef) {
2904 my $pname = $self->get_assignment('project_name');
2909 foreach my $file (@
$files) {
2910 ## If the file doesn't even contain _pch, then there's no point
2911 ## in looping through all of the extensions
2912 if (index($file, '_pch') >= 0) {
2914 foreach my $ext (@
{$self->{'valid_components'}->{'header_files'}}) {
2915 if ($file =~ /(.*_pch$ext)$/) {
2916 $self->process_assignment('pch_header', $1);
2918 $hmatching = $file if (index($file, $pname) >= 0);
2924 foreach my $ext (@
{$self->{'valid_components'}->{'source_files'}}) {
2925 if ($file =~ /(.*_pch$ext)$/) {
2926 $self->process_assignment('pch_source', $1);
2928 $cmatching = $file if (index($file, $pname) >= 0);
2935 if (!$pchhdef && $hcount > 1 && defined $hmatching) {
2936 $self->process_assignment('pch_header', $hmatching);
2938 if (!$pchcdef && $ccount > 1 && defined $cmatching) {
2939 $self->process_assignment('pch_source', $cmatching);
2945 sub fix_pch_filenames
{
2948 ## Unset the precompiled header settings if they are set but empty
2949 foreach my $type ('pch_header', 'pch_source') {
2950 my $pch = $self->get_assignment($type);
2951 $self->process_assignment($type, undef) if (defined $pch && $pch eq '');
2956 sub remove_extra_pch_listings
{
2958 my @pchs = ('pch_header', 'pch_source');
2959 my @tags = ('header_files', 'source_files');
2961 for(my $j = 0; $j < 2; ++$j) {
2962 my $pch = $self->get_assignment($pchs[$j]);
2965 ## If we are converting slashes, then we need to
2966 ## convert the pch file back to forward slashes
2967 $pch =~ s/\\/\//g
if ($self->{'convert_slashes'});
2969 ## Find out which files are duplicated
2970 my $names = $self->{$tags[$j]};
2971 foreach my $name (keys %$names) {
2972 my $comps = $$names{$name};
2973 foreach my $key (keys %$comps) {
2974 my $array = $$comps{$key};
2975 my $count = scalar(@
$array);
2976 for(my $i = 0; $i < $count; ++$i) {
2977 if ($pch eq $$array[$i]) {
2978 splice(@
$array, $i, 1);
2990 my($self, $files, $exts, $pchh, $pchc, $tag, $array, $alldir) = @_;
2992 my $havec = (defined $self->{'exclude_components'}->{$tag});
2994 ## The special actions taken based on $saverc only applies to
2995 ## C++ resource files.
2996 my $saverc = (!$alldir && $tag eq $self->get_resource_tag() &&
2997 $self->languageIs(Creator
::cplusplus
));
2999 foreach my $ext (@
$exts) {
3000 foreach my $file (grep(/$ext$/, @
$files)) {
3001 ## Always exclude the precompiled header and cpp
3002 if ((!defined $pchh || $file ne $pchh) &&
3003 (!defined $pchc || $file ne $pchc)) {
3006 foreach my $exc (@
{$self->{'exclude_components'}->{$tag}}) {
3007 if ($file =~ /$exc$/) {
3015 ## Save these files for later. There may
3016 ## be more than one and we want to try and
3017 ## find the one that corresponds to this project
3018 push(@saved, $file);
3022 push(@
$array, $file) if (!$self->already_added($array, $file));
3027 ## Now deal with the saved files
3028 if (defined $saved[0]) {
3029 if (!defined $saved[1]) {
3030 ## Theres only one rc file, take it
3031 push(@
$array, $saved[0]);
3034 my $pjname = $self->escape_regex_special(
3035 $self->transform_file_name(
3036 $self->get_assignment('project_name')));
3037 ## Use a case insensitive search.
3038 ## After all, this is a Windows specific file type.
3039 foreach my $save (@saved) {
3040 if ($save =~ /$pjname/i) {
3041 if (!$self->already_added($array, $save)) {
3042 push(@
$array, $save);
3051 sub sift_default_file_list
{
3052 my($self, $tag, $file, $built, $exts, $recurse, $pchh, $pchc) = @_;
3053 my $alldir = $recurse ||
3054 (defined $self->{'flag_overrides'}->{$tag} &&
3055 defined $self->{'flag_overrides'}->{$tag}->{$file} &&
3056 $self->{'flag_overrides'}->{$tag}->{$file}->{'recurse'});
3057 my @gen = $self->generate_default_file_list($file, [], undef, $alldir);
3059 $self->sift_files(\
@gen, $exts, $pchh, $pchc, $tag, $built, $alldir);
3063 sub correct_generated_files
{
3064 my($self, $defcomp, $exts, $tag, $array) = @_;
3066 if (defined $sourceComponents{$tag}) {
3067 my $grtag = $grouped_key . $tag;
3068 foreach my $gentype (keys %{$self->{'generated_exts'}}) {
3069 ## If we are not automatically adding generated output, then we
3070 ## need to skip this component type.
3071 next if (!$self->{'generated_exts'}->{$gentype}->{'automatic_out'});
3073 ## If we are auto-generating the source_files, then
3074 ## we need to make sure that any generated source
3075 ## files that are added are put at the front of the list.
3079 ## If I call keys %{$self->{$gentype}} using perl 5.6.1
3080 ## it returns nothing. I have to put it in an
3081 ## intermediate variable to ensure that I get the keys.
3082 my $names = $self->{$gentype};
3083 foreach my $name (keys %$names) {
3084 foreach my $key (keys %{$$names{$name}}) {
3085 push(@input, @
{$$names{$name}->{$key}});
3086 $newgroup = $key if ($key ne $defgroup);
3090 if (defined $input[0]) {
3095 foreach my $input (@input) {
3096 my $part = $self->remove_wanted_extension(
3098 $self->{'valid_components'}->{$gentype});
3100 my @files = $self->generated_filenames($part, $gentype,
3102 if (defined $copy[0]) {
3104 foreach my $file (@files) {
3105 for(my $i = 0; $i < scalar(@copy); $i++) {
3106 my $re = $self->escape_regex_special($copy[$i]);
3107 if ($file eq $copy[$i] || $file =~ /[\/\\]$re$/) {
3108 ## No need to check for previously added files
3109 ## here since there are none.
3111 push(@front, $file);
3112 splice(@copy, $i, 1);
3119 ## The first file listed in @files is the preferred
3120 ## extension for the custom command. Take the first
3121 ## file extension and see if it matches one in the accepted
3123 if (defined $files[0]) {
3125 if ($files[0] =~ /.*(\.[^\.]+)$/) {
3126 $ext = $self->escape_regex_special($1);
3129 ## If it doesn't match one of the accepted extensions,
3130 ## then just use the first extension from the type for
3131 ## which we are generating.
3132 $ext = $$exts[0] if (!StringProcessor
::fgrep
($ext, $exts));
3135 ## Add all the files that match the chosen extension
3136 foreach my $file (@files) {
3137 push(@front, $file) if ($file =~ /$ext$/);
3143 my $ext = $$exts[0];
3144 foreach my $file (@files) {
3145 push(@front, $file) if ($file =~ /$ext$/);
3149 if (defined $copy[0]) {
3150 ## No need to check for previously added files
3151 ## here since there are none.
3152 push(@
$array, @copy);
3153 if (defined $self->get_assignment($grtag)) {
3154 $self->process_assignment_add($grtag, $defgroup);
3157 if (defined $front[0]) {
3158 if (defined $newgroup) {
3159 if (defined $copy[0]) {
3160 $self->process_assignment_add($grtag, $defgroup);
3162 if (!defined $self->{$tag}->{$defcomp}->{$newgroup}) {
3163 $self->{$tag}->{$defcomp}->{$newgroup} = \
@front;
3166 push(@
{$self->{$tag}->{$defcomp}->{$newgroup}}, @front);
3168 $self->process_assignment_add($grtag, $newgroup);
3171 unshift(@
$array, @front);
3179 sub generate_default_components
{
3180 my($self, $files, $passed) = @_;
3181 my $genext = $self->{'generated_exts'};
3182 my @gc = reverse sort { $self->sort_generated_types($a, $b)
3184 my @tags = (defined $passed ?
$passed :
3185 (@gc, keys %{$language{$self->get_language()}->[0]}));
3186 my $pchh = $self->get_assignment('pch_header');
3187 my $pchc = $self->get_assignment('pch_source');
3188 my $recurse = $self->get_assignment('recurse');
3189 my $defcomp = $self->get_default_component_name();
3190 my $flo = $self->{'flag_overrides'};
3191 my $cmdflags = 'commandflags';
3193 ## The order of @tags does make a difference in the way that generated
3194 ## files get added. Hence the sort call on the generate_exts keys to
3195 ## ensure that user defined types come first. They are reverse sorted
3196 ## using the custom sort function to ensure that user defined types
3197 ## that rely on other user defined types for input files are processed
3199 foreach my $tag (@tags) {
3200 if (!defined $genext->{$tag} ||
3201 $genext->{$tag}->{'automatic_in'}) {
3202 my $exts = $self->{'valid_components'}->{$tag};
3203 if (defined $$exts[0]) {
3204 if (defined $self->{$tag}) {
3205 ## If the tag is defined, then process directories
3206 my $names = $self->{$tag};
3207 foreach my $name (keys %$names) {
3208 my $comps = $$names{$name};
3209 foreach my $comp (keys %$comps) {
3210 my $array = $$comps{$comp};
3211 if (defined $passed) {
3212 $self->sift_files($files, $exts, $pchh, $pchc, $tag, $array);
3217 foreach my $file (@
$array) {
3220 $self->sift_default_file_list($tag, $file, \
@portion,
3221 $exts, $recurse, $pchh, $pchc);
3223 ## Since the file was actually a directory, we will
3224 ## need to propagate the flag overrides (if there are
3225 ## any) to the newly located files.
3226 if (defined $flo->{$tag} &&
3227 defined $flo->{$tag}->{$file}) {
3228 foreach my $built (@portion) {
3229 $flo->{$tag}->{$built} = $flo->{$tag}->{$file};
3233 ## Always push the @portion array onto the back of
3235 push(@built, @portion);
3239 if (!$self->already_added(\
@built, $file)) {
3240 push(@built, $file);
3245 $self->correct_generated_files($defcomp, $exts,
3248 $$comps{$comp} = \
@built;
3254 ## Generate default values for undefined tags
3257 $self->{$tag}->{$defcomp} = $comps;
3258 $$comps{$defgroup} = [];
3259 my $array = $$comps{$defgroup};
3261 $self->{'defaulted'}->{$tag} = 1;
3263 if (!defined $specialComponents{$tag}) {
3264 $self->sift_files($files, $exts, $pchh, $pchc, $tag, $array);
3265 $self->correct_generated_files($defcomp, $exts, $tag, $array);
3269 ## If the type that we're generating defaults for ($tag) is a
3270 ## custom type, then we need to see if other custom types
3271 ## ($gentype) will generate files that will be used as input. It
3272 ## has to be done here so that the built-in types will have all
3273 ## of the possible input files that they can.
3274 if (defined $genext->{$tag}) {
3275 foreach my $gentype (keys %{$genext}) {
3276 if ($gentype ne $tag) {
3277 $self->list_default_generated($gentype, [$tag]);
3281 ## Now that we have the files for this type ($tag), we need to
3282 ## locate a command helper for the custom command and see if it
3283 ## knows about any additional output files based on the file
3285 my $cmdHelper = $self->find_command_helper($tag);
3286 if (defined $cmdHelper) {
3287 my $names = $self->{$tag};
3288 foreach my $name (keys %$names) {
3289 my $comps = $$names{$name};
3290 foreach my $comp (keys %$comps) {
3291 my $array = $$comps{$comp};
3292 foreach my $file (@
$array) {
3293 my $flags = defined $flo->{$tag}->{$file} ?
3294 $flo->{$tag}->{$file}->{$cmdflags} :
3295 $genext->{$tag}->{$cmdflags};
3296 my ($add_out, $deps) = $cmdHelper->get_output($file, $flags);
3297 push(@
{$self->{'custom_special_output'}->{$tag}->{$file}},
3299 foreach my $depTag (keys %$deps) {
3300 foreach my $depFile (keys %{$deps->{$depTag}}) {
3301 $self->add_custom_depend($depTag, $depFile,
3302 $deps->{$depTag}->{$depFile});
3316 sub remove_duplicated_files
{
3317 my($self, $dest, $source) = @_;
3318 my @slist = $self->get_component_list($source, 1);
3320 ## There's no point in going on if there's nothing in this component
3322 return undef if ($#slist == -1);
3324 ## Convert the array into keys for a hash table
3326 @shash{@slist} = ();
3328 ## Find out which source files are listed
3329 my $names = $self->{$dest};
3330 foreach my $name (keys %$names) {
3331 foreach my $key (keys %{$$names{$name}}) {
3332 my $array = $$names{$name}->{$key};
3333 my $count = scalar(@
$array);
3334 for(my $i = 0; $i < $count; ++$i) {
3335 ## Is the source file in the component array?
3336 if (exists $shash{$$array[$i]}) {
3337 ## Remove the element and fix the index and count
3338 splice(@
$array, $i, 1);
3348 sub generated_source_listed
{
3349 my($self, $gent, $tag, $arr, $sext) = @_;
3350 my $names = $self->{$tag};
3352 ## Find out which generated source files are listed
3353 foreach my $name (keys %$names) {
3354 my $comps = $$names{$name};
3355 foreach my $key (keys %$comps) {
3356 foreach my $val (@
{$$comps{$key}}) {
3357 foreach my $i (keys %$arr) {
3358 my @gfiles = $self->generated_filenames($$arr{$i}, $gent, $tag, $i);
3359 foreach my $re (@gfiles) {
3360 $re = $self->escape_regex_special($re);
3361 return 1 if ($val =~ /$re$/);
3372 sub list_default_generated
{
3373 my($self, $gentype, $tags) = @_;
3375 ## This method is called when the user has custom input files and has
3376 ## provided source files. If the user defaults the component (i.e.
3377 ## source_files, resource_files, etc.) they are filled in by the
3378 ## generate_default_components method.
3380 if (defined $self->{'generated_exts'}->{$gentype} &&
3381 $self->{'generated_exts'}->{$gentype}->{'automatic_out'}) {
3382 ## After all source and headers have been defaulted, see if we
3383 ## need to add the generated files
3384 if (defined $self->{$gentype}) {
3385 ## Build up the list of files
3387 #tie %arr, "Tie::IxHash"; # preserve insertion order.
3389 my $names = $self->{$gentype};
3391 foreach my $name (keys %$names) {
3392 foreach my $key (keys %{$$names{$name}}) {
3393 my $array = $$names{$name}->{$key};
3395 ## Take the last group name we encounter
3396 $group = $key if ($key ne $defgroup);
3398 foreach my $val (@
$array) {
3399 $arr{$val} = $self->remove_wanted_extension(
3401 $self->{'valid_components'}->{$gentype});
3406 foreach my $type (@
$tags) {
3407 ## Only add generated files if the following is true:
3408 ## 1) The generating type is not the same as the receiving type.
3409 ## 2) The receiving type is not "special" (unless it hasn't been
3410 ## supplied by the user).
3411 ## 3) The receiving type is not user defined or it is user
3412 ## defined and has 'automatic_in' set to true.
3413 if ($gentype ne $type &&
3414 (!$specialComponents{$type} ||
3415 (!$self->{'special_supplied'}->{$type} ||
3416 UNIVERSAL
::isa
($self->{'special_supplied'}->{$type}, 'ARRAY'))) &&
3417 (!defined $self->{'generated_exts'}->{$type} ||
3418 $self->{'generated_exts'}->{$type}->{'automatic_in'})) {
3419 if (!$self->generated_source_listed(
3420 $gentype, $type, \
%arr,
3421 $self->{'valid_components'}->{$gentype})) {
3422 $self->add_generated_files($gentype, $type, $group, \
%arr);
3431 sub prepend_gendir
{
3432 my($self, $created, $ofile, $gentype) = @_;
3435 if (defined $self->{'flag_overrides'}->{$gentype}) {
3436 foreach my $ext (@
{$self->{'valid_components'}->{$gentype}}) {
3441 last if (defined $self->{'flag_overrides'}->{$gentype}->{$key});
3446 if (StringProcessor
::fgrep
('gendir',
3447 $self->{'matching_assignments'}->{$gentype})) {
3448 my $dir = $self->{'flag_overrides'}->{$gentype}->{$key}->{'gendir'};
3450 ## Convert the file to unix style for basename
3451 if ($self->{'convert_slashes'}) {
3452 $created =~ s/\\/\//g
;
3455 return ($dir eq '.' ?
'' : "$dir/") . $self->mpc_basename($created);
3465 sub list_generated_file
{
3466 my($self, $gentype, $tag, $array, $file, $ofile) = @_;
3469 ## Go through each file listed in our original type and attempt to find
3470 ## out if it is the generated file we may need to add ($file).
3471 foreach my $gen ($self->get_component_list($gentype, 1)) {
3474 ## Take the file and see if it contains an extension that our
3475 ## generating type ($gentype) knows about. If it does, remove it and
3476 ## stop looking for the extension.
3477 foreach my $ext (@
{$self->{'valid_components'}->{$gentype}}) {
3478 ## Remove the extension.
3479 ## If it works, then we can exit this loop.
3480 last if ($gen =~ s/$ext$//);
3483 ## If the user provided file does not match any of the
3484 ## extensions specified by the custom definition, we need
3485 ## to remove the extension or else this file will not be
3486 ## added to the project.
3487 $gen =~ s/\.[^\.]+$// if ($gen eq $input);
3489 ## See if we need to add the file. We always need to check since the
3490 ## output file may have absolutely nothing in common with the input
3492 foreach my $created ($self->generated_filenames($gen, $gentype,
3494 ## $gen is a file that has a custom definition that generates
3495 ## files of the type $tag. The $file passed in is of type
3496 ## $gentype and, as far as I can tell, $created will always be
3497 ## longer or of the same length of $file. It doesn't really
3498 ## matter if $file contains a '.' or not.
3499 if (index($created, $file) != -1) {
3500 if (defined $ofile) {
3501 $created = $self->prepend_gendir($created, $ofile, $gentype);
3503 if (!$self->already_added($array, $created)) {
3504 push(@
$array, $created);
3516 sub add_corresponding_component_files
{
3517 my($self, $filecomp, $tag) = @_;
3518 my $grname = $grouped_key . $tag;
3520 ## Create a hash array keyed off of the existing files of the type
3521 ## that we plan on adding.
3524 my $names = $self->{$tag};
3525 foreach my $name (keys %$names) {
3526 ## Check to see if files exist in the default group
3527 if (defined $$names{$name}->{$defgroup} &&
3528 defined $$names{$name}->{$defgroup}->[0]) {
3531 foreach my $comp (keys %{$$names{$name}}) {
3532 @scfiles{@
{$$names{$name}->{$comp}}} = ();
3536 ## Create an array of extensions for the files we want to add
3538 foreach my $ext (@
{$self->{'valid_components'}->{$tag}}) {
3540 $exts[$#exts] =~ s/\\//g;
3543 ## Check each file against a possible new file addition
3544 my $adddefaultgroup = 0;
3545 my $oktoadddefault = 0;
3546 foreach my $sfile (keys %$filecomp) {
3548 foreach my $ext (@exts) {
3549 if (exists $scfiles{"$sfile$ext"}) {
3556 ## Get the array of files for the selected component name
3558 my $comp = $$filecomp{$sfile};
3559 foreach my $name (keys %$names) {
3560 if (defined $$names{$name}->{$comp}) {
3561 $array = $$names{$name}->{$comp};
3565 ## First, see if it will be generated so that we can correctly
3566 ## deal with 'gendir' settings.
3567 foreach my $gentype (keys %{$self->{'generated_exts'}}) {
3568 $found += $self->list_generated_file($gentype, $tag, $array, $sfile);
3571 ## Next check to see if the file exists
3573 foreach my $ext (@exts) {
3574 if (-r
"$sfile$ext") {
3575 my $file = "$sfile$ext";
3576 if (!$self->already_added($array, $file)) {
3577 push(@
$array, $file);
3585 ## If we have any files at all in the component array, check
3586 ## to see if we need to add a new group name
3587 if (defined $$array[0]) {
3588 if ($comp eq $defgroup) {
3589 $adddefaultgroup = 1;
3592 my $grval = $self->get_assignment($grname);
3593 if (!defined $grval ||
3594 !StringProcessor
::fgrep
($comp, $self->create_array($grval))) {
3595 $self->process_assignment_add($grname, $comp);
3597 $oktoadddefault = 1;
3598 $adddefaultgroup |= $fexist;
3601 ## Put the array back into the component list
3603 foreach my $name (keys %$names) {
3604 $$names{$name}->{$comp} = $array;
3611 ## We only need to add the default group name if we wanted to
3612 ## add the default group when adding new files and we added a group
3613 ## by some other name. Otherwise, defaulted files would always be
3614 ## in a group, which is not what we want.
3615 if ($adddefaultgroup && $oktoadddefault) {
3616 $self->process_assignment_add($grname, $defgroup);
3621 sub get_default_project_name
{
3623 my $name = $self->{'current_input'};
3626 $name = $self->transform_file_name($self->base_directory());
3629 ## Since files on UNIX can have back slashes, we transform them
3630 ## into underscores.
3633 ## Convert the name to a usable name
3634 $name = $self->transform_file_name($name);
3636 ## Take off the extension
3637 $name =~ s/\.[^\.]+$//;
3644 sub remove_excluded
{
3648 ## Process each file type and remove the excluded files
3649 foreach my $tag (@tags) {
3650 my $names = $self->{$tag};
3651 foreach my $name (keys %$names) {
3652 foreach my $comp (keys %{$$names{$name}}) {
3653 my $count = scalar(@
{$$names{$name}->{$comp}});
3654 for(my $i = 0; $i < $count; ++$i) {
3655 my $file = $$names{$name}->{$comp}->[$i];
3656 if (defined $self->{'remove_files'}->{$tag}->{$file}) {
3657 splice(@
{$$names{$name}->{$comp}}, $i, 1);
3662 ## The file does not match exactly with one of the files to
3663 ## remove. Look for wildcard specifications in the files to
3664 ## be removed and perform the removal if one of them matches
3665 ## the current file.
3666 foreach my $key (keys %{$self->{'remove_files'}->{$tag}}) {
3667 if ($key =~ /[\*\?\[\]]/) {
3669 $regex =~ s/\./\\./g;
3670 $regex =~ s/\*/\.\*/g;
3671 $regex =~ s/\?/\./g;
3672 if ($file =~ /^$regex$/) {
3673 splice(@
{$$names{$name}->{$comp}}, $i, 1);
3684 delete $self->{'remove_files'}->{$tag};
3689 sub sort_generated_types
{
3690 ## We need to sort the custom component types such that a custom type
3691 ## that generates input for another custom type comes first in the
3693 my($self, $left, $right, $norecurse) = @_;
3694 foreach my $key (keys %{$self->{'generated_exts'}->{$left}}) {
3695 if ($key =~ /_files$/) {
3696 foreach my $regex (@
{$self->{'generated_exts'}->{$left}->{$key}}) {
3699 foreach my $vreg (@
{$self->{'valid_components'}->{$right}}) {
3700 return -1 if ($ext =~ /$vreg$/);
3705 if (!$norecurse && $self->sort_generated_types($right, $left, 1) == -1) {
3712 sub generate_defaults
{
3715 ## Generate default project name
3716 if (!defined $self->get_assignment('project_name')) {
3717 $self->set_project_name($self->get_default_project_name());
3720 ## Generate the default pch file names (if needed)
3721 my @files = $self->generate_default_file_list(
3723 undef, $self->get_assignment('recurse'));
3724 $self->generate_default_pch_filenames(\
@files);
3726 ## If the pch file names are empty strings then we need to fix that
3727 $self->fix_pch_filenames();
3729 ## Generate default components, but %specialComponents
3730 ## are skipped in the initial default components generation
3731 $self->generate_default_components(\
@files);
3733 ## Remove source files that are also listed in the template files
3734 ## If we do not do this, then generated projects can be invalid.
3735 $self->remove_duplicated_files('source_files', 'template_files');
3737 ## If pch files are listed in header_files or source_files more than
3738 ## once, we need to remove the extras
3739 $self->remove_extra_pch_listings();
3741 ## Generate the default generated list of files only if we defaulted
3742 ## the generated file list. I want to ensure that source_files comes
3743 ## first in the list to pick up group information (since source_files
3744 ## are most likely going to be grouped than anything else).
3745 my @vc = sort { return -1 if $a eq 'source_files';
3746 return 1 if $b eq 'source_files';
3747 return $b cmp $a; } keys %{$self->{'valid_components'}};
3748 my @gvc = sort { $self->sort_generated_types($a, $b)
3749 } keys %{$self->{'generated_exts'}};
3750 foreach my $gentype (@gvc) {
3751 $self->list_default_generated($gentype, \
@vc);
3754 ## Now that all of the source files have been added
3755 ## we need to remove those that have need to be removed
3756 $self->remove_excluded('source_files');
3758 ## Collect up all of the source files that have already been listed
3759 ## with the extension removed for use directly below.
3761 foreach my $sourcetag (keys %sourceComponents) {
3762 my $names = $self->{$sourcetag};
3763 foreach my $name (keys %$names) {
3764 foreach my $comp (keys %{$$names{$name}}) {
3765 foreach my $sfile (@
{$$names{$name}->{$comp}}) {
3767 $mod =~ s/\.[^\.]+$//;
3768 $sourcecomp{$mod} = $comp;
3774 ## Add %specialComponents files based on the
3775 ## source_components (i.e. .h and .i or .inl based on .cpp)
3776 foreach my $tag (keys %specialComponents) {
3777 $self->add_corresponding_component_files(\
%sourcecomp, $tag);
3780 ## Now, if the %specialComponents are still empty
3781 ## then take any file that matches the components extension
3782 foreach my $tag (keys %specialComponents) {
3783 if (!$self->{'special_supplied'}->{$tag} ||
3784 UNIVERSAL
::isa
($self->{'special_supplied'}->{$tag}, 'ARRAY')) {
3785 my $names = $self->{$tag};
3786 if (defined $names) {
3787 ## We only want to generate default components if we have
3788 ## defaulted the source files or we have no files listed
3789 ## in the current special component.
3790 my $ok = $self->{'defaulted'}->{'source_files'};
3793 foreach my $name (keys %$names) {
3794 foreach my $key (keys %{$$names{$name}}) {
3795 push(@all, @
{$$names{$name}->{$key}});
3798 $ok = (!defined $all[0]);
3801 ## If the "special" type was supplied and it was all
3802 ## directories, we need to use those directories to generate
3803 ## the default components instead of the current directory.
3804 my $fileref = \
@files;
3805 if (defined $self->{'special_supplied'}->{$tag} &&
3806 UNIVERSAL
::isa
($self->{'special_supplied'}->{$tag}, 'ARRAY')) {
3808 foreach my $dir (@
{$self->{'special_supplied'}->{$tag}}) {
3809 push(@special, $self->generate_default_file_list(
3811 $self->get_assignment('recurse')));
3813 $fileref = \
@special;
3815 $self->generate_default_components($fileref, $tag);
3821 ## The code to add template files automatically when it is left
3822 ## defaulted by the user may add source files that happen to end in _t
3823 ## (minus the extension). If we do not remove template files that are
3824 ## also listed as source files, the generated projects can be invalid.
3825 $self->remove_duplicated_files('template_files', 'source_files');
3827 ## Now that all of the other files have been added
3828 ## we need to remove those that have need to be removed
3829 my @rmkeys = keys %{$self->{'remove_files'}};
3830 $self->remove_excluded(@rmkeys) if (defined $rmkeys[0]);
3832 ## Tie custom files together if need be. This currently only applies
3833 ## to types with command helpers. At some point, if it is found to be
3834 ## desirous, we could extend the MPC syntax somehow to support this
3835 ## sort of thing manually.
3836 my $dep = 'dependent';
3837 foreach my $gentype (@gvc) {
3838 my $cmdHelper = $self->find_command_helper($gentype);
3839 if (defined $cmdHelper) {
3840 ## There has to be at least two files files in order for
3841 ## something to be tied together.
3842 my @files = $self->get_component_list($gentype, 1);
3844 foreach my $file (@files) {
3845 my $part = $self->remove_wanted_extension(
3846 $file, $self->{'valid_components'}->{$gentype});
3847 my($tied, $vc) = $cmdHelper->get_tied($file, \
@files);
3848 foreach my $tie (@
$tied) {
3849 ## We have a tied file, now we need to actually perform
3850 ## the tieing of the two. We will do this by saying that
3851 ## the output of the original is necessary for the
3852 ## processing of the tied file.
3856 @gen = $self->generated_filenames($part, $gentype,
3858 last if ($#gen >= 0);
3861 @gen = $self->generated_filenames($part, $gentype,
3862 $vc, $file) if (!$gen[0]);
3864 ## We have found a set of files that are generated
3865 ## based on the component type of the original file
3866 ## ($gentype), so we just add the first one and
3868 my $first = $gen[0];
3870 if (!defined $self->{'flag_overrides'}->{$gentype}->{$tie}->{$dep}) {
3871 ## We are about to modify the flag overrides for a tied file.
3872 ## We need to make a copy so that we do not affect the
3873 ## overrides of grouped, but no longer affiliated files.
3874 my %copy = %{$self->{'flag_overrides'}->{$gentype}->{$tie}};
3875 $self->{'flag_overrides'}->{$gentype}->{$tie} = \
%copy;
3878 ## Start a new dependent setting based on the original
3879 ## custom build settings.
3880 $self->{'flag_overrides'}->{$gentype}->{$tie}->{$dep} =
3881 $self->{'generated_exts'}->{$gentype}->{$dep};
3884 if (!defined $self->{'flag_overrides'}->{$gentype}->{$tie}->{$dep} ||
3885 $self->{'flag_overrides'}->{$gentype}->{$tie}->{$dep} !~ /\b$first\b/) {
3887 ## We are about to modify the flag overrides for a tied file.
3888 ## We need to make a copy so that we do not affect the
3889 ## overrides of grouped, but no longer affiliated files.
3890 my %copy = %{$self->{'flag_overrides'}->{$gentype}->{$tie}};
3891 $self->{'flag_overrides'}->{$gentype}->{$tie} = \
%copy;
3895 ## Update the dependent value for this tied file.
3896 $self->{'flag_overrides'}->{$gentype}->{$tie}->{$dep} .= " $first";
3906 sub set_project_name
{
3907 my($self, $name) = @_;
3909 ## Save the unmodified project name so that when we
3910 ## need to determine the default target name, we can use
3911 ## what is expected by the user.
3912 $self->{'unmodified_project_name'} = $name;
3914 ## If we are applying the name modifier to the project
3915 ## then we will modify the project name
3916 if ($self->get_apply_project()) {
3917 my $nmod = $self->get_name_modifier();
3919 if (defined $nmod) {
3920 $nmod =~ s/\*/$name/g;
3925 ## Set the project_name assignment so that the TemplateParser
3926 ## can get the project name.
3927 $self->process_assignment('project_name', $name);
3932 return $_[0]->get_assignment('project_name');
3938 return (defined $self->get_assignment('sharedname') ||
3939 defined $self->get_assignment('staticname'));
3944 return (defined $_[0]->get_assignment('exename'));
3948 sub get_component_list
{
3949 my($self, $tag, $noconvert) = @_;
3950 my $names = $self->{$tag};
3953 foreach my $name (keys %$names) {
3954 foreach my $key (keys %{$$names{$name}}) {
3955 push(@list, @
{$$names{$name}->{$key}});
3959 ## By default, if 'convert_slashes' is true, then we convert slashes
3960 ## to backslashes. There are cases where we do not want to convert
3961 ## the slashes, in that case get_component_list() was called with
3962 ## an additional parameter indicating this.
3963 if (!$noconvert && $self->{'convert_slashes'}) {
3964 foreach my $item (@list) {
3969 if ($self->{'sort_files'}) {
3970 @list = sort { $self->file_sorter($a, $b) } @list;
3977 sub check_custom_output
{
3978 my($self, $based, $cinput, $ainput, $type, $comps) = @_;
3981 foreach my $array ($self->generated_filenames($cinput, $based,
3982 $type, $ainput, 0, 1)) {
3983 foreach my $built (@
$array) {
3985 push(@outputs, $built);
3988 elsif (defined $specialComponents{$type} &&
3989 (!$self->{'special_supplied'}->{$type} ||
3990 UNIVERSAL
::isa
($self->{'special_supplied'}->{$type}, 'ARRAY'))) {
3991 push(@outputs, $built);
3996 $base =~ s/\\/\//g
if ($self->{'convert_slashes'});
3997 my $re = $self->escape_regex_special($self->mpc_basename($base));
3998 foreach my $c (@
$comps) {
3999 ## We only match if the built file name matches from
4000 ## beginning to end or from a slash to the end.
4001 if ($c =~ /^$re$/ || $c =~ /[\/\\]$re$/) {
4002 push(@outputs, $built);
4014 sub get_special_value
{
4021 ## These names (held in $type) are variables that contain various
4022 ## commands that will be used in templates within the context of a
4023 ## foreach (e.g., <%custom_type->input_files%> or <%feature->value%>).
4024 if ($type eq 'feature') {
4025 return $self->get_feature_value($cmd, $based);
4027 elsif (index($type, 'custom_type') == 0) {
4028 return $self->get_custom_value($cmd, $based, @params);
4030 elsif (index($type, $grouped_key) == 0) {
4031 return $self->get_grouped_value($type, $cmd, $based);
4033 elsif (defined $self->get_addtemp()->{$type . 's'}) {
4034 if ($cmd eq '_default') {
4035 $based =~ /^([^:]+):/;
4036 return defined $1 ?
$1 : $based;
4039 if ($based =~ /:(.*)/) {
4040 my %attr = map { split('=', $_) } split(',', $1);
4046 my $language = $self->get_language();
4048 ## If the passed in type is not a builtin type, try the type with an
4050 $type .= 's' if (!defined $language{$language}->[0]->{$type});
4052 ## This is a hack for dealing with the fact that built-in types
4053 ## (e.g., Source_Files, Header_Files, etc.) are not real custom
4054 ## definitions. However, we can "modify" them to some extent.
4055 return $self->get_builtin_value($type, $cmd, $based)
4056 if (defined $language{$language}->[0]->{$type});
4063 sub get_feature_value
{
4064 my($self, $cmd, $based) = @_;
4066 if ($cmd eq 'value') {
4067 my $val = $self->{'feature_parser'}->get_value($based);
4068 if (defined $val && $val != 0) {
4077 sub get_grouped_value
{
4078 my($self, $type, $cmd, $based) = @_;
4081 ## Make it all lower case
4084 ## Remove the grouped_ part
4085 $type =~ s/^$grouped_key//;
4087 ## Add the s if it isn't there
4088 $type .= 's' if ($type !~ /s$/);
4090 my $names = $self->{$type};
4091 if ($cmd eq 'files') {
4092 foreach my $name (keys %$names) {
4093 my $comps = $$names{$name};
4094 my @keys = keys %$comps;
4095 if (StringProcessor
::fgrep
($based, \
@keys)) {
4096 if ($self->{'convert_slashes'}) {
4098 foreach my $file (@
{$$comps{$based}}) {
4099 push(@converted, $self->slash_to_backslash($file));
4101 $value = \
@converted;
4104 $value = $$comps{$based};
4106 if ($self->{'sort_files'}) {
4107 my @sorted = sort { $self->file_sorter($a, $b) } @
$value;
4113 elsif ($cmd eq 'component_name') {
4114 ## If there is more than one name, then we will need
4115 ## to deal with that at a later time.
4116 foreach my $name (keys %$names) {
4125 sub get_builtin_value
{
4126 my($self, $type, $cmd, $based) = @_;
4128 ## If the passed in type does not have a generated_exts definition,
4129 ## then try the type with an 's' on the end.
4130 $type .= 's' if (!defined $self->{'generated_exts'}->{$type});
4132 ## If we have a builtin type that has the variable ($cmd) that we are
4133 ## looking for, process the value through command parameter conversion.
4134 if (defined $self->{'generated_exts'}->{$type} &&
4135 defined $self->{'generated_exts'}->{$type}->{$cmd}) {
4136 return $self->convert_command_parameters(
4137 $type, $self->{'generated_exts'}->{$type}->{$cmd},
4138 $based, $self->get_builtin_output($based));
4141 ## Otherwise, there's nothing here.
4145 sub get_command_subs
{
4149 ## Add the built-in OS compatibility commands
4150 if (UNIVERSAL
::isa
($self, 'WinProjectBase') ||
4151 $self->use_win_compatibility_commands()) {
4152 $valid{'cat'} = 'type';
4153 $valid{'cmp'} = 'fc /b';
4154 $valid{'cp'} = 'copy /y';
4155 $valid{'mkdir'} = 'mkdir';
4156 $valid{'mv'} = 'move /y';
4157 $valid{'os'} = 'win32';
4158 $valid{'rm'} = 'del /f/s/q';
4159 $valid{'rmdir'} = 'rmdir /s/q';
4160 $valid{'nul'} = 'nul';
4161 $valid{'slash'} = '\\';
4162 $valid{'bat'} = '.bat';
4163 $valid{'cmd'} = '.cmd';
4164 $valid{'exe'} = '.exe';
4165 $valid{'pathsep'} = ';';
4168 $valid{'cat'} = 'cat';
4169 $valid{'cmp'} = 'cmp';
4170 $valid{'cp'} = 'cp -f';
4171 $valid{'mkdir'} = 'mkdir -p';
4172 $valid{'mv'} = 'mv -f';
4173 $valid{'os'} = 'unix';
4174 $valid{'rm'} = 'rm -rf';
4175 $valid{'rmdir'} = 'rm -rf';
4176 $valid{'nul'} = '/dev/null';
4177 $valid{'slash'} = '/';
4181 $valid{'pathsep'} = ':';
4184 ## Add the project specific compatibility commands
4185 $valid{'gt'} = $self->get_gt_symbol();
4186 $valid{'lt'} = $self->get_lt_symbol();
4187 $valid{'and'} = $self->get_and_symbol();
4188 $valid{'or'} = $self->get_or_symbol();
4189 $valid{'quote'} = $self->get_quote_symbol();
4190 $valid{'equote'} = $self->get_escaped_quote_symbol();
4191 $valid{'crlf'} = $self->crlf();
4192 $valid{'cmdsep'} = $self->get_cmdsep_symbol();
4193 $valid{'temporary'} = 'temp.$$$$.' . int(rand(0xffffffff));
4194 $valid{'prj_type'} = $self->{'pctype'};
4200 sub replace_parameters
{
4201 my($self, $str, $valid, $nowarn, $input, $output, $always_clear) = @_;
4205 while ($str =~ /<%(\w+)(\(\w+\))?%>/) {
4208 if (defined $modifier) {
4211 $name =~ s/[\(\)]//g;
4215 ## Support both pseudo variables and project settings
4216 if (defined $$valid{$name} || $self->is_keyword($name)) {
4217 ## If the pseudo variable is defined or the project setting has a
4218 ## value, then we'll need to do the replacement. However, if it's
4219 ## a project keyword and it's not defined, we will need to delay
4220 ## the replacement until later (unless $always_clear is true).
4222 my $clear = $always_clear;
4223 if (defined $$valid{$name}) {
4224 $replace = $$valid{$name};
4226 elsif ($self->is_keyword($name)) {
4227 $replace = $self->get_assignment($name);
4230 ## Perform the modification and replacement here
4231 if (defined $replace) {
4232 if (defined $modifier) {
4233 if ($modifier eq 'noextension') {
4234 $replace =~ s/\.[^\.]+$//;
4237 $self->warning("Unknown parameter modifier $modifier.");
4240 $str =~ s/<%\w+(\(\w+\))?%>/$replace/;
4243 ## We need to clear out this variable usage.
4244 $str =~ s/<%\w+(\(\w+\))?%>//;
4247 ## Save this variable usage to be put back after we're done
4248 ## processing the string.
4249 my $key = "\1" . $count++ . "\1";
4250 if ($str =~ s/(<%\w+(\(\w+\))?%>)/$key/) {
4256 $str =~ s/<%\w+(\(\w+\))?%>//;
4258 ## We only want to warn the user that we did not recognize the
4259 ## pseudo template parameter if there was an input and an output
4260 ## file passed to this function. If this variable was used
4261 ## without the parenthesis (as in an if statement), then we don't
4262 ## want to warn the user.
4263 if (defined $input && defined $output) {
4264 if (!defined $$nowarn{$name}) {
4265 $self->warning("<%$name%> was not recognized.");
4268 ## If we didn't recognize the pseudo template parameter then
4269 ## we don't want to return anything back.
4275 ## Replace the saved variables so that they may be replaced (or
4276 ## removed) later on.
4277 foreach my $key (keys %saved) {
4278 $str =~ s/$key/$saved{$key}/;
4284 sub convert_command_parameters
{
4285 my($self, $ktype, $str, $input, $output) = @_;
4287 my %valid = %{$self->{'command_subs'}};
4289 ## Add in the values that change for every call to this function
4290 $valid{'temporary'} = 'temp.$$$$.' . int(rand(0xffffffff));
4292 if (defined $input) {
4293 $valid{'input'} = $input;
4294 $valid{'input_basename'} = $self->mpc_basename($input);
4295 $valid{'input_dirname'} = $self->mpc_dirname($input);
4296 $valid{'input_noext'} = $input;
4298 ## An input file doesn't always have an extension. If there isn't
4299 ## one, then we need to set the 'input_ext' field to an empty string
4300 ## ($1 will not necessarily have a valid value).
4301 if ($valid{'input_noext'} =~ s/(\.[^\.]+)$//) {
4302 $valid{'input_ext'} = $1;
4305 $valid{'input_ext'} = '';
4308 ## Check for the gendir setting associated with this input file. We
4309 ## have to check at so many levels so we don't inadvertantly create
4310 ## intermediate hash tables.
4311 if (defined $self->{'flag_overrides'}->{$ktype} &&
4312 defined $self->{'flag_overrides'}->{$ktype}->{$input} &&
4313 $self->{'flag_overrides'}->{$ktype}->{$input}->{'gendir'}) {
4314 $valid{'gendir'} = $self->{'flag_overrides'}->{$ktype}->{$input}->{'gendir'};
4318 ## If there is no gendir setting, just set it to the current directory.
4319 $valid{'gendir'} = '.' if (!defined $valid{'gendir'});
4321 if (defined $output) {
4323 $valid{'output'} = "@$output";
4324 foreach my $out (@
$output) {
4325 ## An output file doesn't always have an extension. If there isn't
4326 ## one, then we need to set the 'output_ext' field to an empty
4327 ## string ($1 will not necessarily have a valid value).
4329 if ($noext =~ s/(\.[^\.]+)$//) {
4330 $valid{'output_ext'} = $1;
4333 $valid{'output_ext'} = '';
4335 $valid{'output_noext'} .= (!$first ?
' ' : '') . $noext;
4337 ## In order to call basename or dirname, we must make sure that the
4338 ## directory separators are forward slashes.
4340 $file =~ s/\\/\//g
if ($self->{'convert_slashes'});
4341 $valid{'output_basename'} .= (!$first ?
' ' : '') .
4342 $self->mpc_basename($file);
4343 $valid{'output_dirname'} .= (!$first ?
' ' : '') .
4344 $self->mpc_dirname($file);
4349 ## Add in the specific types of output files
4350 if (defined $output) {
4351 foreach my $type (keys %{$self->{'valid_components'}}) {
4355 $nowarn{$key . '_noext'} = 1;
4356 foreach my $ext (@
{$self->{'valid_components'}->{$type}}) {
4357 foreach my $out (@
$output) {
4358 if ($out =~ /$ext$/) {
4359 $valid{$key} = $out;
4360 $valid{$key . '_noext'} = $out;
4361 $valid{$key . '_noext'} =~ s/$ext$//;
4369 return $self->replace_parameters($str, \
%valid, \
%nowarn, $input, $output, 1);
4373 sub get_custom_special_output
{
4377 if (defined $self->{'custom_special_output'}->{$tag} &&
4378 defined $self->{'custom_special_output'}->{$tag}->{$input} &&
4379 (!defined $self->{'flag_overrides'}->{$tag} ||
4380 !defined $self->{'flag_overrides'}->{$tag}->{$input} ||
4381 !defined $self->{'flag_overrides'}->{$tag}->{$input}->{'gendir'}
4382 || $self->{'flag_overrides'}->{$tag}->{$input}->{'gendir'} eq '.')) {
4383 return $self->{'custom_special_output'}->{$tag}->{$input};
4389 sub get_first_custom_output
{
4394 foreach my $vc (keys %{$self->{'valid_components'}}) {
4395 my @comps = $self->get_component_list($vc);
4396 $vcomps{$vc} = \
@comps;
4398 $vcomps{$generic_key} = [];
4399 my $ainput = $input;
4400 my $cinput = $input;
4402 ## Remove the extension
4403 $cinput =~ s/\.[^\.]+$//;
4405 ## If we are converting slashes,
4406 ## change them back for this parameter
4407 $ainput =~ s/\\/\//g
if ($self->{'convert_slashes'});
4409 foreach my $vc (keys %{$self->{'valid_components'}}) {
4410 my @cout = $self->check_custom_output($tag, $cinput, $ainput, $vc,
4412 return $cout[0] if @cout;
4414 my @cout = $self->check_custom_output($tag, $cinput, $ainput, $generic_key,
4415 $vcomps{$generic_key});
4416 return $cout[0] if @cout;
4417 my $aref = $self->get_custom_special_output($tag, $ainput);
4418 return $$aref[0] if @
$aref;
4423 sub get_custom_assign_or_override
{
4425 my $var = shift; # which variable? (command, commandflags, etc.)
4426 my $tag = shift; # custom_files
4427 my $input = shift; # input file name which may override
4431 if (defined $self->{'flag_overrides'}->{$tag}) {
4432 my $ustyle = $input;
4433 $ustyle =~ s/\\/\//g
if ($self->{'convert_slashes'});
4434 my $dir = $self->mpc_dirname($ustyle);
4435 if (defined $self->{'flag_overrides'}->{$tag}->{$ustyle}) {
4438 elsif (defined $self->{'flag_overrides'}->{$tag}->{$dir}) {
4444 $value = $self->{'flag_overrides'}->{$tag}->{$key}->{$var};
4446 if (!defined $value) {
4447 $value = $self->get_assignment($var, $self->{'generated_exts'}->{$tag});
4449 return undef if !defined $value;
4450 if (defined $customDefined{$var} && ($customDefined{$var} & 0x14)) {
4451 return $self->convert_command_parameters($tag, $value, $input, undef, @params);
4457 sub get_custom_value
{
4464 if ($cmd eq 'input_files') {
4465 ## Get the component list for the component type
4466 my @array = $self->get_component_list($based);
4468 ## Check for directories in the component list. If the component
4469 ## type is not automatic, we may have directories here and will need
4470 ## to get the file list for that type.
4472 for(my $i = 0; $i < scalar(@array); ++$i) {
4473 if (-d
$array[$i]) {
4474 if (!defined $once) {
4475 $once = {'recurse' => $self->get_assignment('recurse'),
4476 'pchh' => $self->get_assignment('pch_header'),
4477 'pchc' => $self->get_assignment('pch_source'),
4481 $self->sift_default_file_list($based, $array[$i], \
@built,
4482 $self->{'valid_components'}->{$based},
4484 $$once{'pchh'}, $$once{'pchc'});
4485 splice(@array, $i, 1, @built);
4492 $self->{'custom_output_files'} = {};
4493 $self->{'custom_dependency_files'} = {};
4494 $self->{'custom_multi_cmd'} = {};
4496 foreach my $vc (keys %{$self->{'valid_components'}}) {
4497 my @comps = $self->get_component_list($vc);
4498 $vcomps{$vc} = \
@comps;
4500 $vcomps{$generic_key} = [];
4502 foreach my $input (@array) {
4504 my $ainput = $input;
4505 my $cinput = $input;
4507 ## Remove the extension
4508 $cinput =~ s/\.[^\.]+$//;
4510 ## If we are converting slashes,
4511 ## change them back for this parameter
4512 $ainput =~ s/\\/\//g
if ($self->{'convert_slashes'});
4514 if (defined $self->{'combined_custom'}->{$based}) {
4515 $self->{'custom_multi_cmd'}->{$input} =
4516 $self->{'combined_custom'}->{$based};
4518 my $cdf = $self->{'custom_dependency_files'};
4519 my $csd = $self->{'custom_special_depend'};
4520 foreach my $tag (@
{$self->{'combined_custom'}->{$based}}) {
4521 if (defined $csd->{$tag} && defined $csd->{$tag}->{$ainput}) {
4522 $cdf->{$input} = [] if (!defined $cdf->{$input});
4523 StringProcessor
::merge
($cdf->{$input}, $csd->{$tag}->{$ainput});
4528 $self->{'custom_dependency_files'}->{$input} =
4529 $self->{'custom_special_depend'}->{$based}->{$ainput};
4532 ## Add all of the output files. We can not add $generic_key to the
4533 ## list here (as it used to be). It may have been handled by
4534 ## generated_filenames.
4535 foreach my $vc (keys %{$self->{'valid_components'}}) {
4536 ## The output of multiple components could be input for the
4537 ## current component type ($based). We need to avoid adding
4539 if (defined $self->{'combined_custom'}->{$based}) {
4540 foreach my $tag (@
{$self->{'combined_custom'}->{$based}}) {
4541 my @cout = $self->check_custom_output($tag, $cinput, $ainput, $vc,
4543 StringProcessor
::merge
(\
@outputs, \
@cout);
4547 my @cout = $self->check_custom_output($based, $cinput, $ainput, $vc,
4549 StringProcessor
::merge
(\
@outputs, \
@cout);
4552 if (defined $self->{'combined_custom'}->{$based}) {
4553 foreach my $tag (@
{$self->{'combined_custom'}->{$based}}) {
4554 my @cout = $self->check_custom_output($tag, $cinput, $ainput,
4556 $vcomps{$generic_key});
4557 StringProcessor
::merge
(\
@outputs, \
@cout);
4561 my @cout = $self->check_custom_output($based, $cinput, $ainput,
4563 $vcomps{$generic_key});
4564 StringProcessor
::merge
(\
@outputs, \
@cout);
4567 ## Add specially listed files avoiding duplicates. We don't want
4568 ## to add these files if gendir is set to something besides .
4569 if (defined $self->{'combined_custom'}->{$based}) {
4570 foreach my $tag (@
{$self->{'combined_custom'}->{$based}}) {
4571 StringProcessor
::merge
(\
@outputs,
4572 $self->get_custom_special_output($tag,
4577 StringProcessor
::merge
(\
@outputs,
4578 $self->get_custom_special_output($based,
4582 if ($self->{'convert_slashes'}) {
4583 foreach my $output (@outputs) {
4584 $output =~ s/\//\\/g
;
4587 if ($self->{'sort_files'}) {
4588 @outputs = sort { $self->file_sorter($a, $b) } @outputs;
4590 $self->{'custom_output_files'}->{$input} = \
@outputs;
4593 elsif ($cmd eq 'output_files') {
4594 # Generate output files based on $based
4595 if (defined $self->{'custom_output_files'}) {
4596 $value = $self->{'custom_output_files'}->{$based};
4599 elsif ($cmd eq 'source_output_files') {
4600 # Generate source output files based on $based
4601 if (defined $self->{'custom_output_files'}) {
4603 foreach my $file (@
{$self->{'custom_output_files'}->{$based}}) {
4604 foreach my $ext (@
{$self->{'valid_components'}->{'source_files'}}) {
4605 if ($file =~ /$ext$/) {
4606 ## We've found a file that matches one of the source file
4607 ## extensions. Now we have to make sure that it doesn't
4608 ## match a template file extension.
4610 foreach my $text (@
{$self->{'valid_components'}->{'template_files'}}) {
4611 if ($file =~ /$text$/) {
4616 push(@
$value, $file) if (!$matched);
4623 elsif ($cmd eq 'non_source_output_files') {
4624 # Generate non source output files based on $based
4625 if (defined $self->{'custom_output_files'}) {
4627 foreach my $file (@
{$self->{'custom_output_files'}->{$based}}) {
4629 foreach my $ext (@
{$self->{'valid_components'}->{'source_files'}}) {
4630 if ($file =~ /$ext$/) {
4632 ## We've found a file that matches one of the source file
4633 ## extensions. Now we have to make sure that it doesn't
4634 ## match a template file extension.
4635 foreach my $text (@
{$self->{'valid_components'}->{'template_files'}}) {
4636 if ($file =~ /$text$/) {
4644 push(@
$value, $file) if (!$source);
4648 elsif ($cmd eq 'non_template_output_files') {
4649 # Generate non-template output files based on $based
4650 if (defined $self->{'custom_output_files'}) {
4652 foreach my $file (@
{$self->{'custom_output_files'}->{$based}}) {
4654 foreach my $ext (@
{$self->{'valid_components'}->{'template_files'}}) {
4655 if ($file =~ /$ext$/) {
4660 push(@
$value, $file) if (!$template);
4664 elsif ($cmd eq 'inputexts') {
4665 my @array = @
{$self->{'valid_components'}->{$based}};
4666 foreach my $val (@array) {
4671 elsif ($cmd eq 'dependencies') {
4672 $value = $self->{'custom_dependency_files'}->{$based};
4674 elsif ($cmd eq 'commands') { # only used with 'combined_custom'
4676 my %details = ('flags' => 'commandflags',
4677 'outopt' => 'output_option',
4678 'gdir' => 'gendir');
4679 for my $tag (@
{$self->{'custom_multi_cmd'}->{$based}}) {
4680 my $command = $self->get_custom_assign_or_override('command', $tag,
4682 push(@
$value, $command);
4683 my $det = $self->{'custom_multi_details'}->{$command} = {};
4684 for my $k (keys %details) {
4685 $det->{$k} = $self->get_custom_assign_or_override($details{$k}, $tag,
4688 if ($det->{'outopt'} && $self->{'custom_output_files'}->{$based}) {
4689 # only 1 output file is supported with output_option
4690 $det->{'outfile'} = $self->get_first_custom_output($based, $tag);
4691 $det->{'outfile'} =~ s/\//\\/g
if $self->{'convert_slashes'};
4692 if (defined $det->{'gdir'}) {
4693 my $basename = $det->{'outfile'};
4694 if ($self->{'convert_slashes'}) {
4695 $basename =~ s/.*[\/\\]//;
4698 $basename =~ s/.*\///;
4701 $det->{'gdir'} . $self->{'command_subs'}->{'slash'} . $basename;
4706 elsif ($cmd eq 'flags' || $cmd eq 'outopt' || $cmd eq 'outfile' ||
4708 # only used with 'combined_custom'
4709 $value = $self->{'custom_multi_details'}->{$based}->{$cmd} || '';
4711 elsif (defined $customDefined{$cmd}) {
4712 $value = $self->get_assignment($cmd,
4713 $self->{'generated_exts'}->{$based});
4714 if (defined $value && ($customDefined{$cmd} & 0x14) != 0) {
4715 $value = $self->convert_command_parameters($based, $value, @params);
4723 sub check_features
{
4724 my($self, $requires, $avoids, $info) = @_;
4728 if (defined $requires) {
4729 foreach my $require (split(/\s+/, $requires)) {
4730 my $fval = $self->{'feature_parser'}->get_value($require);
4732 ## By default, if the feature is not listed, then it is enabled.
4733 if (defined $fval && !$fval) {
4734 $why = "requires $require";
4739 ## For automakes sake, if we're to this point the feature is
4740 ## enabled and we will set it in the feature parser explicitly
4741 if (!defined $fval) {
4742 $self->{'feature_parser'}->parse_line(undef, "$require = 1");
4747 ## If it passes the requires, then check the avoids
4749 if (defined $avoids) {
4750 foreach my $avoid (split(/\s+/, $avoids)) {
4751 my $fval = $self->{'feature_parser'}->get_value($avoid);
4753 ## By default, if the feature is not listed, then it is enabled.
4754 if (!defined $fval || $fval) {
4755 $why = "avoids $avoid";
4763 if ($info && !$status) {
4764 $self->details("Skipping " . $self->get_assignment('project_name') .
4765 " ($self->{'current_input'}); it $why.");
4772 sub need_to_write_project
{
4776 ## We always write a project if the user has provided a verbatim.
4777 ## We have no idea what that verbatim clause does, so we need to just
4778 ## do what the user tells us to do.
4779 return 1 if (defined $self->{'verbatim'}->{$self->{'pctype'}});
4781 ## The order here is important, we must check for source or resource
4782 ## files first and then for custom input files.
4783 foreach my $key ('source_files', $self->get_resource_tag(),
4784 keys %{$self->{'generated_exts'}}) {
4785 ## For implicitly-discovered projects, just having a resource file without
4786 ## source or generated file is not enough to write a project.
4787 next if $self->{'current_input'} eq '' && $key eq $self->get_resource_tag();
4788 my $names = $self->{$key};
4789 foreach my $name (keys %$names) {
4790 foreach my $key (keys %{$names->{$name}}) {
4791 ## See if the project contains a file that corresponds to this
4793 if (defined $names->{$name}->{$key}->[0]) {
4795 ## Return 2 if we have found a custom input file (and thus no
4796 ## source or resource files due to the foreach order).
4799 ## We have either source files or resource files, we need to
4800 ## see if this project creator supports the current language.
4801 ## If it doesn't then we don't need to create the project.
4802 elsif ($self->languageSupported()) {
4803 ## Return 1 if we have found a source file or a resource file.
4812 ## Indicate that there is no need to write the project
4817 sub write_output_file
{
4818 my($self, $webapp) = @_;
4821 my $tover = $self->get_template_override();
4822 my @templates = $self->get_template();
4824 ## The template override will override all templates
4825 @templates = ($tover) if (defined $tover);
4827 foreach my $template (@templates) {
4828 ## Save the template name for use as a key for various function calls
4829 $self->{'current_template'} = $template;
4831 ## Create the output file name based on the project name and the
4832 ## template that we're currently using.
4833 my $name = $self->transform_file_name(
4834 $self->project_file_name(undef,
4835 $self->{'current_template'}));
4837 ## If the template files does not end in the template extension
4838 ## then we will add it on.
4839 if ($template !~ /$TemplateExtension$/) {
4840 $template .= '.' . $TemplateExtension;
4843 ## If the template file does not contain a path, then we
4844 ## will search through the include paths for it.
4846 if ($template =~ /[\/\\]/i
) {
4850 $tfile = $self->search_include_path($template);
4853 if (defined $tfile) {
4854 ## Read in the template values for the specific target and project
4855 ## type. The template input file we get may depend upon the
4856 ## current template that we're using.
4857 ($status, $error) = $self->read_template_input(
4858 $self->{'current_template'});
4861 my $tp = new TemplateParser
($self);
4863 ## Set the project_file assignment for the template parser
4864 $self->process_assignment('project_file', $name);
4866 ($status, $error) = $tp->parse_file($tfile);
4869 if (defined $self->{'source_callback'} &&
4870 $self->file_visible($self->{'current_template'})) {
4871 my $cb = $self->{'source_callback'};
4872 my $pjname = $self->get_assignment('project_name');
4873 my @list = $self->get_component_list('source_files');
4874 if (UNIVERSAL
::isa
($cb, 'ARRAY')) {
4876 my $s = shift(@copy);
4877 &$s(@copy, $name, $pjname, \
@list);
4879 elsif (UNIVERSAL
::isa
($cb, 'CODE')) {
4880 &$cb($name, $pjname, \
@list);
4883 $self->warning("Ignoring callback: $cb.");
4887 if ($self->get_toplevel()) {
4888 my $outdir = $self->get_outdir();
4891 $name = "$outdir/$name";
4893 my $fh = new FileHandle
();
4894 my $dir = $self->mpc_dirname($name);
4896 mkpath
($dir, 0, 0777) if ($dir ne '.');
4899 ## At this point in time, webapps do not get a project file,
4900 ## but they do appear in the workspace
4902 elsif ($self->compare_output()) {
4903 ## First write the output to a temporary file
4904 my $tmp = "$outdir/MPC$>.$$";
4906 if (open($fh, ">$tmp")) {
4907 my $lines = $tp->get_lines();
4908 foreach my $line (@
$lines) {
4913 $different = 0 if (!$self->files_are_different($name, $tmp));
4916 $error = "Unable to open $tmp for output: $!";
4921 ## If they are different, then rename the temporary file
4924 if (rename($tmp, $name)) {
4925 $error = $self->post_file_creation($name);
4926 if (defined $error) {
4932 $error = "Unable to open $name for output: $!";
4938 ## We will pretend that we wrote the file
4943 if (open($fh, ">$name")) {
4944 my $lines = $tp->get_lines();
4945 foreach my $line (@
$lines) {
4949 $error = $self->post_file_creation($name);
4950 if (defined $error) {
4956 $error = "Unable to open $name for output: $!";
4962 ## There may be more than one template associated with this
4963 ## project creator. If there is, we can only add one generated
4964 ## file and we rely on the project creator to tell us which
4965 ## template generates the file that we need to track.
4966 $self->add_file_written($oname)
4967 if ($self->file_visible($self->{'current_template'}));
4971 $error = "Unable to locate the template file: $template.";
4976 return $status, $error;
4980 sub write_install_file
{
4982 my $fh = new FileHandle
();
4983 my $insfile = $self->transform_file_name(
4984 $self->get_assignment('project_name')) .
4986 my $outdir = $self->get_outdir();
4988 $insfile = "$outdir/$insfile";
4991 if (open($fh, ">$insfile")) {
4992 $self->get_install_info(sub {print $fh $_[0]});
4996 return 0, 'Unable write to ' . $insfile;
5000 sub get_install_info
{
5002 my $callback = shift;
5003 foreach my $vc (keys %{$self->{'valid_components'}}) {
5004 my $names = $self->{$vc};
5005 foreach my $name (keys %$names) {
5006 foreach my $key (keys %{$$names{$name}}) {
5007 my $array = $$names{$name}->{$key};
5008 if (defined $$array[0]) {
5009 &$callback("$vc:\n");
5010 foreach my $file (@
$array) {
5011 if (defined $self->{'flag_overrides'}->{$vc} &&
5012 defined $self->{'flag_overrides'}->{$vc}->{$file} &&
5013 defined $self->{'flag_overrides'}->{$vc}->{$file}->{'gendir'}) {
5014 &$callback(join(' ', map {/ / ?
"\"$_\"" : $_} ($file,
5015 $self->{'flag_overrides'}->{$vc}->{$file}->{'gendir'})) . "\n");
5018 &$callback("$file\n");
5026 if ($self->exe_target()) {
5027 my $exeout = $self->get_assignment('exeout');
5028 &$callback("exe_output:\n");
5029 &$callback((defined $exeout ?
$self->relative($exeout) : '') .
5030 ' ' . $self->get_assignment('exename') . "\n");
5032 elsif ($self->lib_target()) {
5033 my $shared = $self->get_assignment('sharedname');
5034 my $static = $self->get_assignment('staticname');
5035 my $dllout = $self->relative($self->get_assignment('dllout'));
5036 my $libout = $self->relative($self->get_assignment('libout'));
5038 &$callback("lib_output:\n");
5040 if (defined $shared && $shared ne '') {
5041 &$callback((defined $dllout ?
$dllout : $libout) . " $shared\n");
5043 if ((defined $static && $static ne '') &&
5044 (defined $dllout || !defined $shared ||
5045 (defined $shared && $shared ne $static))) {
5046 &$callback("$libout $static\n");
5056 my $progress = $self->get_progress_callback();
5058 &$progress() if (defined $progress);
5060 if ($self->check_features($self->get_assignment('requires'),
5061 $self->get_assignment('avoids'),
5063 my $webapp = $self->get_assignment('webapp');
5064 my $ntwp = $self->need_to_write_project();
5065 if ($webapp || $ntwp) {
5066 if ($webapp && !$self->webapp_supported()) {
5067 $self->warning("Web Applications are not supported by this type.");
5070 ## A return value of 2 from need_to_write_project() indicates
5071 ## that the only reason that we need to write the project is that
5072 ## there are custom input files (i.e., no source or resource
5074 $self->process_assignment('custom_only', '1') if ($ntwp == 2);
5076 if ($self->get_assignment('custom_only')) {
5077 $self->remove_non_custom_settings();
5080 if ($self->{'escape_spaces'}) {
5081 foreach my $name ('exename', 'sharedname', 'staticname',
5082 'exeout', 'dllout', 'libout') {
5083 my $value = $self->get_assignment($name);
5084 if (defined $value && $value =~ s/(\s)/\\$1/g) {
5085 $self->process_assignment($name, $value);
5088 foreach my $key (keys %{$self->{'valid_components'}}) {
5089 my $names = $self->{$key};
5090 foreach my $name (keys %$names) {
5091 foreach my $key (keys %{$$names{$name}}) {
5092 foreach my $file (@
{$$names{$name}->{$key}}) {
5093 $file =~ s/(\s)/\\$1/g;
5100 ## Hook for implementing type-specific behavior.
5101 ($status, $error) = $self->pre_write_output_file($webapp);
5103 return $status, $error;
5105 ## We don't need to pass a file name here. write_output_file()
5106 ## will determine the file name for itself.
5107 ($status, $error) = $self->write_output_file($webapp);
5109 ## Write the .ins file if the user requested it and we were
5111 if ($self->{'generate_ins'} && $status) {
5112 ($status, $error) = $self->write_install_file();
5116 elsif ($self->warn_useless_project()) {
5117 my $msg = $self->transform_file_name($self->project_file_name()) .
5118 " has no useful targets.";
5120 if ($self->{'current_input'} eq '') {
5121 $self->information($msg);
5124 $self->warning($msg);
5129 return $status, $error;
5133 sub get_project_info
{
5134 return $_[0]->{'project_info'};
5138 sub get_lib_locations
{
5139 if ($_[0]->{'pid'} eq 'child') {
5141 for my $k (sort { substr($a, 0 , index ($a, '|')) <=>
5142 substr ($b, 0, index ($b, '|')) } keys %{$_[0]->{'lib_locations'}}) {
5144 # if we are a worker, we need to strip leading 'number|'
5145 my $x = $_[0]->{'lib_locations'}->{$k};
5148 $lib_locs->{substr ($k, index ($k, '|') + 1)} = $x;
5153 return $_[0]->{'lib_locations'};
5158 sub get_inheritance_tree
{
5159 return $_[0]->{'inheritance_tree'};
5163 sub set_component_extensions
{
5165 my $vc = $self->{'valid_components'};
5166 my $ec = $self->{'exclude_components'};
5168 foreach my $key (keys %$vc) {
5169 my $ov = $self->override_valid_component_extensions($key,
5171 $$vc{$key} = $ov if (defined $ov);
5174 foreach my $key (keys %$ec) {
5175 my $ov = $self->override_exclude_component_extensions($key,
5177 $$ec{$key} = $ov if (defined $ov);
5182 sub get_component_extensions
{
5183 my($self, $comp) = @_;
5185 if (defined $self->{'valid_components'}->{$comp}) {
5186 ## Build up an array of extensions. Since they are stored as regular
5187 ## expressions, we need to remove the escaped period to provide the
5188 ## minimal amount of text for each extension to provide maximum
5189 ## flexibility within the project template.
5190 foreach my $re (@
{$self->{'valid_components'}->{$comp}}) {
5192 $ext[$#ext] =~ s/\\\.//;
5199 sub set_source_listing_callback
{
5200 my($self, $cb) = @_;
5201 $self->{'source_callback'} = $cb;
5208 ## Only put data structures that need to be cleared
5209 ## out when the mpc file is done being read, not at the
5210 ## end of each project within the mpc file. Those go in
5211 ## the closing curly brace section of parse_line().
5212 $self->{'project_info'} = [];
5213 $self->{'lib_locations'} = {};
5214 $self->reset_generating_types();
5218 sub add_default_matching_assignments
{
5220 my $lang = $self->get_language();
5222 foreach my $key (keys %{$language{$lang}->[0]}) {
5223 push(@
{$language{$lang}->[2]->{$key}}, @default_matching_assignments)
5224 if (!StringProcessor
::fgrep
($default_matching_assignments[0],
5225 $language{$lang}->[2]->{$key}));
5230 sub reset_generating_types
{
5232 my $lang = $self->get_language();
5233 my %reset = ('valid_components' => $language{$lang}->[0],
5234 'custom_only_removed' => $language{$lang}->[0],
5235 'exclude_components' => $language{$lang}->[1],
5236 'matching_assignments' => $language{$lang}->[2],
5237 'generated_exts' => {},
5238 'combined_custom' => {},
5239 'valid_names' => \
%validNames,
5242 foreach my $r (keys %reset) {
5244 foreach my $key (keys %{$reset{$r}}) {
5245 $self->{$r}->{$key} = $reset{$r}->{$key};
5249 $self->{'custom_types'} = {};
5250 $self->{'define_custom_parent'} = {};
5252 ## Allow subclasses to override the default extensions
5253 $self->set_component_extensions();
5257 sub get_template_input
{
5259 my $lang = $self->get_language();
5261 ## This follows along the same logic as read_template_input() by
5262 ## checking for exe target and then defaulting to a lib target
5263 if ($self->exe_target()) {
5264 if ($self->get_static() == 1) {
5265 return $self->{'lib_exe_template_input'}->{$lang}->{$tikey};
5268 return $self->{'dll_exe_template_input'}->{$lang}->{$tikey};
5272 if ($self->get_static() == 1) {
5273 return $self->{'lib_template_input'}->{$lang}->{$tikey};
5276 return $self->{'dll_template_input'}->{$lang}->{$tikey};
5280 sub update_project_info
{
5281 my($self, $tparser, $append, $names, $sep) = @_;
5283 $sep = '' if (!defined $sep);
5285 ## Append the values of all names into one string
5286 my $ncount = scalar(@
$names) - 1;
5287 for(my $i = 0; $i <= $ncount; $i++) {
5288 $value .= $self->translate_value(
5290 $tparser->get_value_with_default($$names[$i]));
5291 $value .= $sep if ($i != $ncount);
5294 ## There may be more than one template associated with this project
5295 ## creator. If there is, we can only add one generated file and we
5296 ## rely on the project creator to tell us which template generates the
5297 ## file that we need to track.
5298 if ($self->file_visible($self->{'current_template'})) {
5299 ## If we already have an array, take the one off the top. Otherwise,
5300 ## create a new one which will be added below.
5301 my $arr = ($append && defined $self->{'project_info'}->[0] ?
5302 pop(@
{$self->{'project_info'}}) : []);
5304 ## Set up the hash table when we are starting a new project_info
5305 $self->{'project_info_hash_table'} = {} if (!$append);
5307 ## If we haven't seen this value yet, put it on the array
5308 if (!defined $self->{'project_info_hash_table'}->{"@$names $value"}) {
5309 $self->{'project_info_hash_table'}->{"@$names $value"} = 1;
5310 push(@
$arr, $value);
5313 ## Always push the array back onto the project_info
5314 push(@
{$self->{'project_info'}}, $arr);
5321 sub access_pi_values
{
5326 ## This will use the keys left in @_ as indices into the project
5327 ## info array. But, if the user wants configurations, we need to
5328 ## pop that key off and access it along with all the rest of the
5329 ## elements in the array. The CONFIGURATIONS key should always
5330 ## be last if it's included at all. If it's not, the caller will
5331 ## only receive the first configuration instead of all of them.
5332 if ($_[$#_] == CONFIGURATIONS
) {
5333 my $last = scalar(@
{$$pjs{$proj}}) - 1;
5335 return @
{$$pjs{$proj}}[@_], @
{$$pjs{$proj}}[CONFIGURATIONS
..$last];
5338 return @
{$$pjs{$proj}}[@_];
5343 my($self, $names, $value, $tp) = @_;
5344 my $atemp = $self->get_addtemp();
5346 ## Perform any additions, subtractions
5347 ## or overrides for the template values.
5348 foreach my $name (@
$names) {
5349 if (defined $name && defined $atemp->{lc($name)}) {
5350 my $lname = lc($name);
5354 ## If the template variable is a complex name, then we need to make
5355 ## sure that the mapped value belongs to the correct type based on
5356 ## the base of the complex name. The $tp (TemplateParser) variable
5357 ## will, in the majority of all calls to this method, be defined so
5358 ## it is checked second to avoid checking it if the name isn't
5360 if ($base =~ /(.+)\->/ && defined $tp) {
5361 my $v = $tp->get_value($1);
5364 foreach my $val (@
{$atemp->{$lname}}) {
5365 if (defined $$val[3]) {
5366 my $mapped = $self->{'valid_names'}->{$$val[3]};
5367 if (defined $mapped && UNIVERSAL
::isa
($mapped, 'ARRAY')) {
5368 $found = 1 if ($v ne $$mapped[0]);
5377 my $replace = (defined $self->{'valid_names'}->{$base} &&
5378 ($self->{'valid_names'}->{$base} & 0x04) == 0);
5379 foreach my $val (@
{$atemp->{$lname}}) {
5380 if ($replace && index($$val[1], '<%') >= 0) {
5381 $$val[1] = $self->replace_parameters($$val[1],
5382 $self->{'command_subs'});
5384 my $arr = $self->create_array($$val[1]);
5386 if (!defined $value) {
5389 if (UNIVERSAL
::isa
($value, 'ARRAY')) {
5390 ## Avoid adding duplicates. If the existing array contains
5391 ## the value already, remove it from the newly created array.
5392 for(my $i = 0; $i < scalar(@
$value); $i++) {
5393 if (StringProcessor
::fgrep
($$value[$i], $arr)) {
5394 splice(@
$value, $i, 1);
5399 ## We need to make $value a new array reference ($arr)
5400 ## to avoid modifying the array reference pointed to by $value
5401 unshift(@
$arr, @
$value);
5405 $value .= " $$val[1]";
5408 elsif ($$val[0] < 0) {
5409 if (defined $value) {
5411 if (UNIVERSAL
::isa
($value, 'ARRAY')) {
5415 $parts = $self->create_array($value);
5419 foreach my $part (@
$parts) {
5421 push(@
$value, $part) if (!StringProcessor
::fgrep
($part, $arr));
5427 ## If the user set the variable to empty, then we need to
5428 ## set the value to undef
5429 $value = (defined $$arr[0] ?
$arr : undef);
5441 my($self, $marker) = @_;
5443 my $thash = $self->{'verbatim'}->{$self->{'pctype'}};
5445 if (defined $thash) {
5446 if (defined $thash->{$marker}) {
5447 my $crlf = $self->crlf();
5448 foreach my $line (@
{$thash->{$marker}}) {
5449 $str = '' if (!defined $str);
5450 $str .= $self->process_special($line) . $crlf;
5454 $self->{'verbatim_accessed'}->{$self->{'pctype'}}->{$marker} = 1;
5463 sub generate_recursive_input_list
{
5464 my($self, $dir, $exclude) = @_;
5465 return $self->extension_recursive_input_list($dir,
5467 $ProjectCreatorExtension);
5471 sub get_modified_project_file_name
{
5472 my($self, $name, $ext) = @_;
5473 my $nmod = $self->get_name_modifier();
5475 ## We don't apply the name modifier to the project file
5476 ## name if we have already applied it to the project name
5477 ## since the project file name comes from the project name.
5478 if (defined $nmod && !$self->get_apply_project()) {
5479 $nmod =~ s/\*/$name/g;
5486 sub get_valid_names
{
5487 return $_[0]->{'valid_names'};
5491 sub get_feature_parser
{
5492 return $_[0]->{'feature_parser'};
5496 sub preserve_assignment_order
{
5497 my($self, $name) = @_;
5498 my $mapped = $self->{'valid_names'}->{$name};
5500 ## Only return the value stored in the valid_names hash map if it's
5501 ## defined and it's not an array reference. The array reference is
5502 ## a keyword mapping and all mapped keywords should have preserved
5503 ## assignment order.
5504 if (defined $mapped && !UNIVERSAL
::isa
($mapped, 'ARRAY')) {
5505 return ($mapped & 1);
5512 sub add_to_template_input_value
{
5513 my($self, $name) = @_;
5514 my $mapped = $self->{'valid_names'}->{$name};
5516 ## Only return the value stored in the valid_names hash map if it's
5517 ## defined and it's not an array reference. The array reference is
5518 ## a keyword mapping and no mapped keywords should be added to
5519 ## template input variables.
5520 if (defined $mapped && !UNIVERSAL
::isa
($mapped, 'ARRAY')) {
5521 return ($mapped & 2);
5528 sub dependency_combined_static_library
{
5530 return defined $ENV{MPC_DEPENDENCY_COMBINED_STATIC_LIBRARY
};
5534 sub translate_value
{
5535 my($self, $key, $val) = @_;
5537 if ($key eq 'after' && $val ne '') {
5538 my $arr = $self->create_array($val);
5541 if ($self->require_dependencies()) {
5542 foreach my $entry (@
$arr) {
5543 if ($self->get_apply_project()) {
5544 my $nmod = $self->get_name_modifier();
5545 if (defined $nmod) {
5546 $nmod =~ s/\*/$entry/g;
5550 $val .= '"' . ($self->dependency_is_filename() ?
5551 $self->project_file_name($entry) : $entry) . '" ';
5560 sub requires_parameters
{
5563 return $custom{$_[1]};
5567 sub project_file_name
{
5568 my($self, $name, $template) = @_;
5570 ## Fill in the name if one wasn't provided
5571 $name = $self->get_assignment('project_name') if (!defined $name);
5573 ## Apply the transformation so that any name modifiers are utilized.
5574 return $self->get_modified_project_file_name(
5575 $self->project_file_prefix() .
5576 $self->transform_file_name($name),
5577 $self->project_file_extension());
5581 sub remove_non_custom_settings
{
5584 ## Remove any files that may have automatically been added
5585 ## to this project. If they were explicitly added, then we
5586 ## will leave them in the project.
5587 foreach my $key (keys %{$self->{'custom_only_removed'}}) {
5588 if ($self->{'defaulted'}->{$key}) {
5593 ## Unset the exename, sharedname and staticname
5594 $self->process_assignment('exename', undef);
5595 $self->process_assignment('sharedname', undef);
5596 $self->process_assignment('staticname', undef);
5600 sub remove_wanted_extension
{
5601 my($self, $name, $array) = @_;
5603 foreach my $wanted (@
$array) {
5604 return $name if ($name =~ s/$wanted$//);
5607 ## If the user provided file does not match any of the
5608 ## extensions specified by the custom definition, we need
5609 ## to remove the extension or else this file will not be
5610 ## added to the project.
5611 $name =~ s/\.[^\.]+$//;
5617 if (index($_[1], 'install') >= 0) {
5618 my $resolved = $_[1];
5619 if ($resolved =~ s/(.*::)install$/$1exeout/) {
5621 elsif ($resolved eq 'install') {
5622 $resolved = 'exeout';
5630 sub create_feature_parser
{
5631 my($self, $features, $feature) = @_;
5632 my $gfeature = $self->{'gfeature_file'};
5633 my $typefeaturef = (defined $gfeature ?
5634 $self->mpc_dirname($gfeature) . '/' : '') .
5635 $self->{'pctype'} . '.features';
5636 $typefeaturef = undef if (! -r
$typefeaturef);
5637 if (defined $feature && $feature !~ /[\/\\]/i
) {
5638 my $searched = $self->search_include_path($feature);
5639 $feature = $searched if (defined $searched);
5641 my $fp = new FeatureParser
($features,
5646 my $slo = $fp->get_value($static_libs_feature);
5647 if (!defined $slo) {
5648 my $sval = $self->get_static() || 0;
5649 $fp->parse_line(undef,
5650 $static_libs_feature . ' = ' . $sval);
5657 sub restore_state_helper
{
5658 my($self, $skey, $old, $new) = @_;
5660 if ($skey eq 'feature_file') {
5661 if ($self->{'features_changed'} ||
5662 !(!defined $old && !defined $new ||
5663 (defined $old && defined $new && $old eq $new))) {
5664 ## Create a new feature parser. This relies on the fact that
5665 ## 'features' is restored first in restore_state().
5666 $self->{'feature_parser'} = $self->create_feature_parser(
5667 $self->get_features(), $new);
5668 $self->{'features_changed'} = undef;
5671 elsif ($skey eq 'ti') {
5672 my $lang = $self->get_language();
5673 my @keys = keys %$old;
5674 @keys = keys %$new if (!defined $keys[0]);
5675 foreach my $key (@keys) {
5676 if (!defined $$old{$key} || !defined $$new{$key} ||
5677 $$old{$key} ne $$new{$key}) {
5678 ## Clear out the template input reader that we're currently set
5680 $self->{$key . '_template_input'}->{$lang}->{$tikey} = undef;
5684 elsif ($skey eq 'features') {
5685 ## If the user has changed the 'features' setting, then we need to
5686 ## make sure that we create a new feature parser regardless of
5687 ## whether or not the feature file has changed.
5688 $self->{'features_changed'} = ("@$old" ne "@$new");
5690 elsif ($skey eq 'language') {
5692 $self->add_default_matching_assignments();
5698 sub get_initial_relative_values
{
5699 return $_[0]->{'expanded'}, 1;
5702 sub add_main_function
{
5703 my $langmain = shift;
5705 ## See if a language was supplied.
5706 if ($langmain =~ /([^:]+):(.+)/) {
5707 ## If the language supplied is not one that we know about, return an
5709 return 'Invalid language: ' . $1 if (!defined $language{$1});
5711 ## Otherwise, add it to the list for the language.
5712 push(@
{$mains{$1}}, $2);
5715 ## No language was supplied, so add the main to all of the languages
5717 foreach my $lang (keys %language) {
5718 push(@
{$mains{$lang}}, $langmain);
5722 ## Return no error message.
5726 sub get_resource_tag
{
5728 my $lang = $self->get_language();
5730 ## Not all entries in the %language map have a resource tag.
5731 ## For this, we will just return the tag for C++ since it probably
5732 ## doesn't really matter anyway.
5733 return defined $language{$lang}->[5] ?
$language{$lang}->[5] : $cppresource;
5736 sub find_command_helper
{
5737 my($self, $tag) = @_;
5739 ## No tag results in no command helper
5740 return undef if (!defined $tag);
5742 ## See if we have a command helper for this tag
5743 my $ch = CommandHelper
::get
($tag);
5745 ## Give the command helper a reference to the creator. The helper
5746 ## can benefit from many of the infrastructure functions available.
5747 $ch->set_creator($self);
5751 ## None for the base define custom, try again with the parent
5752 return $self->find_command_helper($self->{'define_custom_parent'}->{$tag});
5755 sub get_dependency_attribute
{
5756 ## Return the dependency attribute specified as the first parameter to
5757 ## this method (not counting the ProjectCreator object).
5758 return $_[0]->{'dependency_attributes'}->{$_[1]};
5761 sub valid_project_name
{
5762 #my($self, $name) = @_;
5763 return $_[1] !~ /[\/\\=\?:&"<>|#%]/;
5767 sub append_flag_override {
5768 ## Append $value to the flag_overrides for <$tag, $input, $key>
5774 return if !defined $value || $value eq '';
5775 my %join = ('postcommand' => ' ' . $self->{'command_subs'}->{'and'} . ' ');
5776 my $sep = ($join{$key}) ? $join{$key} : ' ';
5777 my $fo = $self->{'flag_overrides'}->{$tag};
5778 $fo->{$input}->{$key} .= ($fo->{$input}->{$key} ? $sep : '') . $value;
5782 # Some project types can't represent the same input file being used by
5783 # more than one custom type. This function will look for such cases and
5784 # combine them into a single invocation of a synthetic custom type that
5785 # inherits properties from both of them.
5786 # Project types needing this transformation should call this function from
5787 # their overridden pre_write_output_file() method.
5788 sub combine_custom_types {
5790 my %input; # (input_file_name => [custom1_files, custom2_files], ...)
5791 my $fo = $self->{'flag_overrides'};
5792 my %gendir; # (input_file_name => {directory => count}, ...)
5794 # Build the %input data structure as an index of how each input file is used.
5795 foreach my $tag (keys %{$self->{'generated_exts'}}) {
5796 foreach my $complist (values %{$self->{$tag}}) {
5797 foreach my $group (keys %$complist) {
5798 foreach my $in (@{$complist->{$group}}) {
5799 # only add to %input if some command would be run for this type
5801 $ustyle =~ s/\\/\//g if $self->{'convert_slashes'};
5802 my $dir = $self->mpc_dirname($ustyle);
5803 my $of = (!defined $fo->{$tag} ? undef :
5804 (defined $fo->{$tag}->{$ustyle} ? $ustyle :
5805 (defined $fo->{$tag}->{$dir} ? $dir : undef)));
5806 if ($self->{'generated_exts'}->{$tag}->{'command'} ||
5807 (defined $of && $fo->{$tag}->{$of}->{'command'})) {
5808 push(@{$input{$in}}, $tag);
5809 if (defined $fo->{$tag}->{$of}->{'gendir'}) {
5810 $gendir{$in}->{$fo->{$tag}->{$of}->{'gendir'}}++;
5818 # For each input file used in multiple custom types, move it into the new
5820 foreach my $in (keys %input) {
5821 next if scalar @{$input{$in}} < 2;
5822 my $combo_tag = join('_and_', map {/(.+)_files$/; $1} @{$input{$in}})
5824 if (!$self->{'combined_custom'}->{$combo_tag}) {
5825 $self->{'combined_custom'}->{$combo_tag} = $input{$in};
5826 $self->process_assignment_add('custom_types', $combo_tag);
5827 my $ge = $self->{'generated_exts'}->{$combo_tag} = {};
5829 my $combo_vc = $self->{'valid_components'}->{$combo_tag} = [];
5830 foreach my $tag (@{$input{$in}}) {
5831 StringProcessor::merge($combo_vc, $self->{'valid_components'}->{$tag});
5832 if ($self->{'generated_exts'}->{$tag}->{'libpath'}) {
5833 $ge->{'libpath'} .= ($ge->{'libpath'} ?
5834 $self->{'command_subs'}->{'pathsep'} : '') .
5835 $self->{'generated_exts'}->{$tag}->{'libpath'};
5838 $fo->{$combo_tag} = {};
5839 my @keys = keys %custom;
5840 push(@keys, @default_matching_assignments);
5841 $self->{'matching_assignments'}->{$combo_tag} = \@keys;
5844 my @gendir_keys = keys %{$gendir{$in}};
5845 if ($#gendir_keys == 0) {
5846 $fo->{$combo_tag}->{$in}->{'gendir'} = $gendir_keys[0];
5849 # Add to new type -- groups aren't relevant here, so just use the default
5850 push(@{$self->{$combo_tag}->{'default'}->{'default_group'}}, $in);
5852 # Remove from existing types
5853 my $override_recurse = 0;
5854 foreach my $tag (@{$input{$in}}) {
5855 foreach my $complist (values %{$self->{$tag}}) {
5856 foreach my $group (keys %$complist) {
5857 foreach my $idx (0 .. $#{$complist->{$group}}) {
5858 if ($complist->{$group}->[$idx] eq $in) {
5859 splice(@{$complist->{$group}}, $idx, 1);
5864 if (defined $fo->{$tag} && defined $fo->{$tag}->{$in} &&
5865 defined $fo->{$tag}->{$in} && $fo->{$tag}->{$in}->{'recurse'}) {
5866 ++$override_recurse;
5868 foreach my $k ('dependent', 'dependent_libs', 'postcommand') {
5869 $self->append_flag_override($combo_tag, $k, $in,
5870 (defined $fo && defined $fo->{$k})
5872 : $self->{'generated_exts'}->{$tag}->{$k});
5876 # If all existing uses agree to recurse, the new type should recurse too
5877 if ($override_recurse == scalar @{$input{$in}}) {
5878 $fo->{$combo_tag}->{$in}->{'recurse'} = 1;
5887 # ************************************************************
5888 # Accessors used by support scripts
5889 # ************************************************************
5892 return \%validNames;
5895 sub getValidComponents {
5896 my $language = shift;
5897 return (defined $language{$language} ? $language{$language}->[0] : undef);
5900 # ************************************************************
5901 # Virtual Methods To Be Overridden
5902 # ************************************************************
5904 sub get_builtin_output {
5905 #my($self, $input) = @_;
5909 sub languageSupported {
5911 return $_[0]->get_language() eq Creator::cplusplus;
5915 #my($self, $template) = @_;
5919 sub webapp_supported {
5925 sub use_win_compatibility_commands {
5927 return $ENV{MPC_USE_WIN_COMMANDS};
5931 sub post_file_creation {
5944 sub validated_directory {
5945 my($self, $dir) = @_;
5949 sub get_quote_symbol {
5954 sub get_escaped_quote_symbol {
5971 sub get_and_symbol {
5983 sub get_cmdsep_symbol {
5989 sub dollar_special {
5995 sub expand_variables_from_template_values {
6001 sub require_dependencies {
6007 sub dependency_is_filename {
6020 sub project_file_prefix {
6026 sub project_file_extension {
6032 sub override_valid_component_extensions {
6039 sub override_exclude_component_extensions {
6046 sub get_dll_exe_template_input_file {
6047 #my($self, $tkey) = @_;
6052 sub get_lib_exe_template_input_file {
6053 my($self, $tkey) = @_;
6054 return $self->get_dll_exe_template_input_file($tkey);
6058 sub get_lib_template_input_file {
6059 my($self, $tkey) = @_;
6060 return $self->get_dll_template_input_file($tkey);
6064 sub get_dll_template_input_file {
6065 #my($self, $tkey) = @_;
6071 return $_[0]->{'pctype
'};
6074 sub requires_forward_slashes {
6078 sub warn_useless_project {
6082 sub pre_write_output_file {