xref: /trunk/main/icu/createmak.pl (revision b339e61b0e4c15004c00f5d1a4e0671656d90a8f)
1:
2eval 'exec perl -wS $0 ${1+"$@"}'
3    if 0;
4#**************************************************************
5#
6#  Licensed to the Apache Software Foundation (ASF) under one
7#  or more contributor license agreements.  See the NOTICE file
8#  distributed with this work for additional information
9#  regarding copyright ownership.  The ASF licenses this file
10#  to you under the Apache License, Version 2.0 (the
11#  "License"); you may not use this file except in compliance
12#  with the License.  You may obtain a copy of the License at
13#
14#    http://www.apache.org/licenses/LICENSE-2.0
15#
16#  Unless required by applicable law or agreed to in writing,
17#  software distributed under the License is distributed on an
18#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19#  KIND, either express or implied.  See the License for the
20#  specific language governing permissions and limitations
21#  under the License.
22#
23#**************************************************************
24
25
26#
27use XML::Parser;
28# ------------------------------------------------------------------------
29# Other global stuff
30$is_debug = exists $ENV{'debug'};
31$enable_symbols = exists $ENV{'ENABLE_SYMBOLS'};
32my $path = $ENV{'INPATH'} . "/";
33my $quot = '"';
34my %template_hash=();
35my $architecture = "x86";
36my %vcproj_hash=();
37# ------------------------------------------------------------------------
38# Global stuff for parsing the *.vcproj files (XML::Parser)
39#
40my $ConfigurationGlobal = 1; # Release = 1, Debug=0
41my $Configuration = undef;
42my %configelements = ();
43my %files = ();
44my %files2copy = ();
45my %files_special = ();
46my $Release = 1;
47     # Release = 1, Debug = 0, undef = 2
48my $file_tmp = "";      # temporary storage for file name
49my $CustomSection = 0;
50# ------------------------------------------------------------------------
51# ------------------------------------------------------------------------
52# e.g. %object_hash with Key = blabla.cpp
53# contains a Hash:
54# Header: "..\\common\\unicode\\utypes.h ..\\common\\unicode\\uset.h"
55# CFlags: Common (set in templates file) or special sequence
56# CDefs:  Common (set in templates file) or special sequence
57# ------------------------------------------------------------------------
58my $configfile = shift;
59my $sourcePath = shift;
60if ( !$configfile ) {
61    $configfile = "createmak.cfg";
62}
63if ( !$sourcePath ) {
64    $inpath = $ENV{"INPATH"};
65    $sourcePath = $inpath . "\\misc\\build\\icu\\source";
66}
67$dir = "";
68$header = "";
69$sep = "\\\\";
70
71%project_by_id =();
72%project_by_name = ();
73%project_dependencies = ();
74my @builddeps = prepare_allinone_all_mak(\%project_by_id,\%project_by_name,\%project_dependencies,$sourcePath);
75
76fillTemplateHash($configfile);
77# The architecture is indicated in the configuration file
78$architecture=${$template_hash{"Architecture"}}[0];
79chomp $architecture;
80print "Architecture: $architecture\n" if ($is_debug);
81
82create_allinone_all_mak(\@builddeps,\%project_by_id,$sourcePath);
83my @dirs = ();
84foreach $projectname(keys %project_by_name)
85{
86    my $dir = $project_by_name{$projectname}[1];
87    $dir =~ /\.\.\\(.+)\\(.+)\.vcproj/;
88    my $dir1 = $1;
89    my $dir2 = $2;
90    if ( $dir1 !~ /$dir2$/ ) {
91        $dir1 .= "\.$dir2";
92    }
93    print "$dir1 - $dir2\n" if ($is_debug);
94    push @dirs, $dir1;
95}
96
97# set nonpro switch (linking against debug runtime if nonpro=1)
98my $nonpro = ($ENV{"PROEXT"} ne ".pro");
99print "Non Product Build" if ($nonpro);
100
101foreach $dir(@dirs)
102{
103    next if ($dir eq "data.makedata"); # very special don't overwrite this file
104    # ------------------------------------------------------------------------
105    # Reset global stuff for parsing the *.vcproj files (XML::Parser)
106    #
107    $Configuration = $ConfigurationGlobal; # Release = 1, Debug=0
108    %configelements = ();
109    %files = ();
110       # contains all relevant *.c,*.cpp,*.h,*.rc files
111    %files2copy = ();
112    %files_special = ();
113    $Release = 2;
114     # Release = 1, Debug = 0, undef = 2
115    $file_tmp = "";      # temporary storage for file name
116    $CustomSection = 0;
117    # ------------------------------------------------------------------------
118
119    my $extra_mak = "";
120    ($dir, $extra_mak) = handle_extra_mak_files($dir); # handle e.g. tools/genrb.derb entires
121
122    my @mak=(); # Array for make file *.mak
123    my %deps=();
124    my %object_hash=();
125    my %collected_header=();
126    my %collect_header_target_hash=();
127    my %collect_object_target_hash=();
128    my $vcproj_file = "";
129    my $resource_file = "";
130
131    # $dir : common,i18n,...
132    chomp $dir;
133    next if ( $dir eq "" );
134    my $fullpath = $sourcePath . "\\" . $dir;
135    if ( $extra_mak eq "" ) {
136        if ($dir =~ /(.+)+\\(.+)$/)
137        {
138            $vcproj_file = $fullpath ."\\$2.vcproj";
139        } else
140        {
141            $vcproj_file = $fullpath ."\\$dir.vcproj";
142        }
143    } else
144    {
145        $vcproj_file = $fullpath . "\\" . $extra_mak . ".vcproj";
146    }
147
148
149    # Parse the *.vcproj file
150    my $parser = new XML::Parser(ErrorContext => 2);
151    $parser->setHandlers(Start => \&start_handler,
152                 Char  => \&char_handler);
153    $parser->parsefile($vcproj_file);
154    if ( $file_tmp ) {
155        # save a file which hasn't been saved yet
156        $files{ $file_tmp } = 1;        # save it now
157        $file_tmp = "";                 # has been saved now reset it
158    }
159
160    # is there a resource file?
161    foreach $i (keys %files)
162    {
163        if ($i =~ /\.rc/)
164        {
165            $resource_file = $i;
166        }
167    }
168    # Fill hash %deps for dependencies for all files in directory ($testdir)
169    # %files contains all relevant files from *.vcproj
170
171    getAllFilesDeps($fullpath,\%deps,\%files);
172    my $includedir = $configelements{"Release"}{"OutputDirectory"};     # e.g. OutputDirectory = ..\..\lib
173    $includedir =~ s/lib/include/;
174    foreach $file( sort keys %deps)
175    {
176        $file =~ /(.+)\.(.+)/;
177        my $name = $1;
178        my $ext  = $2;
179        next if (!defined $name);
180        $object = "\$(INTDIR)\\" . "$name.obj";
181        $collect_object_target_hash{$object}=1;
182
183        createMakDepSection($dir,$name,$ext,$deps{$file},\@mak,\%files_special);
184    }
185    my %all_target_hash=();
186    foreach $header(sort keys %files2copy)
187    {
188        my $dir;
189        my $file;
190        #$pathdepth = "..\\..";
191        $file = $header;
192        $header =~ s/^\.\\//;
193        $inputpath = $file;
194        $target = $includedir . "\\" . $header;
195        $target =~ /.+\\(.+)\\.+$/;
196        $targetpath = $configelements{"Release"}{"CommandLine"};
197        chomp $targetpath;
198        # set %all_target_hash and @mak
199        createCopySection($file,$inputpath,$target,$targetpath,\@mak,\%all_target_hash);
200        $collect_header_target_hash{$target}=1;
201    }
202    my $test = $configelements{"Release"}{"OutputFile"};
203    $all_target_hash{$test}=1;
204
205    # set name of the *.mak file
206    my $mak_file="";
207    if ( $extra_mak eq "" ) {
208        $mak_file = $vcproj_file;
209        $mak_file =~ s/vcproj/mak/;
210    } else
211    {
212        # extra_mak eg. derb, stringperf
213        $mak_file = $fullpath . "\\$extra_mak" . "\.mak";
214    }
215
216    # generate the content of the *.mak file
217    # in @mak array
218    print "extra_mak=$extra_mak\n" if ($is_debug);
219    print "mak_file=$mak_file\n" if ($is_debug);
220    open(MAKFILE, ">$mak_file") || die "Can't open $mak_file\n";
221    print_all_target($fullpath, \%all_target_hash);
222
223    # $extra_mak handles further *.mak files in a directory
224    print_flags($dir,$extra_mak,'CFlags',$nonpro);    # depends on directory
225    print_simple_flag("Rules");
226    print_simple_flag("Link");
227    print_common_linkflags();
228#    print_flags($fullpath,$extra_mak,'LinkFlags'); # depends on directory
229#    print_lib32_objs($fullpath,$extra_mak,\%collect_object_target_hash,$resource_file);
230    print_flags($dir,$extra_mak,'LinkFlags'); # depends on directory
231    print_lib32_objs($dir,$extra_mak,\%collect_object_target_hash,$resource_file);
232
233    # write @mak array into the *.mak file
234    foreach $line(@mak)
235    {
236        print MAKFILE $line;
237    }
238    $|=1;
239    print "."; # user entertainment
240    $|=0;
241}
242print "\ndone\n";
243exit;
244
245############################################################################
246sub getKey      #01.04.2008 09:46
247############################################################################
248 {
249    my $line = shift;
250    $line =~ /\[(.+)\]/;
251    return $1;
252}   ##getKey
253
254############################################################################
255sub fillTemplateHash        #01.04.2008 10:48
256############################################################################
257 {
258    my $file = shift;
259    open (TEMPLATE, "< $file") || die "Can't open template file $file\n";
260    my $key = "";
261    while ( $line=<TEMPLATE> ) {
262        if ( $line =~ /\[.+\]/ ) {
263            print $line if ($is_debug);
264            if ( $key ne "" ) {
265                $template_hash{$key}=[@cmdlines];
266                @cmdlines="";
267                $key="";
268            }
269            $key = getKey( $line );
270        } else
271        {
272            push @cmdlines, $line;
273        }
274    } # while
275}   ##fillTemplateHash
276
277############################################################################
278sub createCopySection       #01.04.2008 11:37
279############################################################################
280 {
281    my $header     = shift;
282    my $inputpath  = shift;
283    my $target     = shift;
284    my $targetpath = shift;
285    my $ref_make_file = shift; # Array written later to make file *.mak
286    my $ref_all_target_hash = shift;  # reference to fill all_target_hash;
287    if ( $target !~ /\\include/ && $target !~ /\\bin/) {
288        return; # $target contains nonsense
289    }
290    if ( !$targetpath ) {
291        # $targetpath is empty! (Due to missing entry in *.vcproj file)
292        # Generate $targetpath here from $target
293        my $t = $target;
294        $t =~ /(.+)\\(.+)$/;
295        $targetpath = "copy \"\$(InputPath)\" " . $1;
296        chomp $targetpath;
297    }
298    $targetpath =~ s/\r$//; # remove x0A from EOL if the is one
299    my @template = @{$template_hash{"Copy"}};
300    my $line = "";
301    foreach $line(@template)
302    {
303        $line =~ s/<HEADER>/$header/g;
304        $line =~ s/<INPUTPATH>/$inputpath/g;
305        $line =~ s/<TARGET>/$target/g;
306        $line =~ s/<TARGETPATH>/$targetpath/;
307        push @{$ref_make_file}, $line;           # from template
308        $$ref_all_target_hash{$target} = 1;       # "\"$target\" ";
309     # save for target ALL:
310    }
311}   ##createCopySection
312
313############################################################################
314sub createMakDepSection     #01.04.2008 13:36
315############################################################################
316 {
317    # creates the dependency section in the make file
318    my $dir         = shift;
319    my $source      = shift;
320    my $extension   = shift;
321    my $ref_header_list = shift;
322    my $ref_make_file = shift; # Array written later to make file *.mak
323    my $ref_special_file = shift; # hash for special files (compiler flags, include paths)
324    my $header_list = "";
325    my $special_flag = 0;
326
327    return if ( !defined $source );
328    foreach $header(@{$ref_header_list})
329    {
330        if ( ($header =~ /^\.\.\\.+/) && (-e $header )) {
331            $header_list = $header_list . " " . $header; # this header is located in an other directory
332        } else
333        {
334            $header_list = $header_list . " .\\" . $header;
335        }
336    }
337
338    #special handling
339    # compile this file with other compiler switches
340    my $file = $source . "\." . $extension;
341    $dir =~ s/\\/_/;
342    my @template = @{$template_hash{"CFlags_$dir"}};
343    if ( defined $$ref_special_file{"AdditionalIncludeDirectories"}{$file} ) {
344        $special_flag = 1;
345        my $includepath = $$ref_special_file{"AdditionalIncludeDirectories"}{$file};
346        $includepath =~ s/\;/\/I /g;                   # subst ; with /I for multiple paths
347        $line = "CPP_SWITCH_INCLUDE=/I  $includepath\n";
348        push @{$ref_make_file}, $line;
349        foreach $line(@template)
350        {
351            if ( $line =~ /CPP_PROJ/)
352            {
353                $line =~ s/CPP_PROJ=/CPPX_PROJ=/;
354                $line =~ s/\$\(CDEFS\)/\$\(CDEFS\) \$\(CPP_SWITCH_INCLUDE\)/; # include $(CPP_SWITCH_INCLUDE)
355                push @{$ref_make_file}, $line;
356            }
357        }
358    }
359    if ( $$ref_special_file{"DisableLanguageExtensions"}{$file} )
360    {
361        # FALSE = /Ze
362        $special_flag = 1;
363        foreach $line(@template)
364        {
365            if ( $line =~ /CPP_PROJ/)
366            {
367                $line =~ s/CPP_PROJ=/CPPX_PROJ=/;
368                $line =~ s/-Za/-Ze/;
369                if ( $nonpro )
370                {
371                    # if non product link against debug libraries
372                    $line =~ s/-MD/-MDd/;
373                    $line =~ s/-MT/-MTd/;
374                }
375                push @{$ref_make_file}, $line;
376            }
377        }
378    }
379
380    @template = @{$template_hash{"Deps"}};
381    my $line = "";
382    foreach $line(@template)
383    {
384        $line =~ s/<SOURCEFILE>/$source/g;
385        $line =~ s/<EXT>/$extension/g;
386        $line =~ s/<HEADER_LIST>/$header_list/g;
387        push @{$ref_make_file}, $line;
388    }
389
390    if ( $special_flag )
391    {
392        pop @{$ref_make_file}; # remove empty line
393        push @{$ref_make_file},"\t\$(CPP) @<<\n";
394        push @{$ref_make_file},"\t\$(CPPX_PROJ) \$(SOURCE)\n";
395        push @{$ref_make_file},"<<\n\n";
396        $special_flag = 0;
397    }
398
399}   ##createMakDepSection
400
401
402############################################################################
403sub getFilenameFromPath     #10.04.2008 13:03
404############################################################################
405{
406    my $path = shift;
407    $path =~ /.+\\(.+)$/;
408    return $1;
409}   ##getFilenameFromPath
410
411############################################################################
412sub getAllFilesDeps     #08.04.2008 09:39
413############################################################################
414{
415    my $path = shift;
416    my $ref_deps = shift;
417    my $ref_allfiles = shift;       # contains all relevant files from *.vcproj
418    my %local_header_hash=();       # contains all local header
419
420    my @all_files = keys %{$ref_allfiles};
421
422    # collect lokal header names in %header_hash
423    foreach $file(@all_files)
424    {
425        if ( $file =~ /.+\.h/ ) {
426            chomp $file;
427            $local_header_hash{$file} = 1;
428        }
429    }
430
431    foreach $file(@all_files)
432    {
433        my @header_deps=();
434        my $skip = 0;
435
436        $file =~ s/^\.\\//; # remove leading .\
437
438        # exclude sub directories and several file extensions
439        # *.dep,*.h,*.in,*.mak,*.pl,*.txt,*.vcproj.*.rc and origs of patch files (*.*~) and
440        # .cvsignore (files beginning with .)
441        next if ( (-d "$path$sep$file") || ($file =~ /.+(_|\~|dep|h|in|mak|pl|txt|vcproj|rc)$/) || ($file =~ /^\.+./));
442        parse_header_deps($path,$file,\@header_deps,\%local_header_hash);
443        handle_dep_to_other_directory($path,$file,\@header_deps,$$ref_vcproj{$file}) if ($$ref_vcproj{$file});
444        $$ref_deps{$file}=[@header_deps];
445    }
446}   ##getAllFilesDeps
447
448 ############################################################################
449 sub parse_header_deps      #14.06.2006 18:04
450 ############################################################################
451  {
452    # get includes from c/cpp file
453    # call create_deps(path,file,\$link_obj)
454    #
455    my $path = shift;
456    my $cfile = shift;
457    my $ref_header_deps = shift;
458    my $ref_local_header_hash = shift;
459
460    my $fullpath = $path . $sep . $cfile;
461    my $unicodedep="";
462    open(IN, "<$fullpath") || die "can't open $fullpath\n";
463    while ( $line = <IN> ) {
464        next if ($line !~ /^.?\#include.+/); # handle include lines only
465        if ($line =~ /.+?\s(.+)/)
466        {
467            $header = $1;
468            if ( ($header !~ /^<.+/) && ($header !~ /.+\.c.+$/) ) {
469                # no <stdio> etc. header
470                $header =~ s/\s+\/\*.+\*\///; # delete <blanks>/* ... */
471                $header =~ s/\s+\/\/.+//;      # delete <blanks>//......
472                $header =~ s/\//\\/;           # subst. / with \
473                $header =~ s/^\"/\".\\/;
474                $header =~ s/\"//g;
475                $header =~ s/\.\\//;
476                my $test = $$ref_local_header_hash{$header};
477                    my $header_fullpath = $path . "\\" . $header;
478                if ( $test || (($header =~ /\\/) && (-e $header_fullpath))) {
479                    push @{$ref_header_deps}, $header;
480                }
481            }
482        }
483    }
484 }  ##parse_header_deps
485
486############################################################################
487sub handle_dep_to_other_directory       #16.04.2008 15:11
488############################################################################
489{
490    # there has been an additional include directoy detected
491    # now try to find out which header (parsed from c/cpp-file)
492    # comes from this directory by checking: does it exist there?
493    my $path = shift;
494    my $file = shift;
495    my $ref_header_deps = shift;
496    my $path_additional = shift;
497    my $search_path = $path . "\\" . $path_additional;
498    my $counter = 0;
499    foreach $header(@{$ref_header_deps})
500    {
501        my $full_path = $search_path . "\\" . $header;
502        if ( -e "$full_path" )
503        {
504            $$ref_header_deps[$counter] = $path_additional . "\\" . $header;
505        }
506        $counter++
507    }
508}   ##handle_dep_to_other_directory
509
510############################################################################
511sub print_lib32_objs        #18.04.2008 12:54
512############################################################################
513 {
514    # generate Link section
515    my $path = shift;
516    my $extra_mak = shift;
517    my $ref_objecthash = shift;
518    my $resource_file = shift;
519    # output link objects
520    print MAKFILE "LINK32_OBJS= \\\n";
521    # print objects
522    foreach $object(sort keys %{$ref_objecthash})
523    {
524        print MAKFILE "\t$object \\\n";
525    }
526
527    # print *.res if *.rc exists
528    if ( $resource_file ne "" ) {
529        my $res_file = $resource_file;
530        $res_file =~ s/\.rc/\.res/;
531        $res_file =~ /(.+)\\(.+)$/;
532        $res_file = $2;
533        print MAKFILE "\t\$(INTDIR)\\$res_file \\\n";
534    }
535
536    # add import libs and res files
537    print_flags($path,$extra_mak,"AdditionalLinkObjects");
538    my $outfile = $configelements{"Release"}{"OutputFile"};
539
540    # section for linking
541    print_link_template($path,$outfile);
542
543    # section for creating res files
544    # setting for rsc, res target etc.
545    print "resource_file=$resource_file\n" if ($is_debug);
546    print_rsc_template($resource_file) if ($resource_file);
547    print_simple_flag("Special_extra_uconv") if ($outfile =~ /uconv/);
548}   ##print_lib32_objs
549
550############################################################################
551sub print_all_target        #26.06.2008 13:27
552############################################################################
553 {
554    my $path = shift;
555    my $ref_all_target_hash = shift;
556    my $filename = getFilenameFromPath($path);
557    my $outdir = $configelements{"Release"}{"OutputDirectory"};
558    print MAKFILE "NULL=\n";
559    print MAKFILE "OUTDIR=$outdir\n";
560    print MAKFILE "OutDir=$outdir\n";
561    print MAKFILE "INTDIR=.\\Release\n\n";
562    print MAKFILE "ALL: ";
563    foreach $target(sort keys %{$ref_all_target_hash})
564    {
565        if ( $target =~ /\.exe/ ) {
566            my $out = $target;
567            $out =~ s/\.\\((x64|x86)\\)?Release/\.\.\\\.\.\\\.\.\\$1bin/;
568            $out =~ s/\$\(OutDir\)/\.\.\\\.\.\\\.\.\\bin/;
569            $out =~ s/\//\\/; # convert / to \
570            $target = $out;
571        }
572        print MAKFILE "\"$target\" ";
573    }
574
575    # Append [Target_<dir>] item e.g. ../../icuxy36.dll
576    my $targetkey = "Target_" . $filename;
577    my @target = ();
578    if ( exists $template_hash{$targetkey}  ) {
579        @target = @{$template_hash{$targetkey}};
580        print "target: @target from cfg key $targetkey\n" if ($is_debug);
581    } else {
582        print "No cfg key for target $targetkey\n" if ($is_debug);
583    }
584    my $additional_target="";
585    foreach $additional_target(@target)
586    {
587        print MAKFILE $additional_target if ($additional_target ne "");
588    }
589    print MAKFILE "\n\n";
590    print MAKFILE "\"\$(OUTDIR)\" : \n";
591    print MAKFILE "\tif not exist \"\$(OUTDIR)/\$(NULL)\" mkdir \"\$(OUTDIR)\"\n\n";
592    print MAKFILE "!IF \"\$(OUTDIR)\" != \"\$(INTDIR)\"\n";
593    print MAKFILE "\"\$(INTDIR)\" : \n";
594    print MAKFILE "\tif not exist \"\$(INTDIR)/\$(NULL)\" mkdir \"\$(INTDIR)\"\n";
595    print MAKFILE "!ENDIF\n";
596    print MAKFILE "\n\n";
597}   ##print_all_target
598
599############################################################################
600sub print_simple_flag       #18.04.2008 13:39
601############################################################################
602{
603    my $simple_flag = shift;
604    my @template = @{$template_hash{$simple_flag}};
605    foreach $line(@template)
606    {
607        print MAKFILE $line;
608    }
609}   ##print_rules
610
611############################################################################
612sub print_link_template       #18.04.2008 13:39
613############################################################################
614{
615    my $dir = shift;
616    my $outfile = shift;
617    my $manifest;
618    # set resource id for manifest file
619    if ( $outfile =~ /\.exe/ ) {
620        $manifest = 1;
621    } else
622    {
623        $manifest = 2;
624    }
625    my @template = ();
626    if ($dir =~ /stubdata/ ) {
627        @template = @{$template_hash{"Special_stubdata"}};
628    } else
629    {
630        @template = @{$template_hash{"LinkTemplate"}};
631    }
632
633    print MAKFILE "\n"; # insert blank line
634    foreach $line(@template)
635    {
636        $line =~ s/<OUTFILE>/$outfile/;
637        $line =~ s/<MANIFEST>/$manifest/;
638        print MAKFILE $line;
639    }
640
641    # insert special stuff for
642    # extras/uconv/uconv.mak
643    if ( $dir =~ /uconv/ ) {
644        print_flags($dir,"","Special");
645    }
646
647    # for *.exe files an additional
648    # copy section is required to get
649    # the stuff into the per-arch bin directory
650    my %dummy = ();
651    my @mak = ();
652    my $arch = "";
653    if ( $out =~ /x64/ ) {
654    $arch = "x64\\";
655    } elsif ( $out =~ /x86/ ) {
656    $arch = "x86\\";
657    }
658    if( $manifest ==1 )
659    {
660        # source,inputpath,target,action
661        my $out = $outfile;
662        $out =~ s/\.\\((x64|x86)\\)?Release/\.\.\\\.\.\\\.\.\\$1bin/;
663        $out =~ s/\$\(OutDir\)/\.\.\\\.\.\\\.\.\\bin/;
664        $out =~ s/\//\\/;       # subst / with \
665        $outfile =~ s/\//\\/;   # subst / with \
666        createCopySection($outfile,$outfile,$out,"copy \"\$(InputPath)\" .\\..\\..\\..\\${arch}bin",\@mak,\%dummy);
667        foreach $line(@mak)
668        {
669            print MAKFILE $line;
670        }
671    }
672}   ##print_rules
673
674############################################################################
675sub print_rsc_template      #04.11.2008 14:48
676############################################################################
677 {
678    # print resource compiler setting + resource target
679    my $resourcefile = shift;
680    # skip this if no res file required
681
682    return if (!$resourcefile);
683    $resfile = $resourcefile;
684    #remove file extension (.res)
685    $resfile =~ /(.+)\\(.+)\.(.+)/;
686    $resfile = $2;
687
688    my @template = @{$template_hash{"RSC_Template"}};
689    print MAKFILE "\n"; # insert blank line
690    foreach $line(@template)
691    {
692        $line =~ s/<FILE>/$resourcefile/;
693        $line =~ s/<FILEOUT>/$resfile/;
694        $line =~ s/\/d \"NDEBUG\"/\/d \"DEBUG\"/ if ($enable_symbols ||
695                             $is_debug);
696        print MAKFILE $line;
697    }
698}   ##print_rsc_template
699
700############################################################################
701sub print_flags     #18.04.2008 14:19
702############################################################################
703{
704    # CFlags, LinkFlags
705    my $dir = shift;
706    my $extra_mak = shift; # eg. derb.mak, stringperf.mak
707    my $flag = shift;
708    my $nonpro = shift;
709    my @template = ();
710    my $switch = "";
711    $dir =~ s/\\/_/g if ($dir);            # change \ to _
712    $switch = "$flag" . "_" . "$dir" if ($dir);
713    handle_CFlags() if ($flag eq "CFlags");  # get and print Preprocessor defines
714    $switch .= "\." . $extra_mak if ( $extra_mak ne "" ) ;
715    if ( exists $template_hash{$switch} ) {
716        print "Reading switches from cfg section $switch\n" if ($is_debug);
717        @template = @{$template_hash{$switch}};
718        foreach $line(@template)
719        {
720            if ( $nonpro )
721            {
722                # if non product link against debug libraries
723                $line =~ s/-MD/-MDd/;
724                $line =~ s/-MT/-MTd/;
725            }
726            print MAKFILE $line;
727        }
728    } else {
729        print "No cfg section $switch -> no switches\n" if ($is_debug);
730    }
731}   ##print_flags
732
733############################################################################
734sub handle_CFlags       #28.01.2009 11:20
735############################################################################
736 {
737
738    my $ppdefs = $configelements{"Release"}{"PreprocessorDefinitions"};
739    my $ppinc  = $configelements{"Release"}{"AdditionalIncludeDirectories"};
740    my @template = @{$template_hash{"General_CFlags"}};
741    $ppdefs =~ s/;/ -D/g; # subst ; with -D switch
742    $ppdefs = "-D" . $ppdefs;
743    $ppinc =~ s/(;|,)/ -I/g; # subst ; with -I switch
744    $ppinc = "-I" . $ppinc;
745    print "ppdefs=$ppdefs\n" if ($is_debug);
746    print "ppinc =$ppinc\n" if ($is_debug);
747    foreach $line(@template)
748    {
749        $line =~ s/<AddIncDirs>/$ppinc/;
750        $line =~ s/<PreProcDefs>/$ppdefs/;
751        $line =~ s/-DNDEBUG/\-Zi/ if ($enable_symbols || $is_debug);
752        print MAKFILE $line;
753    }
754}   ##handle_CFlags
755
756############################################################################
757sub print_common_linkflags      #21.11.2008 11:47
758############################################################################
759 {
760    my @template = @{$template_hash{"CommonLinkFlags"}};
761    my $outfile = $configelements{"Release"}{"OutputFile"};
762    my $pdbfile = $configelements{"Release"}{"ProgramDatabaseFile"};
763    $pdbfile =~ s/\//\\/;   # subst / with \
764    $outfile =~ s/\//\\/;   # subst / with \
765    print "PATH=$path OUTFILE=$outfile\n" if ($is_debug);
766    foreach $line(@template)
767    {
768        $line =~ s/<OUTFILE>/$outfile/;
769        $line =~ s/<PDBFILE>/$pdbfile/;
770        print MAKFILE $line;
771    }
772}   ##print_common_linkflags
773
774############################################################################
775sub handle_extra_mak_files      #25.08.2008 14:32
776############################################################################
777{
778    # extract extra filename for *.mak file
779    # e.g input: tools\genrb.derb
780    #    output: derb
781    my $direntry = shift;
782    my $out = "";
783    my $dir = "";
784    if ( $direntry =~ /(.+)\.(.+)$/ ) {
785        $dir = $1;
786        $out = $2;
787    } else
788    {
789        $dir = $direntry;
790    }
791    return ($dir,$out);
792}   ##handle_extra_mak_files
793
794############################################################################
795sub prepare_allinone_all_mak
796############################################################################
797{
798    # Read in allinone.sln
799    # Fills hashes and returns an array with build order
800    # uses topographical sorting
801
802    my $href_project_by_id = shift;
803    my $href_project_by_name = shift;
804    my $href_project_dependencies = shift;
805    my $sourcePath = shift;
806
807    my $allslnfile = $sourcePath . "\\allinone\\allinone.sln";
808    my @projectdeps;
809    my $projectname;
810    my $projectpath;
811    my $projectid;
812
813    # fill hash tables
814    open (SLN, "< $allslnfile") || die "Can't open $allslnfile\n";
815    while ($line = <SLN>)
816    {
817        my @project = ();
818        if ( $line =~ /^Project\(/ ) {
819            @project = split( /,/, $line);
820            if ( $#project ) {
821                $projectname = "";
822                $projectpath = "";
823                $projectid = "";
824                @projectdeps = ();
825                my @subarray = ();
826                @subarray = split( /=/, $project[0]);
827                $projectname = $subarray[1];
828                $projectname =~ s/\"//g;      # remove "
829                $projectpath = $project[1];
830                $projectid = $project[2];
831                $projectid =~ s/\"//g;        # remove "
832                $projectid =~ s/.+\{//g;      # remove til {
833                $projectid =~ s/\}\n//g;      # remove }<CR>
834                my @pnp = ($projectname,$projectpath);
835                my @pip = ($projectid,$projectpath);
836                $$href_project_by_id{$projectid}=[@pnp];
837                $$href_project_by_name{$projectname} =[@pip];
838            }
839        } # $line =~ /^Project\(/
840        if ( $line =~ /ProjectSection\(/ ) {
841            $psect = 1;
842            next;
843        }
844        if ( $line =~ /EndProjectSection/ ) {
845            $psect = 0;
846            $$href_project_dependencies{$projectid}=[@projectdeps];
847            next;
848        }
849        if ( $psect ) {
850            my @tarray = split(/=/, $line);
851            $depends_on_id = $tarray[0];
852            $depends_on_id =~ s/.+\{//g;
853            $depends_on_id =~ s/\}.+//g;
854             print "+$depends_on_id-\n" if ($is_debug);
855
856            push @projectdeps, $depends_on_id;
857        }
858    }
859    ########################################
860    # sort here and generate build order
861    ########################################
862    $objektzahl=0;
863    %hashindex=();
864
865    foreach $projectid(keys %{$href_project_by_id})
866    {
867        if ( $$href_project_dependencies{$projectid} )
868        {
869            @deps = @{$$href_project_dependencies{$projectid}};
870        } else
871        {
872            @deps = ();
873        }
874        for  $counter(0..$#deps)
875        {
876            $v = find_or_create_element($deps[$counter]);
877            $n = find_or_create_element($projectid);
878            push @{$nachfolgerliste[$v]},$n;
879        }
880    }
881
882    for $n (0..$objektzahl-1)
883    {
884            $vorgaengerzahl[$n]=0;
885    }
886    for $v (0..$objektzahl-1)
887    {
888            for $n (@{$nachfolgerliste[$v]})
889            {
890                    ++$vorgaengerzahl[$n];
891            }
892    }
893
894    @hilfsliste=();
895    for $n (0..$objektzahl-1)
896    {
897        push(@hilfsliste,$n) if ($vorgaengerzahl[$n]==0)
898    }
899
900    $ausgabe=0;
901    @builddep =();
902    while (defined($v=pop(@hilfsliste)))
903    {
904        push @builddep, $name[$v];                           # save build order by project_id;
905        ++$ausgabe;
906        for $n (@{$nachfolgerliste[$v]})
907        {
908                --$vorgaengerzahl[$n];
909                push(@hilfsliste,$n) if ($vorgaengerzahl[$n]==0);
910        }
911    } # while
912    die "Cyclic dependencies found! Stopping now.\n" if $ausgabe<$objektzahl;
913    ##############################################################
914    # End of sorting stuff
915    ##############################################################
916
917    return @builddep;
918    ###############################################################
919    ###########################
920    # sub for sorting only
921    ###########################
922    sub find_or_create_element
923    {
924        my ($str)=@_;
925        my ($idx)=$hashindex{$str};
926        if (!defined($idx)) {               # new element ...
927                $idx=$objektzahl++;
928                $hashindex{$str}=$idx;
929                $name[$idx]=$str;
930            @{$nachfolgerliste[$idx]}=();
931        }
932        return $idx;
933    } # find_or_create_element
934}  # prepare_allinone_all_mak
935
936############################################################################
937sub create_allinone_all_mak     #09.02.2009 09:22
938############################################################################
939{
940    my $ref_buildorder = shift;
941    my $href_project_by_id = shift;
942    my $sourcePath = shift;
943    my $allmakfile = $sourcePath . "\\allinone\\all.mak";
944    open (ALLMAK, ">$allmakfile") || die "Can't write to $allmakfile \n";
945    print ALLMAK "ALL: ";
946    foreach $proj(@{$ref_buildorder})
947    {
948        print ALLMAK $$href_project_by_id{$proj}[0];
949    }
950    print ALLMAK "\n\n";
951
952    foreach $proj( @{$ref_buildorder} )
953    {
954        print "$proj $$href_project_by_id{$proj}[0] $$href_project_by_id{$proj}[1]\n";
955        my $prjdir = $$href_project_by_id{$proj}[1];
956        $prjdir =~ /(.+)\\(.+)$/;
957        $prjdir = $1;
958        $prjname = $2;
959        $prjdir =~ s/^.+\"//;
960        $prjname =~ s/\"$//;
961        $prjname =~ s/vcproj/mak/;
962        $allinonehelpstring = $prjdir;
963        $allinonehelpstring =~ s/^\.+\\//; # remove ..\
964        my $backcount = "";
965        while ($allinonehelpstring=~ /.+\\/g) # counts the occurring \
966        {
967            $backcount .= "..\\";
968        }
969        $allinonedir = $backcount . "..\\allinone";
970
971        # write all.mak
972        $$href_project_by_id{$proj}[0] =~ s/^\s+//;
973        if ( $$href_project_by_id{$proj}[0] ne "makedata" )
974        {
975            my @template = @{$template_hash{"AllInOnePrj"}};
976            foreach $line(@template)
977            {
978                $line =~ s/<PRJ>/$$href_project_by_id{$proj}[0]/;
979                $line =~ s/<PRJDIR>/$prjdir/;
980                $line =~ s/<PRJMAK>/$prjname/;
981                $line =~ s/<ALLINONEDIR>/$allinonedir/;
982                print ALLMAK $line;
983            }
984        } else
985        {
986            #special code snippet
987            print ALLMAK "makedata : \n";
988            print ALLMAK "     cd \"..\\data\"\n";
989            print ALLMAK "     nmake /f makedata.mak icumake=\$(MAKEDIR)\\..\\data cfg=$architecture/Release\n";
990            print ALLMAK "     cd \"..\\allinone\"\n\n";
991        }
992    }
993    close ALLMAK;
994}   ##create_allinone_all_mak
995
996############################################################################
997
998# ------------------------------------------------------------------------
999# XML parser handling
1000# ------------------------------------------------------------------------
1001
1002############################################################################
1003sub start_handler
1004############################################################################
1005{
1006    my $p = shift;           # pointer to parser
1007    my $el = shift;          # element
1008
1009    # Deal with attributes
1010
1011    my $CompilerSection = 0;
1012    my $LinkerSection = 0;
1013    my $ConfigSection = ($el eq "Configuration");
1014
1015    while (@_)
1016    {
1017 #       shift if ( $el eq "FileConfiguration" );
1018        my $att = shift;
1019        my $val = shift;
1020        $CustomSection = 0;
1021        if ($special_file && defined $att & $att ne "Name")
1022        {
1023            print "$special_file - $att - $val\n";
1024            my @param = ($att,$val);
1025            $files_special{ $special_file } = [@param]; # files with special compiler switch
1026            @test = @{$files_special{ $special_file }};
1027            print "test=@test\n";
1028            $special_file="";
1029        }
1030        if ( $ConfigSection && $att eq "Name" && $val eq "Release|Win32" ) {
1031        if ( $architecture eq "x86" ) {
1032        $Release = 1;
1033        $config = "Release";                                                             # Release
1034        } else {
1035        print "Ignoring Configuration $val\n" if ($is_debug);
1036        $Release = 2;
1037        $config = "Ignored";
1038        }
1039        }
1040        if ( $ConfigSection && $att eq "Name" && $val eq "Debug|Win32" ) {
1041        if ( $architecture eq "x86" ) {
1042        $Release = 0;                                                                    # Debug
1043        $config = "Debug";
1044        } else {
1045                print "Ignoring Configuration $val\n" if ($is_debug);
1046        $Release = 2;
1047        $config = "Ignored";
1048        }
1049        }
1050        if ( $ConfigSection && $att eq "Name" && $val eq "Release|x64" ) {
1051        if ( $architecture eq "x64" ) {
1052        $Release = 1;
1053        $config = "Release";                                                             # Release
1054        } else {
1055                print "Ignoring Configuration $val\n" if ($is_debug);
1056        $Release = 2;
1057        $config = "Ignored";
1058        }
1059        }
1060        if ( $ConfigSection && $att eq "Name" && $val eq "Debug|x64" ) {
1061        if ( $architecture eq "x64" ) {
1062        $Release = 0;                                                             # Debug
1063        $config = "Debug";
1064        } else {
1065                print "Ignoring Configuration $val\n" if ($is_debug);
1066        $Release = 2;
1067        $config = "Ignored";
1068        }
1069        }
1070        if ( $att eq "Name" && $val eq "VCCLCompilerTool" ) {
1071            $CompilerSection = 1;
1072        }
1073        if ( $att eq "Name" && $val eq "VCLinkerTool" ) {
1074            $LinkerSection = 1;
1075        }
1076        if ( $att eq "Name" && $val eq "VCCustomBuildTool" ) {
1077            $CustomSection = 1;
1078        }
1079
1080        # For Configuration Infos like compiler defines etc.
1081        if ( $att eq "PreprocessorDefinitions" && $CompilerSection ) {
1082           $configelements{$config}{$att} = $val;
1083        }
1084        if ( $att eq "AdditionalIncludeDirectories" && $CompilerSection ) {
1085           #$configelements{$config}{$att} = $val;
1086            if ( ($file_tmp ne "") && ($val ne "") ) {
1087                $files{ $file_tmp } = 1;        # save it now
1088                $file_tmp =~ s/^\.\\//;         # remove leading .\
1089                $files_special{"AdditionalIncludeDirectories"}{$file_tmp} = $val;
1090                print "Include $val: $file_tmp\n" if ($is_debug);
1091                $file_tmp = "";                 # has been saved now reset it
1092            } else
1093            {
1094               $configelements{$config}{$att} = $val;
1095            }
1096        }
1097        if ( ($att eq "DisableLanguageExtensions") && $CompilerSection ) {
1098           #$configelements{$config}{$att} = $val;
1099            if ( ($file_tmp ne "") && ($val ne "")) {
1100                $files{ $file_tmp } = 1;        # save it now
1101                $file_tmp =~ s/^\.\\//;         # remove leading .\
1102                $files_special{"DisableLanguageExtensions"}{$file_tmp} = $val;
1103                print "-Ze: $file_tmp\n" if ($is_debug);
1104                $file_tmp = "";                 # has been saved now reset it
1105            }
1106        }
1107        if ( $att eq "OutputDirectory" ) {
1108           $configelements{$config}{$att} = $val;
1109        }
1110        if ( $att eq "OutputFile" && $LinkerSection ) {
1111           if ($architecture eq "x64") {
1112              # We want the /bin/ subdirectory on all architectures
1113              $val =~ s/\\bin64\\/\\bin\\/;
1114           }
1115           $configelements{$config}{$att} = $val;
1116        }
1117        if ( $att eq "ProgramDatabaseFile" ) {
1118           $configelements{$config}{$att} = $val;
1119        }
1120        if ( $att eq "ImportLibrary" && $LinkerSection ) {
1121           $configelements{$config}{$att} = $val;
1122        }
1123        if ($att eq "CommandLine") {
1124           $configelements{$config}{$att} = $val;
1125        }
1126        if (($att eq "PreprocessorDefinitions") && $ConfigSection) {
1127           $configelements{$config}{$att} = $val;
1128        }
1129
1130        # Is the file in the step before a header
1131        # which has to be copied into the global
1132        # include path?
1133        if ( $file_tmp ne "" )
1134        {
1135            $config = "Release";
1136            if ( ($att eq "CommandLine") && ($el eq "Tool") )
1137            {
1138                if ( $file_tmp =~ /.+\.h$/ ) {
1139                    $files2copy{ $file_tmp } = $val; # unicode + layout header to copy
1140                    $file_tmp = "";                 # has been saved now reset it
1141                }
1142            }
1143        } # if $file_tmp
1144
1145        # For files
1146        if ( $att eq "RelativePath" ) {
1147            if ( $file_tmp ) {
1148                # no special file (include dir / compiler switch)
1149                $files{ $file_tmp } = 1;        # save it now
1150                $file_tmp = "";                 # has been saved now reset it
1151            }
1152            # store temporary the file name
1153            $file_tmp = $val if ($val !~ /\.mk$/);  # no *.mk files
1154        }
1155    } # while @_
1156}  # End start_handler
1157
1158############################################################################
1159sub char_handler
1160############################################################################
1161{
1162}  # End char_handler
1163