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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy