- Better .dsp file generation for .exe outputs
[wine] / tools / winapi / msvcmaker
1 #! /usr/bin/perl -w
2
3 # Copyright 2002 Patrik Stridvall
4
5 use strict;
6
7 BEGIN {
8     $0 =~ m%^(.*?/?tools)/winapi/msvcmaker$%;
9     require "$1/winapi/setup.pm";
10 }
11
12 use config qw(&file_directory &get_spec_files &get_makefile_in_files $current_dir $wine_dir);
13 use output qw($output);
14
15 ########################################################################
16 # _compare_files
17
18 sub _compare_files {
19     my $file1 = shift;
20     my $file2 = shift;
21
22     local $/ = undef;
23
24     return -1 if !open(IN, "< $file1");
25     my $s1 = <IN>;
26     close(IN);
27
28     return 1 if !open(IN, "< $file2");
29     my $s2 = <IN>;
30     close(IN);
31
32     return $s1 cmp $s2;
33 }
34
35 ########################################################################
36 # replace_file
37
38 sub replace_file {
39     my $filename = shift;
40     my $function = shift;
41
42     open(OUT, "> $filename.tmp") || die "Can't open file '$filename.tmp'";
43
44     my $result = &$function(\*OUT, @_);
45
46     close(OUT);
47
48     if($result && _compare_files($filename, "$filename.tmp")) {
49         unlink("$filename");
50         rename("$filename.tmp", $filename);
51     } else {
52         unlink("$filename.tmp");
53     }
54
55     return $result;
56 }
57
58 ########################################################################
59 # main
60
61 my @spec_files = get_spec_files("winelib");
62 my @makefile_in_files = get_makefile_in_files("winelib");
63
64 my $wine = 1;
65
66 my $output_prefix_dir = "Output";
67 my $no_release = 1;
68 my $no_msvc_headers = 1;
69
70 my %modules;
71
72 foreach my $spec_file (@spec_files) {
73     my $module = $spec_file;
74     $module =~ s%^.*?([^/]+)\.spec$%$1%;
75     $module .= ".dll" if $module !~ /\./;
76
77     my $type = "win32";
78
79     open(IN, "< $wine_dir/$spec_file");
80
81     my $header = 1;
82     my $lookahead = 0;
83     while($lookahead || defined($_ = <IN>)) {
84         $lookahead = 0;
85
86         s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begining and end of line
87         s/^(.*?)\s*#.*$/$1/;  # remove comments
88         /^$/ && next;         # skip empty lines
89
90         if($header)  {
91             if(/^\d+|@/) {
92                 $header = 0;
93                 $lookahead = 1;
94             }
95             next;
96         }
97
98         if(/^(\d+|@)\s+pascal(?:16)?/) {
99             $type = "win16";
100             last;
101         }
102     }
103     close(IN);
104
105     # FIXME: Kludge
106     if($module =~ /^(?:comm|imm|ole2conv|ole2prox|ole2thk|rasapi16|windebug)\.dll$/) {
107         $type = "win16";
108     }
109
110     if($type eq "win32") {
111         $modules{$module}{module} = $module;
112         $modules{$module}{type} = $type;
113         $modules{$module}{spec_file} = $spec_file;
114     }
115 }
116
117 my @gdi32_dirs = qw(dlls/gdi/enhmfdrv dlls/gdi/mfdrv dlls/gdi/win16drv graphics objects);
118 my @ntdll_dirs = qw(files if1632 loader/ne loader memory misc msdos ole relay32 scheduler win32);
119 my @user32_dirs = qw(controls dlls/user/dde windows);
120
121 push @makefile_in_files, "library/Makefile.in";
122 push @makefile_in_files, "unicode/Makefile.in";
123 push @makefile_in_files, "tools/winebuild/Makefile.in";
124
125 sub filter_files {
126     my $files = shift;
127     my $filter = shift;
128
129     my $filtered_files = [];
130     my $rest_of_files = [];
131     foreach my $file (@$files) {
132         if($file =~ /$filter/) {
133             $file =~ s%.*?([^/]+)$%./$1%; # FIXME: Kludge
134             push @$filtered_files, $file;
135         } else {
136             push @$rest_of_files, $file;
137         }
138     }
139     return ($rest_of_files, $filtered_files);
140 }
141
142 MAKEFILE_IN: foreach my $makefile_in_file (@makefile_in_files) {
143     open(IN, "< $wine_dir/$makefile_in_file");
144
145     my $topobjdir;
146     my $module;
147
148     my %vars;
149
150     my $again = 0;
151     my $lookahead = 0;
152     while($again || defined(my $line = <IN>)) {
153         if(!$again) {
154             chomp $line;
155             if($lookahead) {
156                 $lookahead = 0;
157                 $_ .= "\n" . $line;
158             } else {
159                 $_ = $line;
160             }
161         } else {
162             $again = 0;
163         }
164
165         s/^\s*?(.*?)\s*$/$1/; # remove whitespace at begining and end of line
166         s/^(.*?)\s*#.*$/$1/;  # remove comments
167         /^$/ && next;         # skip empty lines
168
169         if(s/\\$/ /s) {
170             $lookahead = 1;
171             next;
172         }
173
174         if(/^MODULE\s*=\s*([\w\.]+)$/) {
175             $module = $1;
176
177             if($module eq "none") {
178                 if($makefile_in_file eq "library/Makefile.in") {
179                     $module = "wine.dll";
180                 } elsif($makefile_in_file eq "unicode/Makefile.in") {
181                     $module = "wine_unicode.dll";
182                 } elsif($makefile_in_file eq "tools/winebuild/Makefile.in") {
183                     $module = "winebuild.exe";
184                 } else {
185                     next MAKEFILE_IN;
186                 }
187             }
188         } elsif(/^TOPOBJDIR\s*=\s*(\S+)\s*$/) {
189             $topobjdir = $1;
190         } elsif(/^(\w+)\s*=\s*/) {
191             my $var = $1;
192             my @files = split /\s+/s, $';
193
194             # @files = ();
195
196             @files = map {
197                 if(/^\$\((\w+):\%=(.*?)\%(.*?)\)$/) {
198                     my @list = @{$vars{$1}};
199                     my $prefix = $2;
200                     my $suffix = $3;
201                     foreach my $item (@list) {
202                         $item = "$prefix$item$suffix";
203                     }
204                     @list;
205                 } elsif(/^\$\(TOPOBJDIR\)(.*?)$/) {
206                     "$topobjdir$1";
207                 } elsif(/^\$/) {
208                     print STDERR "unknown variable '$_'\n" if 0;
209                     ();
210                 } else {
211                     $_;
212                 }
213             } @files;
214
215             $vars{$var} = \@files;
216         }
217     }
218
219     close(IN);
220
221     next if !$module;
222
223     my $c_srcs = [];
224     my $source_files = [];
225     if(exists($vars{C_SRCS})) {
226         $c_srcs = [sort(@{$vars{C_SRCS}})];
227         $source_files = [sort(@{$vars{C_SRCS}})];
228     }
229
230     my $header_files = [];
231     if(exists($vars{H_SRCS})) {
232         $header_files = [sort(@{$vars{H_SRCS}})];
233     }
234
235     my $resource_files = [];
236     if(exists($vars{RC_SRCS})) {
237         $resource_files = [sort(@{$vars{RC_SRCS}})];
238     }
239
240     my $project = $module;
241     $project =~ s/\.(?:dll|exe|lib)$//;
242     $project =~ y/./_/;
243
244     my $type;
245     if($module =~ /\.exe$/) {
246         $type = "exe";
247     } elsif($module =~ /\.lib$/) {
248         $type = "lib";
249     } else {
250         $type = "dll";
251     }
252
253     my $dsp_file = $makefile_in_file;
254     $dsp_file =~ s/Makefile.in$/$project.dsp/;
255
256     if($module eq "gdi32.dll") {
257         foreach my $dir (@gdi32_dirs) {
258             my $dir2 = $dir;
259             $dir2 =~ s%^.*?/([^/]+)$%$1%;
260
261             my $module = "gdi32_$dir2.lib";
262             $module =~ s%/%_%g;
263
264             my $project = "gdi32_$dir2";
265             $project =~ s%/%_%g;
266
267             my $type = "lib";
268             my $dsp_file = "$dir/$project.dsp";
269
270             ($source_files, my $local_source_files) = filter_files($source_files, "$dir2/");
271             ($header_files, my $local_header_files) = filter_files($header_files, "$dir2/");
272             ($resource_files, my $local_resource_files) = filter_files($resource_files, "$dir2/");
273
274             $modules{$module}{project} = $project;
275             $modules{$module}{type} = $type;
276             $modules{$module}{dsp_file} = $dsp_file;
277             $modules{$module}{c_srcs} = $c_srcs;
278             $modules{$module}{source_files} = $local_source_files;
279             $modules{$module}{header_files} = $local_header_files;
280             $modules{$module}{resource_files} = $local_resource_files;
281         }
282     } elsif($module eq "ntdll.dll") {
283         foreach my $dir (@ntdll_dirs) {
284             my $module = "ntdll_$dir.lib";
285             $module =~ s%/%_%g;
286
287             my $project = "ntdll_$dir";
288             $project =~ s%/%_%g;
289
290             my $type = "lib";
291             my $dsp_file = "$dir/$project.dsp";
292
293             ($source_files, my $local_source_files) = filter_files($source_files, "/$dir/");
294             ($header_files, my $local_header_files) = filter_files($header_files, "/$dir/");
295             ($resource_files, my $local_resource_files) = filter_files($resource_files, "/$dir/");
296
297             $modules{$module}{project} = $project;
298             $modules{$module}{type} = $type;
299             $modules{$module}{dsp_file} = $dsp_file;
300             $modules{$module}{c_srcs} = $c_srcs;
301             $modules{$module}{source_files} = $local_source_files;
302             $modules{$module}{header_files} = $local_header_files;
303             $modules{$module}{resource_files} = $local_resource_files;
304         }
305     } elsif($module eq "user32.dll") {
306         foreach my $dir (@user32_dirs) {
307             my $dir2 = $dir;
308             $dir2 =~ s%^.*?/([^/]+)$%$1%;
309
310             my $module = "user32_$dir2.lib";
311             $module =~ s%/%_%g;
312
313             my $project = "user32_$dir2";
314             $project =~ s%/%_%g;
315
316             my $type = "lib";
317             my $dsp_file = "$dir/$project.dsp";
318
319             ($source_files, my $local_source_files) = filter_files($source_files, "$dir2/");
320             ($header_files, my $local_header_files) = filter_files($header_files, "$dir2/");
321             ($resource_files, my $local_resource_files) = filter_files($resource_files, "$dir2/");
322
323             $modules{$module}{project} = $project;
324             $modules{$module}{type} = $type;
325             $modules{$module}{dsp_file} = $dsp_file;
326             $modules{$module}{c_srcs} = $c_srcs;
327             $modules{$module}{source_files} = $local_source_files;
328             $modules{$module}{header_files} = $local_header_files;
329             $modules{$module}{resource_files} = $local_resource_files;
330         }
331     }
332
333     $modules{$module}{project} = $project;
334     $modules{$module}{type} = $type;
335     $modules{$module}{dsp_file} = $dsp_file;
336     $modules{$module}{c_srcs} = $c_srcs;
337     $modules{$module}{source_files} = $source_files;
338     $modules{$module}{header_files} = $header_files;
339     $modules{$module}{resource_files} = $resource_files;
340 }
341
342 # FIMXE: Parse the Makefile.in's instead.
343
344 my @wine_test_dsp_files = (
345     "dlls/gdi/tests/gdi32_test.dsp",
346     "dlls/kernel/tests/kernel32_test.dsp",
347     "dlls/ntdll/tests/ntdll_test.dsp",
348     "dlls/user/tests/user32_test.dsp",
349     "programs/winetest/winetest.dsp",
350 );
351
352 foreach my $dsp_file (@wine_test_dsp_files) {
353     my $project = $dsp_file;
354     $project =~ s%^.*?/([^/]+)\.dsp$%$1%;
355
356     my $type;
357     my $c_srcs = [];
358     my $source_files = [];
359     my $header_files = [];
360     my $resource_files = [];
361
362     if ($project eq "winetest") {
363         $type = "lib";
364         $c_srcs = ["wtmain.c"];
365         $source_files = ["wtmain.c"];
366         $header_files = [];
367         $resource_files = [];
368     } else {
369         $type = "exe";
370         $c_srcs = ["generated.c", "testlist.c"];
371         $source_files = ["generated.c", "testlist.c"];
372         $header_files = [];
373         $resource_files = [];
374     }
375     my $module = "$project.$type";
376
377     $modules{$module}{project} = $project;
378     $modules{$module}{type} = $type;
379     $modules{$module}{dsp_file} = $dsp_file;
380     $modules{$module}{c_srcs} = $c_srcs;
381     $modules{$module}{source_files} = $source_files;
382     $modules{$module}{header_files} = $header_files;
383     $modules{$module}{resource_files} = $resource_files;
384 }
385
386 foreach my $module (sort(keys(%modules))) {
387     if($module =~ /^(?:ttydrv.dll|x11drv.dll)$/) {
388         delete $modules{$module};
389     }
390 }
391
392 my $progress_output;
393 my $progress_current = 0;
394 my $progress_max = scalar(keys(%modules));
395
396 foreach my $module (sort(keys(%modules))) {
397     my $dsp_file = $modules{$module}{dsp_file};
398
399     replace_file("$wine_dir/$dsp_file", \&_generate_dsp, $module);
400 }
401
402 sub _generate_dsp {
403     local *OUT = shift;
404
405     my $module = shift;
406
407     my $dsp_file = $modules{$module}{dsp_file};
408     my $project = $modules{$module}{project};
409
410     my $lib = ($modules{$module}{type} eq "lib");
411     my $dll = ($modules{$module}{type} eq "dll");
412     my $exe = ($modules{$module}{type} eq "exe");
413
414     my $console = $exe; # FIXME: Not always correct
415
416     my $wine_include_dir = do {
417         my @parts = split(m%/%, $dsp_file);
418         if($#parts == 1) {
419             "..\\include";
420         } elsif($#parts == 2) {
421             "..\\..\\include";
422         } else {
423             "..\\..\\..\\include";
424         }
425     };
426
427     $progress_current++;
428     $output->progress("$dsp_file (file $progress_current of $progress_max)");
429
430     my @c_srcs = @{$modules{$module}{c_srcs}};
431     my @source_files = @{$modules{$module}{source_files}};
432     my @header_files = @{$modules{$module}{header_files}};
433     my @resource_files = @{$modules{$module}{resource_files}};
434
435     if ($project !~ /^(?:wine(?:_unicode)?|wine(?:build|test))$/ &&
436         $project !~ /^(?:gdi32|ntdll|user32)_.+?$/ &&
437         $project !~ /_test$/)
438     {
439         push @source_files, "$project.spec";
440         # push @source_files, "$project.spec.c";
441         @source_files = sort(@source_files);
442     }
443
444     my @cfgs;
445     if($no_release && $no_msvc_headers) {
446         push @cfgs, "$project - Win32";
447     } elsif($no_release && !$no_msvc_headers) {
448         push @cfgs, "$project - Win32 MS Headers";
449         push @cfgs, "$project - Win32 Wine Headers";
450     } elsif(!$no_release && $no_msvc_headers) {
451         push @cfgs, "$project - Win32 Release";
452         push @cfgs, "$project - Win32 Debug";
453     } else {
454         push @cfgs, "$project - Win32 Release MS Headers";
455         push @cfgs, "$project - Win32 Debug MS Headers";
456         push @cfgs, "$project - Win32 Release Wine Headers";
457         push @cfgs, "$project - Win32 Debug Wine Headers";
458     }
459     my $default_cfg = $cfgs[$#cfgs];
460
461     my $msvc_include = "d:\\program files\\microsoft visual studio\\vc98\\include";
462
463     print OUT "# Microsoft Developer Studio Project File - Name=\"$project\" - Package Owner=<4>\r\n";
464     print OUT "# Microsoft Developer Studio Generated Build File, Format Version 6.00\r\n";
465     print OUT "# ** DO NOT EDIT **\r\n";
466     print OUT "\r\n";
467
468     if ($lib) {
469         print OUT "# TARGTYPE \"Win32 (x86) Static Library\" 0x0104\r\n";
470     } elsif ($dll) {
471         print OUT "# TARGTYPE \"Win32 (x86) Dynamic-Link Library\" 0x0102\r\n";
472     } else {
473         print OUT "# TARGTYPE \"Win32 (x86) Console Application\" 0x0103\r\n";
474     }
475     print OUT "\r\n";
476
477     print OUT "CFG=$default_cfg\r\n";
478     print OUT "!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r\n";
479     print OUT "!MESSAGE use the Export Makefile command and run\r\n";
480     print OUT "!MESSAGE \r\n";
481     print OUT "!MESSAGE NMAKE /f \"$project.mak\".\r\n";
482     print OUT "!MESSAGE \r\n";
483     print OUT "!MESSAGE You can specify a configuration when running NMAKE\r\n";
484     print OUT "!MESSAGE by defining the macro CFG on the command line. For example:\r\n";
485     print OUT "!MESSAGE \r\n";
486     print OUT "!MESSAGE NMAKE /f \"$project.mak\" CFG=\"$default_cfg\"\r\n";
487     print OUT "!MESSAGE \r\n";
488     print OUT "!MESSAGE Possible choices for configuration are:\r\n";
489     print OUT "!MESSAGE \r\n";
490     foreach my $cfg (@cfgs) {
491         if ($lib) {
492             print OUT "!MESSAGE \"$cfg\" (based on \"Win32 (x86) Static Library\")\r\n";
493         } elsif ($dll) {
494             print OUT "!MESSAGE \"$cfg\" (based on \"Win32 (x86) Dynamic-Link Library\")\r\n";
495         } else {
496             print OUT "!MESSAGE \"$cfg\" (based on \"Win32 (x86) Console Application\")\r\n";
497         }
498     }
499     print OUT "!MESSAGE \r\n";
500     print OUT "\r\n";
501
502     print OUT "# Begin Project\r\n";
503     print OUT "# PROP AllowPerConfigDependencies 0\r\n";
504     print OUT "# PROP Scc_ProjName \"\"\r\n";
505     print OUT "# PROP Scc_LocalPath \"\"\r\n";
506     print OUT "CPP=cl.exe\r\n";
507     print OUT "MTL=midl.exe\r\n" if !$lib && !$exe;
508     print OUT "RSC=rc.exe\r\n";
509
510     my $n = 0;
511
512     my $output_dir;
513     foreach my $cfg (@cfgs) {
514         if($#cfgs == 0) {
515             # Nothing
516         } elsif($n == 0) {
517             print OUT "!IF  \"\$(CFG)\" == \"$cfg\"\r\n";
518             print OUT "\r\n";
519         } else {
520             print OUT "\r\n";
521             print OUT "!ELSEIF  \"\$(CFG)\" == \"$cfg\"\r\n";
522             print OUT "\r\n";
523         }
524
525         my $debug = ($cfg !~ /Release/);
526         my $msvc_headers = ($cfg =~ /MS Headers/);
527
528         print OUT "# PROP BASE Use_MFC 0\r\n";
529
530         if($debug) {
531             print OUT "# PROP BASE Use_Debug_Libraries 1\r\n";
532         } else {
533             print OUT "# PROP BASE Use_Debug_Libraries 0\r\n";
534         }
535
536         $output_dir = $cfg;
537         $output_dir =~ s/^$project -//;
538         $output_dir =~ s/ //g;
539         if($output_prefix_dir) {
540             $output_dir = "$output_prefix_dir\\$output_dir";
541         }
542
543         print OUT "# PROP BASE Output_Dir \"$output_dir\"\r\n";
544         print OUT "# PROP BASE Intermediate_Dir \"$output_dir\"\r\n";
545
546         print OUT "# PROP BASE Target_Dir \"\"\r\n";
547
548         print OUT "# PROP Use_MFC 0\r\n";
549         if($debug) {
550             print OUT "# PROP Use_Debug_Libraries 1\r\n";
551         } else {
552             print OUT "# PROP Use_Debug_Libraries 0\r\n";
553         }
554         print OUT "# PROP Output_Dir \"$output_dir\"\r\n";
555         print OUT "# PROP Intermediate_Dir \"$output_dir\"\r\n";
556
557         print OUT "# PROP Ignore_Export_Lib 0\r\n" if $dll;
558         print OUT "# PROP Target_Dir \"\"\r\n";
559
560         my @defines;
561         if($debug) {
562             if($lib || $exe) {
563                 print OUT "# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od";
564                 @defines = (qw(WIN32 _DEBUG _MBCS _LIB));
565             } else {
566                 print OUT "# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od";
567                 @defines = (qw(WIN32 _DEBUG _WINDOWS _MBCS _USRDLL), ("\U${project}\E_EXPORTS"));
568             }
569         } else {
570             if($lib || $exe) {
571                 print OUT "# ADD BASE CPP /nologo /W3 /GX /O2";
572                 @defines = (qw(WIN32 NDEBUG _MBCS _LIB));
573             } else {
574                 print OUT "# ADD BASE CPP /nologo /MT /W3 /GX /O2";
575                 @defines = (qw(WIN32 NDEBUG _WINDOWS _MBCS _USRDLL), ("\U${project}\E_EXPORTS"));
576             }
577         }
578
579         foreach my $define (@defines) {
580             print OUT " /D \"$define\"";
581         }
582         print OUT " /YX" if $lib || $exe;
583         print OUT " /FD";
584         print OUT " /GZ" if $debug;
585         print OUT " " if $debug && ($lib || $exe);
586         print OUT " /c";
587         print OUT "\r\n";
588
589         my @defines2;
590         if($debug) {
591             if($lib) {
592                 print OUT "# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od";
593                 @defines2 = qw(WIN32 _DEBUG _WINDOWS _MBCS _LIB);
594             } else {
595                 print OUT "# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od";
596                 @defines2 = qw(_DEBUG WIN32 _WINDOWS _MBCS _USRDLL);
597             }
598         } else {
599             if($lib) {
600                 print OUT "# ADD CPP /nologo /MT /W3 /GX /O2";
601                 @defines2 = qw(WIN32 NDEBUG _WINDOWS _MBCS _LIB);
602             } else {
603                 print OUT "# ADD CPP /nologo /MT /W3 /GX /O2";
604                 @defines2 = qw(NDEBUG WIN32 _WINDOWS _MBCS _USRDLL);
605             }
606         }
607
608         my @includes = ();
609         if($wine) {
610             push @defines2, "_\U${project}\E_";
611             push @defines2, "__WINE__" if $module !~ /^winebuild\.exe$/;
612             push @defines2, qw(__i386__ _X86_);
613
614             if($msvc_headers) {
615                 push @includes, $msvc_include;
616             }
617
618             if($project =~ /^gdi32_(?:enhmfdrv|mfdrv|win16drv)$/) {
619                 push @includes, "..";
620             }
621
622             if($project =~ /^user32_(?:controls|windows)$/) {
623                 push @includes, "..\\dlls\\user";
624             }
625
626             if($project =~ /^user32_dde$/) {
627                 push @includes, "..";
628             }
629
630             push @includes, $wine_include_dir;
631         }
632
633         if($wine) {
634             print OUT " /X" if $msvc_headers;
635
636             foreach my $include (@includes) {
637                 print OUT " /I \"$include\"";
638             }
639         }
640
641         foreach my $define (@defines2) {
642             print OUT " /D \"$define\"";
643         }
644         print OUT " /D inline=__inline" if $wine;
645         print OUT " /D \"__STDC__\"" if 0 && $wine;
646
647         print OUT " /YX" if $lib;
648         print OUT " /FR" if !$lib;
649         print OUT " /FD";
650         print OUT " /GZ" if $debug;
651         print OUT " " if $debug && $lib;
652         print OUT " /c";
653         print OUT "\r\n";
654
655         if($debug) {
656             print OUT "# SUBTRACT CPP /X /YX\r\n" if $dll;
657             print OUT "# ADD BASE MTL /nologo /D \"_DEBUG\" /mktyplib203 /win32\r\n" if $dll;
658             print OUT "# ADD MTL /nologo /D \"_DEBUG\" /mktyplib203 /win32\r\n" if $dll;
659             print OUT "# ADD BASE RSC /l 0x41d /d \"_DEBUG\"\r\n";
660             print OUT "# ADD RSC /l 0x41d";
661             if($wine) {
662                 foreach my $include (@includes) {
663                     print OUT " /i \"$include\"";
664                 }
665             }
666             print OUT " /d \"_DEBUG\"\r\n";
667         } else {
668             print OUT "# SUBTRACT CPP /YX\r\n" if $dll;
669             print OUT "# ADD BASE MTL /nologo /D \"NDEBUG\" /mktyplib203 /win32\r\n" if $dll;
670             print OUT "# ADD MTL /nologo /D \"NDEBUG\" /mktyplib203 /win32\r\n" if $dll;
671             print OUT "# ADD BASE RSC /l 0x41d /d \"NDEBUG\"\r\n";
672             print OUT "# ADD RSC /l 0x41d";
673             if($wine) {
674                 foreach my $include (@includes) {
675                     print OUT " /i \"$include\"";
676                 }
677             }
678             print OUT "/d \"NDEBUG\"\r\n";
679         }
680         print OUT "BSC32=bscmake.exe\r\n";
681         print OUT "# ADD BASE BSC32 /nologo\r\n";
682         print OUT "# ADD BSC32 /nologo\r\n";
683
684         if($exe || $dll) {
685             print OUT "LINK32=link.exe\r\n";
686             print OUT "# ADD BASE LINK32 ";
687             my @libraries = qw(kernel32.lib user32.lib gdi32.lib winspool.lib
688                                comdlg32.lib advapi32.lib shell32.lib ole32.lib
689                                oleaut32.lib uuid.lib odbc32.lib odbccp32.lib);
690             foreach my $library (@libraries) {
691                 print OUT "$library ";
692             }
693             print OUT " /nologo";
694             print OUT " /dll" if $dll;
695             print OUT " /subsystem:console" if $console;
696             print OUT " /debug" if $debug;
697             print OUT " /machine:I386";
698             print OUT " /pdbtype:sept" if $debug;
699             print OUT "\r\n";
700
701             print OUT "# ADD LINK32";
702             print OUT " /nologo";
703             print OUT " libcmt.lib" if $project =~ /^ntdll$/; # FIXME: Kludge
704             print OUT " /dll" if $dll;
705             print OUT " /subsystem:console" if $console;
706             print OUT " /debug" if $debug;
707             print OUT " /machine:I386";
708             print OUT " /nodefaultlib" if $project =~ /^ntdll$/; # FIXME: Kludge
709             print OUT " /def:\"$project.def\"" if $dll;
710             print OUT " /pdbtype:sept" if $debug;
711             print OUT "\r\n";
712         } else {
713             print OUT "LIB32=link.exe -lib\r\n";
714             print OUT "# ADD BASE LIB32 /nologo\r\n";
715             print OUT "# ADD LIB32 /nologo\r\n";
716         }
717
718         $n++;
719     }
720
721     if($#cfgs != 0) {
722         print OUT "\r\n";
723         print OUT "!ENDIF \r\n";
724         print OUT "\r\n";
725     }
726
727     if($project eq "winebuild") {
728         print OUT "# Begin Special Build Tool\r\n";
729         print OUT "SOURCE=\"\$(InputPath)\"\r\n";
730         print OUT "PostBuild_Desc=Copying wine.dll and wine_unicode.dll ...\r\n";
731         print OUT "PostBuild_Cmds=";
732         print OUT "copy ..\\..\\library\\$output_dir\\wine.dll \$(OutDir)\t";
733         print OUT "copy ..\\..\\unicode\\$output_dir\\wine_unicode.dll \$(OutDir)\r\n";
734         print OUT "# End Special Build Tool\r\n";
735     }
736     print OUT "# Begin Target\r\n";
737     print OUT "\r\n";
738     foreach my $cfg (@cfgs) {
739         print OUT "# Name \"$cfg\"\r\n";
740     }
741
742     print OUT "# Begin Group \"Source Files\"\r\n";
743     print OUT "\r\n";
744     print OUT "# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\r\n";
745
746     foreach my $source_file (@source_files) {
747         $source_file =~ s%/%\\%g;
748         if($source_file !~ /^\./) {
749             $source_file = ".\\$source_file";
750         }
751
752         if($source_file =~ /^(.*?)\.spec$/) {
753             my $basename = $1;
754
755             $basename = "$basename.dll" if $basename !~ /\..{1,3}$/;
756             my $dbg_c_file = "$basename.dbg.c";
757
758             print OUT "# Begin Source File\r\n";
759             print OUT "\r\n";
760             print OUT "SOURCE=$dbg_c_file\r\n";
761             print OUT "# End Source File\r\n";
762         }
763
764         print OUT "# Begin Source File\r\n";
765         print OUT "\r\n";
766
767         print OUT "SOURCE=$source_file\r\n";
768
769         if($source_file =~ /^(.*?)\.spec$/) {
770             my $basename = $1;
771
772             my $spec_file = $source_file;
773             my $def_file = "$basename.def";
774
775             $basename = "$basename.dll" if $basename !~ /\..{1,3}$/;
776             my $dbg_file = "$basename.dbg";
777             my $dbg_c_file = "$basename.dbg.c";
778
779             my $srcdir = "."; # FIXME: Is this really always correct?
780
781             print OUT "# Begin Custom Build\r\n";
782             print OUT "InputPath=$spec_file\r\n";
783             print OUT "\r\n";
784             print OUT "BuildCmds= \\\r\n";
785             print OUT "\t..\\..\\tools\\winebuild\\$output_dir\\winebuild.exe -def $spec_file > $def_file \\\r\n";
786             
787             if($project =~ /^ntdll$/) {
788                 my $n = 0;
789                 foreach my $c_src (@c_srcs) {
790                     if($n++ > 0)  {
791                         print OUT "\techo $c_src >> $dbg_file \\\r\n";
792                     } else {
793                         print OUT "\techo $c_src > $dbg_file \\\r\n";
794                     }
795                 }
796                 print OUT "\t..\\..\\tools\\winebuild\\$output_dir\\winebuild.exe";
797                 print OUT " -o $dbg_c_file -debug -C$srcdir $dbg_file \\\r\n";
798             } else {
799                 my $c_srcs = join(" ", grep(/\.c$/, @c_srcs));
800
801                 print OUT "\t..\\..\\tools\\winebuild\\$output_dir\\winebuild.exe";
802                 print OUT " -o $dbg_c_file -debug -C$srcdir $c_srcs \\\r\n";
803             }
804
805             print OUT "\t\r\n";
806             print OUT "\r\n";
807             print OUT "\"$def_file\" : \$(SOURCE) \"\$(INTDIR)\" \"\$(OUTDIR)\"\r\n";
808             print OUT "   \$(BuildCmds)\r\n";
809             print OUT "\r\n";
810             print OUT "\"$dbg_c_file\" : \$(SOURCE) \"\$(INTDIR)\" \"\$(OUTDIR)\"\r\n";
811             print OUT "   \$(BuildCmds)\r\n";
812             print OUT "# End Custom Build\r\n";
813         }
814
815         print OUT "# End Source File\r\n";
816     }
817     print OUT "# End Group\r\n";
818
819     print OUT "# Begin Group \"Header Files\"\r\n";
820     print OUT "\r\n";
821     print OUT "# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\r\n";
822     foreach my $header_file (@header_files) {
823         print OUT "# Begin Source File\r\n";
824         print OUT "\r\n";
825         print OUT "SOURCE=.\\$header_file\r\n";
826         print OUT "# End Source File\r\n";
827     }
828     print OUT "# End Group\r\n";
829
830
831
832     print OUT "# Begin Group \"Resource Files\"\r\n";
833     print OUT "\r\n";
834     print OUT "# PROP Default_Filter \"ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe\"\r\n";
835     foreach my $resource_file (@resource_files) {
836         print OUT "# Begin Source File\r\n";
837         print OUT "\r\n";
838         print OUT "SOURCE=.\\$resource_file\r\n";
839         print OUT "# End Source File\r\n";
840     }
841     print OUT "# End Group\r\n";
842
843     print OUT "# End Target\r\n";
844     print OUT "# End Project\r\n";
845
846     close(OUT);
847 }
848
849 sub _generate_dsw_header {
850     local *OUT = shift;
851
852     print OUT "Microsoft Developer Studio Workspace File, Format Version 6.00\r\n";
853     print OUT "# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r\n";
854     print OUT "\r\n";
855 }
856
857 sub _generate_dsw_project {
858     local *OUT = shift;
859
860     my $project = shift;
861     my $dsp_file = shift;
862     my @dependencies = @{(shift)};
863
864     $dsp_file = "./$dsp_file";
865     $dsp_file =~ y%/%\\%;
866     
867     @dependencies = sort(@dependencies);
868
869     print OUT "###############################################################################\r\n";
870     print OUT "\r\n";
871     print OUT "Project: \"$project\"=$dsp_file - Package Owner=<4>\r\n";
872     print OUT "\r\n";
873     print OUT "Package=<5>\r\n";
874     print OUT "{{{\r\n";
875     print OUT "}}}\r\n";
876     print OUT "\r\n";
877     print OUT "Package=<4>\r\n";
878     print OUT "{{{\r\n";
879     foreach my $dependency (@dependencies) {
880         print OUT "    Begin Project Dependency\r\n";
881         print OUT "    Project_Dep_Name $dependency\r\n";
882         print OUT "    End Project Dependency\r\n";
883     }
884     print OUT "}}}\r\n";
885     print OUT "\r\n";
886 }
887
888 sub _generate_dsw_footer {
889     local *OUT = shift;
890
891     print OUT "###############################################################################\r\n";
892     print OUT "\r\n";
893     print OUT "Global:\r\n";
894     print OUT "\r\n";
895     print OUT "Package=<5>\r\n";
896     print OUT "{{{\r\n";
897     print OUT "}}}\r\n";
898     print OUT "\r\n";
899     print OUT "Package=<3>\r\n";
900     print OUT "{{{\r\n";
901     print OUT "}}}\r\n";
902     print OUT "\r\n";
903     print OUT "###############################################################################\r\n";
904     print OUT "\r\n";
905 }
906
907 do {
908     my $dsw_file = "wine.dsw";
909     $output->progress("$dsw_file");
910     replace_file("$wine_dir/$dsw_file", \&_generate_wine_dsw);
911 };
912
913 sub _generate_wine_dsw {
914     local *OUT = shift;
915
916     _generate_dsw_header(\*OUT);
917     foreach my $module (sort(keys(%modules))) {
918         next if $module =~ /(?:winetest\.lib|_test\.exe)$/;
919
920         my $project = $modules{$module}{project};
921         my $dsp_file = $modules{$module}{dsp_file};
922
923         my @dependencies;
924         if($project =~ /^wine(?:_unicode)?$/) {
925             @dependencies = ();
926         } elsif($project =~ /^winebuild$/) {
927             @dependencies = ("wine", "wine_unicode");
928         } elsif($project =~ /^(?:gdi32|ntdll|user32)_.+?$/) {
929             @dependencies = ();
930         } else {
931             @dependencies = ("wine", "wine_unicode", "winebuild");
932         }
933
934         if($project =~ /^gdi32$/) {
935             foreach my $dir (@gdi32_dirs) {
936                 my $dir2 = $dir;
937                 $dir2 =~ s%^.*?/([^/]+)$%$1%;
938
939                 my $module = "gdi32_$dir2";
940                 $module =~ s%/%_%g;
941                 push @dependencies, $module;
942             }
943         } elsif($project =~ /^ntdll$/) {
944             foreach my $dir (@ntdll_dirs) {
945                 my $module = "ntdll_$dir";
946                 $module =~ s%/%_%g;
947                 push @dependencies, $module;
948             }
949         } elsif($project =~ /^user32$/) {
950             foreach my $dir (@user32_dirs) {
951                 my $dir2 = $dir;
952                 $dir2 =~ s%^.*?/([^/]+)$%$1%;
953
954                 my $module = "user32_$dir2";
955                 $module =~ s%/%_%g;
956                 push @dependencies, $module;
957             }
958         }
959
960         _generate_dsw_project(\*OUT, $project, $dsp_file, \@dependencies);
961     }
962     _generate_dsw_footer(\*OUT);
963
964     return 1;
965 }
966
967 do {
968     my $dsw_file = "winetest.dsw";
969     $output->progress("$dsw_file");
970     replace_file("$wine_dir/$dsw_file", \&_generate_winetest_dsw);
971 };
972
973 sub _generate_winetest_dsw {
974     local *OUT = shift;
975
976     _generate_dsw_header(\*OUT);
977
978     foreach my $module (sort(keys(%modules))) {
979         next if $module !~ /(?:winetest\.lib|_test\.exe)$/;
980
981         my $project = $modules{$module}{project};
982         my $dsp_file = $modules{$module}{dsp_file};
983
984         my @dependencies;
985         if($project =~ /^winetest$/) {
986             @dependencies = ();
987         } else {
988             @dependencies = ("winetest");
989         }
990
991         _generate_dsw_project(\*OUT, $project, $dsp_file, \@dependencies);
992     }
993
994     _generate_dsw_footer(\*OUT);
995 }
996
997 do {
998     foreach my $module (sort(keys(%modules))) {
999         next if $module !~ /_test\.exe$/;
1000
1001         my $project = $modules{$module}{project};
1002         my $dsp_file = $modules{$module}{dsp_file};
1003
1004         my $testlist_c = $dsp_file;
1005         $testlist_c =~ s%[^/]*\.dsp$%testlist.c%;
1006
1007         replace_file("$wine_dir/$testlist_c", \&_generate_testlist_c);
1008     }
1009 };
1010
1011 sub _generate_testlist_c {
1012     local *OUT = shift;
1013
1014     my @tests = qw(generated); # FIXME: Not alway correct
1015
1016     print OUT "/* Automatically generated file; DO NOT EDIT!! */\n";
1017     print OUT "\n";
1018     foreach my $test (@tests) {
1019         print OUT "extern void func_$test(void);\n";
1020     }
1021     print OUT "\n";
1022     print OUT "const struct\n";
1023     print OUT "{\n";
1024     print OUT "    const char *name;\n";
1025     print OUT "    void (*func)(void);\n";
1026     print OUT "} winetest_testlist[] =\n";
1027     print OUT "{\n";
1028     foreach my $test (@tests) {
1029         print OUT "    { \"$test\", func_$test },\n";
1030     }
1031     print OUT "    { 0, 0 }\n";
1032     print OUT "};\n";
1033 }
1034
1035 do {
1036     my $config_h = "include/config.h";
1037
1038     $output->progress("$config_h");
1039
1040     replace_file("$wine_dir/$config_h", \&_generate_config_h);
1041 };
1042
1043 sub _generate_config_h {
1044     local *OUT = shift;
1045
1046     print OUT "#define __WINE_CONFIG_H\n";
1047     print OUT "\n";
1048
1049     my @headers = qw(direct.h io.h);
1050     foreach my $header (@headers) {
1051         $header =~ y/\.\//__/;
1052         print OUT "#define HAVE_\U$header\E\n";
1053         print OUT "\n";
1054     }
1055
1056     my @functions = qw(
1057         _alldiv _allmul _allrem _aulldiv _aullrem
1058         _access _chdir _close _lseek _mkdir _open _pclose _popen _read _rmdir _write _stat
1059         _snprintf _stricmp _strnicmp _vsnprintf _wcsicmp wcslen
1060         ecvt fcvt gcvt
1061         strerror
1062     );
1063     foreach my $function (@functions) {
1064         print OUT "#define HAVE_\U$function\E 1\n";
1065         print OUT "\n";
1066     }
1067
1068     if(0) {
1069         print OUT "#define NEED_STDCALL_DECORATION 1\n";
1070         print OUT "\n";
1071     }
1072
1073     print OUT "#define X_DISPLAY_MISSING 1\n";
1074     print OUT "\n";
1075
1076     print OUT "/* Define to a macro to generate an assembly function directive */\n";
1077     print OUT "#define __ASM_FUNC(name) \"\"\n";
1078     print OUT "\n";
1079
1080     print OUT "/* Define to a macro to generate an assembly name from a C symbol */\n";
1081     print OUT "#define __ASM_NAME(name) name\n";
1082     print OUT "\n";
1083
1084     print OUT "/* Define to the address where bug reports for this package should be sent. */\n";
1085     print OUT "#define PACKAGE_BUGREPORT \"\"\n";
1086     print OUT "\n";
1087
1088     print OUT "/* Define to the full name of this package. */\n";
1089     print OUT "#define PACKAGE_NAME \"Wine\"\n";
1090     print OUT "\n";
1091
1092     print OUT "/* Define to the full name and version of this package. */\n";
1093     print OUT "#define PACKAGE_STRING \"Wine YYYYMMDD\"\n";
1094     print OUT "\n";
1095
1096     print OUT "/* Define to the one symbol short name of this package. */\n";
1097     print OUT "#define PACKAGE_TARNAME \"wine\"\n";
1098     print OUT "\n";
1099
1100     print OUT "/* Define to the version of this package. */\n";
1101     print OUT "#define PACKAGE_VERSION \"YYYYMMDD\"\n";
1102     print OUT "\n";
1103
1104     close(OUT);
1105 }