Skip to content

Commit c66939c

Browse files
committed
Add MSVC build tools.
Magnus Hagander
1 parent f8bbfad commit c66939c

File tree

8 files changed

+1048
-0
lines changed

8 files changed

+1048
-0
lines changed

src/tools/msvc/Project.pm

Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
package Project;
2+
3+
use Carp;
4+
use strict;
5+
use warnings;
6+
7+
sub new {
8+
my ($junk, $name, $type, $solution) = @_;
9+
my $good_types = {
10+
lib => 1,
11+
exe => 1,
12+
dll => 1,
13+
};
14+
confess("Bad project type: $type\n") unless exists $good_types->{$type};
15+
my $self = {
16+
name => $name,
17+
type => $type,
18+
guid => Win32::GuidGen(),
19+
files => {},
20+
references => [],
21+
libraries => '',
22+
includes => '',
23+
defines => ';',
24+
solution => $solution,
25+
disablewarnings => '4018;4244',
26+
};
27+
28+
bless $self;
29+
return $self;
30+
}
31+
32+
sub AddFile {
33+
my ($self, $filename) = @_;
34+
35+
$self->{files}->{$filename} = 1;
36+
}
37+
38+
sub AddFiles {
39+
my $self = shift;
40+
my $dir = shift;
41+
42+
while (my $f = shift) {
43+
$self->{files}->{$dir . "\\" . $f} = 1;
44+
}
45+
}
46+
47+
sub ReplaceFile {
48+
my ($self, $filename, $newname) = @_;
49+
my $re = "\\\\$filename\$";
50+
51+
foreach my $file ( keys %{ $self->{files} } ) {
52+
# Match complete filename
53+
if ($filename =~ /\\/) {
54+
if ($file eq $filename) {
55+
delete $self->{files}{$file};
56+
$self->{files}{$newname} = 1;
57+
return;
58+
}
59+
}
60+
elsif ($file =~ m/($re)/) {
61+
delete $self->{files}{$file};
62+
$self->{files}{ "$newname\\$filename" } = 1;
63+
return;
64+
}
65+
}
66+
confess("Could not find file $filename to replace\n");
67+
}
68+
69+
sub RemoveFile {
70+
my ($self, $filename) = @_;
71+
my $orig = scalar keys %{ $self->{files} };
72+
delete $self->{files}->{$filename};
73+
if ($orig > scalar keys %{$self->{files}} ) {
74+
return;
75+
}
76+
confess("Could not find file $filename to remove\n");
77+
}
78+
79+
sub AddReference {
80+
my $self = shift;
81+
82+
while (my $ref = shift) {
83+
push @{$self->{references}},$ref;
84+
$self->AddLibrary("debug\\" . $ref->{name} . "\\" . $ref->{name} . ".lib") if ($ref->{type} eq "exe");
85+
}
86+
}
87+
88+
sub AddLibrary {
89+
my ($self, $lib) = @_;
90+
91+
if ($self->{libraries} ne '') {
92+
$self->{libraries} .= ' ';
93+
}
94+
$self->{libraries} .= $lib;
95+
}
96+
97+
sub AddIncludeDir {
98+
my ($self, $inc) = @_;
99+
100+
if ($self->{includes} ne '') {
101+
$self->{includes} .= ';';
102+
}
103+
$self->{includes} .= $inc;
104+
}
105+
106+
sub AddDefine {
107+
my ($self, $def) = @_;
108+
109+
$self->{defines} .= $def . ';';
110+
}
111+
112+
sub FullExportDLL {
113+
my ($self, $libname) = @_;
114+
115+
$self->{builddef} = 1;
116+
$self->{def} = ".\\debug\\$self->{name}\\$self->{name}.def";
117+
$self->{implib} = "debug\\$self->{name}\\$libname";
118+
}
119+
120+
sub UseDef {
121+
my ($self, $def) = @_;
122+
123+
$self->{def} = $def;
124+
}
125+
126+
sub AddDir {
127+
my ($self, $reldir) = @_;
128+
my $MF;
129+
130+
my $t = $/;undef $/;
131+
open($MF,"$reldir\\Makefile") || open($MF,"$reldir\\GNUMakefile") || croak "Could not open $reldir\\Makefile\n";
132+
my $mf = <$MF>;
133+
close($MF);
134+
135+
$mf =~ s{\\\s*[\r\n]+}{}mg;
136+
if ($mf =~ m{^(?:SUB)?DIRS[^=]*=\s*(.*)$}mg) {
137+
foreach my $subdir (split /\s+/,$1) {
138+
next if $subdir eq "\$(top_builddir)/src/timezone"; #special case for non-standard include
139+
$self->AddDir($reldir . "\\" . $subdir);
140+
}
141+
}
142+
while ($mf =~ m{^(?:EXTRA_)?OBJS[^=]*=\s*(.*)$}m) {
143+
my $s = $1;
144+
my $filter_re = qr{\$\(filter ([^,]+),\s+\$\(([^\)]+)\)\)};
145+
while ($s =~ /$filter_re/) {
146+
# Process $(filter a b c, $(VAR)) expressions
147+
my $list = $1;
148+
my $filter = $2;
149+
$list =~ s/\.o/\.c/g;
150+
my @pieces = split /\s+/, $list;
151+
my $matches = "";
152+
foreach my $p (@pieces) {
153+
if ($filter eq "LIBOBJS") {
154+
if (grep(/$p/, @main::pgportfiles) == 1) {
155+
$p =~ s/\.c/\.o/;
156+
$matches .= $p . " ";
157+
}
158+
}
159+
else {
160+
confess "Unknown filter $filter\n";
161+
}
162+
}
163+
$s =~ s/$filter_re/$matches/;
164+
}
165+
foreach my $f (split /\s+/,$s) {
166+
next if $f =~ /^\s*$/;
167+
next if $f eq "\\";
168+
next if $f =~ /\/SUBSYS.o$/;
169+
$f =~ s/,$//; # Remove trailing comma that can show up from filter stuff
170+
next unless $f =~ /.*\.o$/;
171+
$f =~ s/\.o$/\.c/;
172+
if ($f =~ /^\$\(top_builddir\)\/(.*)/) {
173+
$f = $1;
174+
$f =~ s/\//\\/g;
175+
$self->{files}->{$f} = 1;
176+
}
177+
else {
178+
$f =~ s/\//\\/g;
179+
$self->{files}->{"$reldir\\$f"} = 1;
180+
}
181+
}
182+
$mf =~ s{OBJS[^=]*=\s*(.*)$}{}m;
183+
}
184+
185+
# Match rules that pull in source files from different directories
186+
my $replace_re = qr{^([^:\n\$]+\.c)\s*:\s*(?:%\s*: )?\$(\([^\)]+\))\/(.*)\/[^\/]+$};
187+
while ($mf =~ m{$replace_re}m) {
188+
my $match = $1;
189+
my $top = $2;
190+
my $target = $3;
191+
$target =~ s{/}{\\}g;
192+
my @pieces = split /\s+/,$match;
193+
foreach my $fn (@pieces) {
194+
if ($top eq "(top_srcdir)") {
195+
eval { $self->ReplaceFile($fn, $target) };
196+
}
197+
elsif ($top eq "(backend_src)") {
198+
eval { $self->ReplaceFile($fn, "src\\backend\\$target") };
199+
}
200+
else {
201+
confess "Bad replacement top: $top, on line $_\n";
202+
}
203+
}
204+
$mf =~ s{$replace_re}{}m;
205+
}
206+
207+
# See if this Makefile contains a description, and should have a RC file
208+
if ($mf =~ /^PGFILEDESC\s*=\s*\"([^\"]+)\"/m) {
209+
my $desc = $1;
210+
my $ico;
211+
if ($mf =~ /^PGAPPICON\s*=\s*(.*)$/m) { $ico = $1; }
212+
$self->AddResourceFile($reldir,$desc,$ico);
213+
}
214+
$/ = $t;
215+
}
216+
217+
sub AddResourceFile {
218+
my ($self, $dir, $desc, $ico) = @_;
219+
220+
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
221+
my $d = ($year - 100) . "$yday";
222+
223+
if (Solution::IsNewer("$dir\\win32ver.rc",'src\port\win32ver.rc')) {
224+
print "Generating win32ver.rc for $dir\n";
225+
open(I,'src\port\win32ver.rc') || confess "Could not open win32ver.rc";
226+
open(O,">$dir\\win32ver.rc") || confess "Could not write win32ver.rc";
227+
my $icostr = $ico?"IDI_ICON ICON \"src/port/$ico.ico\"":"";
228+
while (<I>) {
229+
s/FILEDESC/"$desc"/gm;
230+
s/_ICO_/$icostr/gm;
231+
s/(VERSION.*),0/$1,$d/;
232+
if ($self->{type} eq "dll") {
233+
s/VFT_APP/VFT_DLL/gm;
234+
}
235+
print O;
236+
}
237+
}
238+
close(O);
239+
close(I);
240+
$self->AddFile("$dir\\win32ver.rc");
241+
}
242+
243+
sub Save {
244+
my ($self) = @_;
245+
246+
# If doing DLL and haven't specified a DEF file, do a full export of all symbols
247+
# in the project.
248+
if ($self->{type} eq "dll" && !$self->{def}) {
249+
$self->FullExportDLL($self->{name} . ".lib");
250+
}
251+
252+
# Dump the project
253+
open(F, ">$self->{name}.vcproj") || croak("Could not write to $self->{name}.vcproj\n");
254+
$self->WriteHeader(*F);
255+
$self->WriteReferences(*F);
256+
print F <<EOF;
257+
<Files>
258+
EOF
259+
my @dirstack = ();
260+
my %uniquefiles;
261+
foreach my $f (sort keys %{ $self->{files} }) {
262+
confess "Bad format filename '$f'\n" unless ($f =~ /^(.*)\\([^\\]+)\.[r]?[cyl]$/);
263+
my $dir = $1;
264+
my $file = $2;
265+
266+
# Walk backwards down the directory stack and close any dirs we're done with
267+
while ($#dirstack >= 0) {
268+
if (join('\\',@dirstack) eq substr($dir, 0, length(join('\\',@dirstack)))) {
269+
last if (length($dir) == length(join('\\',@dirstack)));
270+
last if (substr($dir, length(join('\\',@dirstack)),1) eq '\\');
271+
}
272+
print F ' ' x $#dirstack . " </Filter>\n";
273+
pop @dirstack;
274+
}
275+
# Now walk forwards and create whatever directories are needed
276+
while (join('\\',@dirstack) ne $dir) {
277+
my $left = substr($dir, length(join('\\',@dirstack)));
278+
$left =~ s/^\\//;
279+
my @pieces = split /\\/, $left;
280+
push @dirstack, $pieces[0];
281+
print F ' ' x $#dirstack . " <Filter Name=\"$pieces[0]\" Filter=\"\">\n";
282+
}
283+
284+
print F ' ' x $#dirstack . " <File RelativePath=\"$f\"";
285+
if ($f =~ /\.y$/) {
286+
my $of = $f;
287+
$of =~ s/\.y$/.c/;
288+
$of =~ s{^src\\pl\\plpgsql\\src\\gram.c$}{src\\pl\\plpgsql\\src\\pl_gram.c};
289+
print F '><FileConfiguration Name="Debug|Win32"><Tool Name="VCCustomBuildTool" Description="Running bison on ' . $f . '" CommandLine="vcbuild\pgbison.bat ' . $f . '" AdditionalDependencies="" Outputs="' . $of . '" /></FileConfiguration></File>' . "\n";
290+
}
291+
elsif ($f =~ /\.l$/) {
292+
my $of = $f;
293+
$of =~ s/\.l$/.c/;
294+
$of =~ s{^src\\pl\\plpgsql\\src\\scan.c$}{src\\pl\\plpgsql\\src\\pl_scan.c};
295+
print F "><FileConfiguration Name=\"Debug|Win32\"><Tool Name=\"VCCustomBuildTool\" Description=\"Running flex on $f\" CommandLine=\"vcbuild\\pgflex.bat $f\" AdditionalDependencies=\"\" Outputs=\"$of\" /></FileConfiguration></File>\n";
296+
}
297+
elsif (defined($uniquefiles{$file})) {
298+
# File already exists, so fake a new name
299+
my $obj = $dir;
300+
$obj =~ s/\\/_/g;
301+
print F "><FileConfiguration Name=\"Debug|Win32\"><Tool Name=\"VCCLCompilerTool\" ObjectFile=\".\\debug\\$self->{name}\\$obj" . "_$file.obj\" /></FileConfiguration></File>\n";
302+
}
303+
else {
304+
$uniquefiles{$file} = 1;
305+
print F " />\n";
306+
}
307+
}
308+
while ($#dirstack >= 0) {
309+
print F ' ' x $#dirstack . " </Filter>\n";
310+
pop @dirstack;
311+
}
312+
$self->Footer(*F);
313+
close(F);
314+
}
315+
316+
sub WriteReferences {
317+
my ($self, $f) = @_;
318+
print $f " <References>\n";
319+
foreach my $ref (@{$self->{references}}) {
320+
print $f " <ProjectReference ReferencedProjectIdentifier=\"$ref->{guid}\" Name=\"$ref->{name}\" />\n";
321+
}
322+
print $f " </References>\n";
323+
}
324+
325+
sub WriteHeader {
326+
my ($self, $f) = @_;
327+
328+
my $cfgtype = ($self->{type} eq "exe")?1:($self->{type} eq "dll"?2:4);
329+
330+
print $f <<EOF;
331+
<?xml version="1.0" encoding="Windows-1252"?>
332+
<VisualStudioProject ProjectType="Visual C++" Version="8.00" Name="$self->{name}" ProjectGUID="$self->{guid}">
333+
<Platforms><Platform Name="Win32"/></Platforms>
334+
<Configurations>
335+
<Configuration Name="Debug|Win32" OutputDirectory=".\\Debug\\$self->{name}" IntermediateDirectory=".\\Debug\\$self->{name}"
336+
ConfigurationType="$cfgtype" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="FALSE" CharacterSet="2">
337+
<Tool Name="VCCLCompilerTool" Optimization="0"
338+
AdditionalIncludeDirectories="src/include;src/include/port/win32;src/include/port/win32_msvc;$self->{solution}->{options}->{pthread};$self->{includes}"
339+
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;__WINDOWS__;DEBUG=1;__WIN32__;EXEC_BACKEND;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE$self->{defines}"
340+
RuntimeLibrary="3" DisableSpecificWarnings="$self->{disablewarnings}"
341+
EOF
342+
print $f <<EOF;
343+
AssemblerOutput="0" AssemblerListingLocation=".\\debug\\$self->{name}\\" ObjectFile=".\\debug\\$self->{name}\\"
344+
ProgramDataBaseFileName=".\\debug\\$self->{name}\\" BrowseInformation="0"
345+
WarningLevel="3" SuppressStartupBanner="TRUE" DebugInformationFormat="3" CompileAs="0"/>
346+
<Tool Name="VCLinkerTool" OutputFile=".\\debug\\$self->{name}\\$self->{name}.$self->{type}"
347+
AdditionalDependencies="$self->{libraries}"
348+
LinkIncremental="0" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="" IgnoreDefaultLibraryNames="libc"
349+
StackReserveSize="4194304" DisableSpecificWarnings="$self->{disablewarnings}"
350+
GenerateDebugInformation="TRUE" ProgramDatabaseFile=".\\debug\\$self->{name}\\$self->{name}.pdb"
351+
GenerateMapFile="FALSE" MapFileName=".\\debug\\$self->{name}\\$self->{name}.map"
352+
SubSystem="1" TargetMachine="1"
353+
EOF
354+
if ($self->{implib}) {
355+
print $f "\t\tImportLibrary=\"$self->{implib}\"\n";
356+
}
357+
if ($self->{def}) {
358+
print $f "\t\tModuleDefinitionFile=\"$self->{def}\"\n";
359+
}
360+
361+
print $f "\t/>\n";
362+
print $f "\t<Tool Name=\"VCLibrarianTool\" OutputFile=\".\\Debug\\$self->{name}\\$self->{name}.lib\" IgnoreDefaultLibraryNames=\"libc\" />\n";
363+
print $f "\t<Tool Name=\"VCResourceCompilerTool\" AdditionalIncludeDirectories=\"src\\include\" />\n";
364+
if ($self->{builddef}) {
365+
print $f "\t<Tool Name=\"VCPreLinkEventTool\" Description=\"Generate DEF file\" CommandLine=\"perl vcbuild\\gendef.pl debug\\$self->{name}\" />\n";
366+
}
367+
print $f <<EOF;
368+
</Configuration>
369+
</Configurations>
370+
EOF
371+
}
372+
373+
sub Footer {
374+
my ($self, $f) = @_;
375+
376+
print $f <<EOF;
377+
</Files>
378+
<Globals/>
379+
</VisualStudioProject>
380+
EOF
381+
}
382+
383+
384+
1;

0 commit comments

Comments
 (0)