OSDN Git Service

Add MSVC build tools.
authorBruce Momjian <bruce@momjian.us>
Mon, 4 Sep 2006 21:30:40 +0000 (21:30 +0000)
committerBruce Momjian <bruce@momjian.us>
Mon, 4 Sep 2006 21:30:40 +0000 (21:30 +0000)
Magnus Hagander

src/tools/msvc/Project.pm [new file with mode: 0644]
src/tools/msvc/Solution.pm [new file with mode: 0644]
src/tools/msvc/build.bat [new file with mode: 0755]
src/tools/msvc/config.pl [new file with mode: 0644]
src/tools/msvc/gendef.pl [new file with mode: 0644]
src/tools/msvc/mkvcbuild.pl [new file with mode: 0644]
src/tools/msvc/pgbison.bat [new file with mode: 0755]
src/tools/msvc/pgflex.bat [new file with mode: 0755]

diff --git a/src/tools/msvc/Project.pm b/src/tools/msvc/Project.pm
new file mode 100644 (file)
index 0000000..239a473
--- /dev/null
@@ -0,0 +1,384 @@
+package Project;
+
+use Carp;
+use strict;
+use warnings;
+
+sub new {
+       my ($junk, $name, $type, $solution) = @_;
+    my $good_types = {
+        lib => 1,
+        exe => 1,
+        dll => 1,
+    };
+       confess("Bad project type: $type\n") unless exists $good_types->{$type};
+       my $self = {
+        name            => $name,
+        type            => $type,
+        guid            => Win32::GuidGen(),
+        files           => {},
+        references      => [],
+        libraries       => '',
+        includes        => '',
+        defines         => ';',
+               solution        => $solution,
+        disablewarnings => '4018;4244',
+    };
+
+       bless $self;
+       return $self;
+}
+
+sub AddFile {
+       my ($self, $filename) = @_;
+
+       $self->{files}->{$filename} = 1;
+}
+
+sub AddFiles {
+       my $self = shift;
+       my $dir = shift;
+
+       while (my $f = shift) {
+               $self->{files}->{$dir . "\\" . $f} = 1;
+       }
+}
+
+sub ReplaceFile {
+       my ($self, $filename, $newname) = @_;
+       my $re = "\\\\$filename\$";
+
+       foreach my $file ( keys %{ $self->{files} } ) {
+        # Match complete filename
+               if ($filename =~ /\\/) {
+                       if ($file eq $filename) {
+                delete $self->{files}{$file};
+                $self->{files}{$newname} = 1;
+                               return;
+                       }
+               }
+               elsif ($file =~ m/($re)/) {
+            delete $self->{files}{$file};
+            $self->{files}{ "$newname\\$filename" } = 1;
+                       return;
+               }
+       }
+       confess("Could not find file $filename to replace\n");
+}
+
+sub RemoveFile {
+       my ($self, $filename) = @_;
+    my $orig = scalar keys %{ $self->{files} };
+    delete $self->{files}->{$filename};
+    if ($orig > scalar keys %{$self->{files}} ) {
+        return;
+    }
+       confess("Could not find file $filename to remove\n");
+}
+
+sub AddReference {
+       my $self = shift;
+
+       while (my $ref = shift) {
+               push @{$self->{references}},$ref;
+               $self->AddLibrary("debug\\" . $ref->{name} . "\\" . $ref->{name} . ".lib") if ($ref->{type} eq "exe");
+       }
+}
+
+sub AddLibrary {
+       my ($self, $lib) = @_;
+
+       if ($self->{libraries} ne '') {
+               $self->{libraries} .= ' ';
+       }
+       $self->{libraries} .= $lib;
+}
+
+sub AddIncludeDir {
+       my ($self, $inc) = @_;
+
+       if ($self->{includes} ne '') {
+               $self->{includes} .= ';';
+       }
+       $self->{includes} .= $inc;
+}
+
+sub AddDefine {
+       my ($self, $def) = @_;
+
+       $self->{defines} .= $def . ';';
+}
+
+sub FullExportDLL {
+       my ($self, $libname) = @_;
+
+       $self->{builddef} = 1;
+       $self->{def} = ".\\debug\\$self->{name}\\$self->{name}.def";
+       $self->{implib} = "debug\\$self->{name}\\$libname";
+}
+
+sub UseDef {
+       my ($self, $def) = @_;
+
+       $self->{def} = $def;
+}
+
+sub AddDir {
+       my ($self, $reldir) = @_;
+       my $MF;
+
+       my $t = $/;undef $/;
+       open($MF,"$reldir\\Makefile") || open($MF,"$reldir\\GNUMakefile") || croak "Could not open $reldir\\Makefile\n";
+       my $mf = <$MF>;
+       close($MF);
+
+       $mf =~ s{\\\s*[\r\n]+}{}mg;
+       if ($mf =~ m{^(?:SUB)?DIRS[^=]*=\s*(.*)$}mg) {
+               foreach my $subdir (split /\s+/,$1) {
+                       next if $subdir eq "\$(top_builddir)/src/timezone"; #special case for non-standard include
+                               $self->AddDir($reldir . "\\" . $subdir);
+               }
+       }
+       while ($mf =~ m{^(?:EXTRA_)?OBJS[^=]*=\s*(.*)$}m) {
+               my $s = $1;
+               my $filter_re = qr{\$\(filter ([^,]+),\s+\$\(([^\)]+)\)\)};
+               while ($s =~ /$filter_re/) {
+# Process $(filter a b c, $(VAR)) expressions
+                       my $list = $1;
+                       my $filter = $2;
+                       $list =~ s/\.o/\.c/g;
+                       my @pieces = split /\s+/, $list;
+                       my $matches = "";
+                       foreach my $p (@pieces) {
+                               if ($filter eq "LIBOBJS") {
+                                       if (grep(/$p/, @main::pgportfiles) == 1) {
+                                               $p =~ s/\.c/\.o/;
+                                               $matches .= $p . " ";
+                                       }
+                               }
+                               else {
+                                       confess "Unknown filter $filter\n";
+                               }
+                       }
+                       $s =~ s/$filter_re/$matches/;
+               }
+               foreach my $f (split /\s+/,$s) {
+                       next if $f =~ /^\s*$/;
+                       next if $f eq "\\";
+                       next if $f =~ /\/SUBSYS.o$/;
+                       $f =~ s/,$//; # Remove trailing comma that can show up from filter stuff
+                       next unless $f =~ /.*\.o$/;
+                       $f =~ s/\.o$/\.c/;
+                       if ($f =~ /^\$\(top_builddir\)\/(.*)/) {
+                               $f = $1;
+                               $f =~ s/\//\\/g;
+                               $self->{files}->{$f} = 1;
+                       }
+                       else {
+                               $f =~ s/\//\\/g;
+                               $self->{files}->{"$reldir\\$f"} = 1;
+                       }
+               }
+               $mf =~ s{OBJS[^=]*=\s*(.*)$}{}m;
+       }
+
+# Match rules that pull in source files from different directories
+       my $replace_re = qr{^([^:\n\$]+\.c)\s*:\s*(?:%\s*: )?\$(\([^\)]+\))\/(.*)\/[^\/]+$};
+       while ($mf =~ m{$replace_re}m) {
+               my $match = $1;
+               my $top = $2;
+               my $target = $3;
+               $target =~ s{/}{\\}g;
+               my @pieces = split /\s+/,$match;
+               foreach my $fn (@pieces) {
+                       if ($top eq "(top_srcdir)") {
+                               eval { $self->ReplaceFile($fn, $target) };
+                       }
+                       elsif ($top eq "(backend_src)") {
+                               eval { $self->ReplaceFile($fn, "src\\backend\\$target") };
+                       }
+                       else {
+                               confess "Bad replacement top: $top, on line $_\n";
+                       }
+               }
+               $mf =~ s{$replace_re}{}m;
+       }
+
+# See if this Makefile contains a description, and should have a RC file
+       if ($mf =~ /^PGFILEDESC\s*=\s*\"([^\"]+)\"/m) {
+               my $desc = $1;
+               my $ico;
+               if ($mf =~ /^PGAPPICON\s*=\s*(.*)$/m) { $ico = $1; }
+               $self->AddResourceFile($reldir,$desc,$ico);
+       }
+       $/ = $t;
+}
+
+sub AddResourceFile {
+       my ($self, $dir, $desc, $ico) = @_;
+
+       my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+       my $d = ($year - 100) . "$yday";
+
+       if (Solution::IsNewer("$dir\\win32ver.rc",'src\port\win32ver.rc')) {
+               print "Generating win32ver.rc for $dir\n";
+               open(I,'src\port\win32ver.rc') || confess "Could not open win32ver.rc";
+               open(O,">$dir\\win32ver.rc") || confess "Could not write win32ver.rc";
+               my $icostr = $ico?"IDI_ICON ICON \"src/port/$ico.ico\"":"";
+               while (<I>) {
+                       s/FILEDESC/"$desc"/gm;
+                       s/_ICO_/$icostr/gm;
+                       s/(VERSION.*),0/$1,$d/;
+                       if ($self->{type} eq "dll") {
+                               s/VFT_APP/VFT_DLL/gm;
+                       }
+                       print O;
+               }
+       }
+       close(O);
+       close(I);
+       $self->AddFile("$dir\\win32ver.rc");
+}
+
+sub Save {
+       my ($self) = @_;
+
+# If doing DLL and haven't specified a DEF file, do a full export of all symbols
+# in the project.
+       if ($self->{type} eq "dll" && !$self->{def}) {
+               $self->FullExportDLL($self->{name} . ".lib");
+       }
+
+# Dump the project
+       open(F, ">$self->{name}.vcproj") || croak("Could not write to $self->{name}.vcproj\n");
+       $self->WriteHeader(*F);
+       $self->WriteReferences(*F);
+       print F <<EOF;
+ <Files>
+EOF
+       my @dirstack = ();
+       my %uniquefiles;
+       foreach my $f (sort keys %{ $self->{files} }) {
+               confess "Bad format filename '$f'\n" unless ($f =~ /^(.*)\\([^\\]+)\.[r]?[cyl]$/);
+               my $dir = $1;
+               my $file = $2;
+
+# Walk backwards down the directory stack and close any dirs we're done with
+               while ($#dirstack >= 0) {
+                       if (join('\\',@dirstack) eq substr($dir, 0, length(join('\\',@dirstack)))) {
+                               last if (length($dir) == length(join('\\',@dirstack)));
+                               last if (substr($dir, length(join('\\',@dirstack)),1) eq '\\');
+                       }
+                       print F ' ' x $#dirstack . "  </Filter>\n";
+                       pop @dirstack;
+               }
+# Now walk forwards and create whatever directories are needed
+               while (join('\\',@dirstack) ne $dir) {
+                       my $left = substr($dir, length(join('\\',@dirstack)));
+                       $left =~ s/^\\//;
+                       my @pieces = split /\\/, $left;
+                       push @dirstack, $pieces[0];
+                       print F ' ' x $#dirstack . "  <Filter Name=\"$pieces[0]\" Filter=\"\">\n";
+               }
+
+               print F ' ' x $#dirstack . "   <File RelativePath=\"$f\"";
+               if ($f =~ /\.y$/) {
+                       my $of = $f;
+                       $of =~ s/\.y$/.c/;
+                       $of =~ s{^src\\pl\\plpgsql\\src\\gram.c$}{src\\pl\\plpgsql\\src\\pl_gram.c};
+                       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";
+               }
+               elsif ($f =~ /\.l$/) {
+                       my $of = $f;
+                       $of =~ s/\.l$/.c/;
+                       $of =~ s{^src\\pl\\plpgsql\\src\\scan.c$}{src\\pl\\plpgsql\\src\\pl_scan.c};
+                       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";
+               }
+               elsif (defined($uniquefiles{$file})) {
+# File already exists, so fake a new name
+                       my $obj = $dir;
+                       $obj =~ s/\\/_/g;
+                       print F "><FileConfiguration Name=\"Debug|Win32\"><Tool Name=\"VCCLCompilerTool\" ObjectFile=\".\\debug\\$self->{name}\\$obj" . "_$file.obj\" /></FileConfiguration></File>\n";
+               }
+               else {
+                       $uniquefiles{$file} = 1;
+                       print F " />\n";
+               }
+       }
+       while ($#dirstack >= 0) {
+               print F ' ' x $#dirstack . "  </Filter>\n";
+               pop @dirstack;
+       }
+       $self->Footer(*F);
+       close(F);
+}
+
+sub WriteReferences {
+       my ($self, $f) = @_;
+       print $f " <References>\n";
+       foreach my $ref (@{$self->{references}}) {
+               print $f "  <ProjectReference ReferencedProjectIdentifier=\"$ref->{guid}\" Name=\"$ref->{name}\" />\n";
+       }
+       print $f " </References>\n";
+}
+
+sub WriteHeader {
+       my ($self, $f) = @_;
+
+       my $cfgtype = ($self->{type} eq "exe")?1:($self->{type} eq "dll"?2:4);
+
+       print $f <<EOF;
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject ProjectType="Visual C++" Version="8.00" Name="$self->{name}" ProjectGUID="$self->{guid}">
+ <Platforms><Platform Name="Win32"/></Platforms>
+ <Configurations>
+  <Configuration Name="Debug|Win32" OutputDirectory=".\\Debug\\$self->{name}" IntermediateDirectory=".\\Debug\\$self->{name}"
+       ConfigurationType="$cfgtype" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="FALSE" CharacterSet="2">
+       <Tool Name="VCCLCompilerTool" Optimization="0"
+               AdditionalIncludeDirectories="src/include;src/include/port/win32;src/include/port/win32_msvc;$self->{solution}->{options}->{pthread};$self->{includes}"
+               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;__WINDOWS__;DEBUG=1;__WIN32__;EXEC_BACKEND;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE$self->{defines}"
+               RuntimeLibrary="3" DisableSpecificWarnings="$self->{disablewarnings}"
+EOF
+       print $f <<EOF;
+               AssemblerOutput="0" AssemblerListingLocation=".\\debug\\$self->{name}\\" ObjectFile=".\\debug\\$self->{name}\\"
+               ProgramDataBaseFileName=".\\debug\\$self->{name}\\" BrowseInformation="0"
+               WarningLevel="3" SuppressStartupBanner="TRUE" DebugInformationFormat="3" CompileAs="0"/>
+       <Tool Name="VCLinkerTool" OutputFile=".\\debug\\$self->{name}\\$self->{name}.$self->{type}"
+               AdditionalDependencies="$self->{libraries}"
+               LinkIncremental="0" SuppressStartupBanner="TRUE" AdditionalLibraryDirectories="" IgnoreDefaultLibraryNames="libc"
+               StackReserveSize="4194304" DisableSpecificWarnings="$self->{disablewarnings}"
+               GenerateDebugInformation="TRUE" ProgramDatabaseFile=".\\debug\\$self->{name}\\$self->{name}.pdb"
+               GenerateMapFile="FALSE" MapFileName=".\\debug\\$self->{name}\\$self->{name}.map"
+               SubSystem="1" TargetMachine="1"
+EOF
+       if ($self->{implib}) {
+               print $f "\t\tImportLibrary=\"$self->{implib}\"\n";
+       }
+       if ($self->{def}) {
+               print $f "\t\tModuleDefinitionFile=\"$self->{def}\"\n";
+       }
+
+       print $f "\t/>\n";
+       print $f "\t<Tool Name=\"VCLibrarianTool\" OutputFile=\".\\Debug\\$self->{name}\\$self->{name}.lib\" IgnoreDefaultLibraryNames=\"libc\" />\n";
+       print $f "\t<Tool Name=\"VCResourceCompilerTool\" AdditionalIncludeDirectories=\"src\\include\" />\n";
+       if ($self->{builddef}) {
+               print $f "\t<Tool Name=\"VCPreLinkEventTool\" Description=\"Generate DEF file\" CommandLine=\"perl vcbuild\\gendef.pl debug\\$self->{name}\" />\n";
+       }
+       print $f <<EOF;
+  </Configuration>
+ </Configurations>
+EOF
+}
+
+sub Footer {
+       my ($self, $f) = @_;
+
+       print $f <<EOF;
+ </Files>
+ <Globals/>
+</VisualStudioProject>
+EOF
+}
+
+
+1;
diff --git a/src/tools/msvc/Solution.pm b/src/tools/msvc/Solution.pm
new file mode 100644 (file)
index 0000000..2b1357b
--- /dev/null
@@ -0,0 +1,301 @@
+package Solution;
+use Carp;
+use strict;
+use warnings;
+
+sub new {
+       my $junk = shift;
+       my $options = shift;
+       die "Pthreads is required.\n" unless $options->{pthread};
+       my $self = {
+        projects => {},
+        options  => $options,
+        numver   => '',
+        strver   => '',
+    };
+       bless $self;
+       return $self;
+}
+
+# Return 1 if $oldfile is newer than $newfile, or if $newfile doesn't exist.
+# Special case - if config.pl has changed, always return 1
+sub IsNewer {
+       my ($newfile, $oldfile) = @_;
+       if ($oldfile ne 'vcbuild\config.pl') {
+               return 1 if IsNewer($newfile, 'vcbuild\config.pl');
+       }
+       return 1 if (!(-e $newfile));
+       my @nstat = stat($newfile);
+       my @ostat = stat($oldfile);
+       return 1 if ($nstat[9] < $ostat[9]);
+       return 0;
+}
+
+# Copy a file, *not* preserving date. Only works for text files.
+sub copyFile {
+       my ($src, $dest) = @_;
+       open(I,$src) || croak "Could not open $src";
+       open(O,">$dest") || croak "Could not open $dest";
+       while (<I>) {
+               print O;
+       }
+       close(I);
+       close(O);
+}
+
+sub GenerateFiles {
+       my $self = shift;
+
+# Parse configure.in to get version numbers
+       open(C,"configure.in") || confess("Could not open configure.in for reading\n");
+       while (<C>) {
+               if (/^AC_INIT\(\[PostgreSQL\], \[([^\]]+)\]/) {
+                       $self->{strver} = $1;
+                       if ($self->{strver} !~ /^(\d+)\.(\d+)(?:\.(\d+))?/) {
+                               confess "Bad format of version: $self->{strver}\n"
+                       }
+                       $self->{numver} = sprintf("%d%02d%02d", $1, $2, $3?$3:0);
+               }
+       }
+       close(C);
+       confess "Unable to parse configure.in for all variables!"
+               if ($self->{strver} eq '' || $self->{numver} eq '');
+
+       if (IsNewer("src\\include\\pg_config_os.h","src\\include\\port\\win32.h")) {
+               print "Copying pg_config_os.h...\n";
+               copyFile("src\\include\\port\\win32.h","src\\include\\pg_config_os.h");
+       }
+       
+       if (IsNewer("src\\include\\pg_config.h","src\\include\\pg_config.h.win32")) {
+               print "Generating pg_config.h...\n";
+               open(I,"src\\include\\pg_config.h.win32") || confess "Could not open pg_config.h.win32\n";
+               open(O,">src\\include\\pg_config.h") || confess "Could not write to pg_config.h\n";
+               while (<I>) {
+                       s{PG_VERSION "[^"]+"}{PG_VERSION "$self->{strver}"};
+                       s{PG_VERSION_NUM \d+}{PG_VERSION_NUM $self->{numver}};
+                       s{PG_VERSION_STR "[^"]+"}{__STRINGIFY(x) #x\n#define __STRINGIFY2(z) __STRINGIFY(z)\n#define PG_VERSION_STR "PostgreSQL $self->{strver}, compiled by Visual C++ build " __STRINGIFY2(_MSC_VER)};
+                       print O;
+               }
+               print O "/* defines added by config steps */\n";
+               print O "#define USE_ASSERT_CHECKING 1\n" if ($self->{options}->{asserts});
+               print O "#define USE_LDAP 1\n" if ($self->{options}->{ldap});
+               print O "#define HAVE_LIBZ 1\n" if ($self->{options}->{zlib});
+               print O "#define USE_SSL 1\n" if ($self->{options}->{openssl});
+               print O "#define ENABLE_NLS 1\n" if ($self->{options}->{nls});
+               print O "#define LOCALEDIR \"/usr/local/pgsql/share/locale\"\n" if ($self->{options}->{nls});
+               if ($self->{options}->{nls}) {
+                       print O "#define KRB5 1\n";
+                       print O "#define HAVE_KRB5_ERROR_TEXT_DATA 1\n";
+                       print O "#define HAVE_KRB5_TICKET_ENC_PART2 1\n";
+                       print O "#define PG_KRB_SRVNAM \"postgres\"\n";
+               }
+               close(O);
+               close(I);
+       }
+
+       if (IsNewer("src\\interfaces\\libpq\\libpqdll.def","src\\interfaces\\libpq\\exports.txt")) {
+               print "Generating libpqdll.def...\n";
+               open(I,"src\\interfaces\\libpq\\exports.txt") || confess("Could not open exports.txt\n");
+               open(O,">src\\interfaces\\libpq\\libpqdll.def") || confess("Could not open libpqdll.def\n");
+               print O "LIBRARY LIBPQ\nEXPORTS\n";
+               while (<I>) {
+                       next if (/^#/);
+                       my ($f, $o) = split;
+                       print O " $f @ $o\n";
+               }
+               close(O);
+               close(I);
+       }
+
+       if (IsNewer("src\\backend\\utils\\fmgrtab.c","src\\include\\catalog\\pg_proc.h")) {
+               print "Generating fmgrtab.c and fmgroids.h...\n";
+               open(I,"src\\include\\catalog\\pg_proc.h") || confess "Could not open pg_proc.h";
+               my @fmgr = ();
+               my %seenit;
+               while (<I>) {
+                       next unless (/^DATA/);
+                       s/^.*OID[^=]*=[^0-9]*//;
+                       s/\(//g;
+                       s/[ \t]*\).*$//;
+                       my @p = split;
+                       next if ($p[4] ne "12");
+                       push @fmgr,{
+                oid     => $p[0],
+                proname => $p[1],
+                prosrc  => $p[$#p-2],
+                nargs   => $p[10],
+                strict  => $p[7],
+                retset  => $p[8],
+            };
+               }
+               close(I);
+
+               open(H,'>', 'src\include\utils\fmgroids.h') ||
+            confess "Could not open fmgroids.h";
+               print H "/* fmgroids.h generated for Visual C++ */\n#ifndef FMGROIDS_H\n#define FMGROIDS_H\n\n";
+               open(T,">src\\backend\\utils\\fmgrtab.c") || confess "Could not open fmgrtab.c";
+               print T "/* fmgrtab.c generated for Visual C++ */\n#include \"postgres.h\"\n#include \"utils/fmgrtab.h\"\n\n";
+               foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr) {
+                       next if $seenit{$s->{prosrc}};
+                       $seenit{$s->{prosrc}} = 1;
+                       print H "#define F_" . uc $s->{prosrc} . " $s->{oid}\n"; 
+                       print T "extern Datum $s->{prosrc} (PG_FUNCTION_ARGS);\n";
+               }
+               print H "\n#endif\n /* FMGROIDS_H */\n";
+               close(H);
+               print T "const FmgrBuiltin fmgr_builtins[] = {\n";
+               my %bmap;
+           $bmap{'t'} = 'true';
+           $bmap{'f'} = 'false';
+               foreach my $s (sort {$a->{oid} <=> $b->{oid}} @fmgr) {
+                       print T "  { $s->{oid}, \"$s->{prosrc}\", $s->{nargs}, $bmap{$s->{strict}}, $bmap{$s->{retset}}, $s->{prosrc} },\n";
+               }
+
+               
+               print T " { 0, NULL, 0, false, false, NULL }\n};\n\nconst int fmgr_nbuiltins = (sizeof(fmgr_builtins) / sizeof(FmgrBuiltin)) - 1;\n";
+               close(T);
+       }
+
+       if (IsNewer('src\interfaces\libpq\libpq.rc','src\interfaces\libpq\libpq.rc.in')) {
+               print "Generating libpq.rc...\n";
+               my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+               my $d = ($year - 100) . "$yday";
+               open(I,'<', 'src\interfaces\libpq\libpq.rc.in') || confess "Could not open libpq.rc.in";
+               open(O,'>', 'src\interfaces\libpq\libpq.rc') || confess "Could not open libpq.rc";
+               while (<I>) {
+                       s/(VERSION.*),0/$1,$d/;
+                       print O;
+               }
+               close(I);
+               close(O);
+       }
+
+       if (IsNewer('src\bin\psql\sql_help.h','src\bin\psql\create_help.pl')) {
+               print "Generating sql_help.h...\n";
+               chdir('src\bin\psql');
+               system("perl create_help.pl ../../../doc/src/sgml/ref sql_help.h");
+               chdir('..\..\..');
+       }
+
+       unless (-f "src\\port\\pg_config_paths.h") {
+               print "Generating pg_config_paths.h...\n";
+               open(O,'>', 'src\port\pg_config_paths.h') || confess "Could not open pg_config_paths.h";
+               print O  <<EOF;
+#define PGBINDIR "/usr/local/pgsql/bin"
+#define PGSHAREDIR "/usr/local/pgsql/share"
+#define SYSCONFDIR "/usr/local/pgsql/etc"
+#define INCLUDEDIR "/usr/local/pgsql/include"
+#define PKGINCLUDEDIR "/usr/local/pgsql/include"
+#define INCLUDEDIRSERVER "/usr/local/pgsql/include/server"
+#define LIBDIR "/usr/local/pgsql/lib"
+#define PKGLIBDIR "/usr/local/pgsql/lib"
+#define LOCALEDIR "/usr/local/pgsql/share/locale"
+#define DOCDIR "/usr/local/pgsql/doc"
+#define MANDIR "/usr/local/pgsql/man"
+EOF
+               close(O);
+       }
+}
+
+sub AddProject {
+       my ($self, $name, $type, $folder, $initialdir) = @_;
+
+       my $proj = new Project($name, $type, $self);
+       push @{$self->{projects}->{$folder}}, $proj;
+       $proj->AddDir($initialdir) if ($initialdir);
+       if ($self->{options}->{zlib}) {
+               $proj->AddIncludeDir($self->{options}->{zlib} . '\include');
+               $proj->AddLibrary($self->{options}->{zlib} . '\lib\zdll.lib');
+       }
+       if ($self->{options}->{openssl}) {
+               $proj->AddIncludeDir($self->{options}->{openssl} . '\include');
+               $proj->AddLibrary($self->{options}->{openssl} . '\lib\VC\ssleay32.lib');
+               $proj->AddLibrary($self->{options}->{openssl} . '\lib\VC\libeay32.lib');
+       }
+       if ($self->{options}->{nls}) {
+               $proj->AddIncludeDir($self->{options}->{nls} . '\include');
+               $proj->AddLibrary($self->{options}->{nls} . '\lib\intl.lib');
+       }
+       if ($self->{options}->{krb5}) {
+               $proj->AddIncludeDir($self->{options}->{krb5} . '\inc\krb5');
+               $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\krb5_32.lib');
+               $proj->AddLibrary($self->{options}->{krb5} . '\lib\i386\comerr32.lib');
+       }
+       return $proj;
+}
+
+sub Save {
+       my ($self) = @_;
+       my %flduid;
+
+       $self->GenerateFiles();
+       foreach my $fld (keys %{$self->{projects}}) {
+               foreach my $proj (@{$self->{projects}->{$fld}}) {
+                       $proj->Save();
+               }
+       }
+
+       open(SLN,">pgsql.sln") || croak "Could not write to pgsql.sln\n";
+       print SLN <<EOF;
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+EOF
+
+       foreach my $fld (keys %{$self->{projects}}) {
+               foreach my $proj (@{$self->{projects}->{$fld}}) {
+                       print SLN <<EOF;
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "$proj->{name}", "$proj->{name}.vcproj", "$proj->{guid}"
+EndProject
+EOF
+               }
+               if ($fld ne "") {
+                       $flduid{$fld} = Win32::GuidGen();
+                       print SLN <<EOF;
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "$fld", "$fld", "$flduid{$fld}"
+EndProject
+EOF
+               }
+       }
+
+       print SLN <<EOF;
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Win32 = Debug|Win32
+               Release|Win32 = Release|Win32
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+EOF
+
+       foreach my $fld (keys %{$self->{projects}}) {
+               foreach my $proj (@{$self->{projects}->{$fld}}) {
+               print SLN <<EOF;
+               $proj->{guid}.Debug|Win32.ActiveCfg = Debug|Win32
+               $proj->{guid}.Debug|Win32.Build.0  = Debug|Win32        
+               $proj->{guid}.Release|Win32.Build.0 = Release|Win32
+EOF
+               }
+       }
+
+       print SLN <<EOF;
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(NestedProjects) = preSolution
+EOF
+
+       foreach my $fld (keys %{$self->{projects}}) {
+               next if ($fld eq "");
+               foreach my $proj (@{$self->{projects}->{$fld}}) {
+                       print SLN "\t\t$proj->{guid} = $flduid{$fld}\n";
+               }
+       }
+
+       print SLN <<EOF;
+       EndGlobalSection
+EndGlobal
+EOF
+       close(SLN);
+}
+
+1;
diff --git a/src/tools/msvc/build.bat b/src/tools/msvc/build.bat
new file mode 100755 (executable)
index 0000000..024819f
--- /dev/null
@@ -0,0 +1,12 @@
+@echo off\r
+SET STARTDIR=%CD%\r
+\r
+perl mkvcbuild.pl\r
+if errorlevel 1 goto :eof\r
+\r
+if exist ..\vcbuild if exist ..\src cd ..\r
+\r
+if "%1" == "" msbuild pgsql.sln\r
+if not "%1" == "" vcbuild %1.vcproj\r
+\r
+cd %STARTDIR%\r
diff --git a/src/tools/msvc/config.pl b/src/tools/msvc/config.pl
new file mode 100644 (file)
index 0000000..0165819
--- /dev/null
@@ -0,0 +1,18 @@
+# Configuration arguments for vcbuild.\r
+use strict;\r
+use warnings;\r
+\r
+our $config = {\r
+       asserts=>1,                     # --enable-cassert\r
+       nls=>undef,                             # --enable-nls=<path>\r
+       tcl=>'c:\tcl',          # --with-tls=<path>\r
+       perl=>1,                        # --with-perl\r
+       python=>'c:\python24', # --with-python=<path>\r
+       krb5=>'c:\prog\pgsql\depend\krb5', # --with-krb5=<path>\r
+       ldap=>1,                        # --with-ldap\r
+       openssl=>'c:\openssl', # --with-ssl=<path>\r
+       pthread=>'c:\prog\pgsql\depend\pthread', # foo baz?\r
+       zlib=>'c:\prog\pgsql\depend\zlib'# --with-zlib=<path>\r
+};\r
+\r
+1;\r
diff --git a/src/tools/msvc/gendef.pl b/src/tools/msvc/gendef.pl
new file mode 100644 (file)
index 0000000..fd97497
--- /dev/null
@@ -0,0 +1,50 @@
+my @def;\r
+\r
+die "Usage: gendef.pl <modulepath>\n" unless ($ARGV[0] =~ /\\([^\\]+$)/);\r
+my $defname = uc $1;\r
+\r
+if (-f "$ARGV[0]/$defname.def") {\r
+       print "Not re-generating $defname.DEF, file already exists.\n";\r
+       exit(0);\r
+}\r
+\r
+print "Generating $defname.DEF from directory $ARGV[0]\n";\r
+\r
+while (<$ARGV[0]/*>) {\r
+    print ".";\r
+       open(F,"dumpbin /symbols $_|") || die "Could not open $_\n";\r
+       while (<F>) {\r
+               s/\(\)//g;\r
+               next unless /^\d/;\r
+               my @pieces = split ;\r
+               next unless $pieces[6];\r
+               next if ($pieces[2] eq "UNDEF");\r
+               next unless ($pieces[4] eq "External");\r
+               next if $pieces[6] =~ /^@/;\r
+               next if $pieces[6] =~ /^\(/;\r
+               next if $pieces[6] =~ /^__real/;\r
+               next if $pieces[6] =~ /^__imp/;\r
+               next if $pieces[6] =~ /NULL_THUNK_DATA$/;\r
+               next if $pieces[6] =~ /^__IMPORT_DESCRIPTOR/;\r
+               next if $pieces[6] =~ /^__NULL_IMPORT/;\r
+\r
+               push @def, $pieces[6];\r
+       }\r
+       close(F);\r
+}\r
+print "\n";\r
+\r
+open(DEF,">$ARGV[0]/$defname.def") || die "Could not write to $defname\n";\r
+print DEF "EXPORTS\n";\r
+my $i = 0;\r
+my $last = "";\r
+foreach my $f (sort @def) {\r
+   next if ($f eq $last);\r
+   $last = $f;\r
+   $f =~ s/^_//;\r
+   $i++;\r
+#   print DEF "  $f \@ $i\n";  # ordinaled exports?\r
+   print DEF "  $f\n";\r
+}\r
+close(DEF);\r
+print "Generated $i symbols\n";\r
diff --git a/src/tools/msvc/mkvcbuild.pl b/src/tools/msvc/mkvcbuild.pl
new file mode 100644 (file)
index 0000000..3eac344
--- /dev/null
@@ -0,0 +1,235 @@
+use Carp;
+use Win32;
+use strict;
+use warnings;
+use Project;
+use Solution;
+
+chdir('..') if (-d '..\vcbuild' && -d '..\src');
+die 'Must run from root directory or vcbuild directory' unless (-d 'vcbuild' && -d 'src');
+die 'Could not find config.pl' unless (-f 'vcbuild/config.pl');
+
+our $config;
+require 'vcbuild/config.pl';
+
+my $solution = new Solution($config);
+
+our @pgportfiles = qw(
+   crypt.c fseeko.c getrusage.c inet_aton.c random.c srandom.c
+   unsetenv.c getaddrinfo.c gettimeofday.c kill.c open.c rand.c
+   snprintf.c copydir.c dirmod.c exec.c noblock.c path.c pipe.c
+   pgsleep.c pgstrcasecmp.c sprompt.c thread.c getopt.c getopt_long.c
+   dirent.c rint.c win32error.c);
+
+my $libpgport = $solution->AddProject('libpgport','lib','misc');
+$libpgport->AddDefine('FRONTEND');
+$libpgport->AddFiles('src\port',@pgportfiles);
+
+my $postgres = $solution->AddProject('postgres','exe','','src\backend');
+$postgres->AddIncludeDir('src\backend');
+$postgres->AddDir('src\backend\port\win32');
+$postgres->AddFile('src\backend\utils\fmgrtab.c');
+$postgres->ReplaceFile('src\backend\port\dynloader.c','src\backend\port\dynloader\win32.c');
+$postgres->ReplaceFile('src\backend\port\pg_sema.c','src\backend\port\win32_sema.c');
+$postgres->ReplaceFile('src\backend\port\pg_shmem.c','src\backend\port\sysv_shmem.c');
+$postgres->AddFiles('src\port',@pgportfiles);
+$postgres->AddDir('src\timezone');
+$postgres->AddFiles('src\backend\parser','scan.l','gram.y');
+$postgres->AddFiles('src\backend\bootstrap','bootscanner.l','bootparse.y');
+$postgres->AddFiles('src\backend\utils\misc','guc-file.l');
+$postgres->AddDefine('BUILDING_DLL');
+$postgres->AddLibrary('wsock32.lib ws2_32.lib');
+$postgres->AddLibrary('wldap32.lib') if ($solution->{options}->{ldap});
+$postgres->FullExportDLL('postgres.lib');
+
+my $plpgsql = $solution->AddProject('plpgsql','dll','PLs','src\pl\plpgsql\src');
+$plpgsql->AddFiles('src\pl\plpgsql\src','scan.l','gram.y');
+$plpgsql->AddReference($postgres);
+
+if ($solution->{options}->{perl}) {
+# Already running in perl, so use the version that we already have information for.
+       use Config;
+       my $plperl = $solution->AddProject('plperl','dll','PLs','src\pl\plperl');
+       $plperl->AddIncludeDir($Config{archlibexp} . '\CORE');
+       $plperl->AddDefine('PLPERL_HAVE_UID_GID');
+       if (Solution::IsNewer('src\pl\plperl\SPI.c','src\pl\plperl\SPI.xs')) {
+               print 'Building src\pl\plperl\SPI.c...' . "\n";
+               system('perl ' . $Config{privlibexp} . '/ExtUtils/xsubpp -typemap ' . $Config{privlibexp} . '/ExtUtils/typemap src\pl\plperl\SPI.xs >src\pl\plperl\SPI.c');
+               die 'Failed to create SPI.c' . "\n" if ((!(-f 'src\pl\plperl\SPI.c')) || -z 'src\pl\plperl\SPI.c');
+       }
+       $plperl->AddReference($postgres);
+       $plperl->AddLibrary($Config{archlibexp} . '\CORE\perl58.lib');
+}
+
+if ($solution->{options}->{python}) {
+       my $plpython = $solution->AddProject('plpython','dll','PLs','src\pl\plpython');
+       $plpython->AddIncludeDir($solution->{options}->{python} . '\include');
+       $plpython->AddLibrary($solution->{options}->{python} . '\Libs\python24.lib');
+       $plpython->AddReference($postgres);
+}
+
+if ($solution->{options}->{tcl}) {
+       my $pltcl = $solution->AddProject('pltcl','dll','PLs','src\pl\tcl');
+       $pltcl->AddIncludeDir($solution->{options}->{tcl} . '\include');
+       $pltcl->AddReference($postgres);
+       $pltcl->AddLibrary($solution->{options}->{tcl} . '\lib\tcl84.lib');
+}
+
+my $libpq = $solution->AddProject('libpq','dll','interfaces','src\interfaces\libpq');
+$libpq->AddDefine('FRONTEND');
+$libpq->AddIncludeDir('src\port');
+$libpq->AddLibrary('wsock32.lib');
+$libpq->UseDef('src\interfaces\libpq\libpqdll.def');
+$libpq->ReplaceFile('src\interfaces\libpq\libpqrc.c','src\interfaces\libpq\libpq.rc');
+
+my $pgtypes = $solution->AddProject('libpgtypes','dll','interfaces','src\interfaces\ecpg\pgtypeslib');
+$pgtypes->AddDefine('FRONTEND');
+$pgtypes->AddReference($postgres,$libpgport);
+$pgtypes->AddIncludeDir('src\interfaces\ecpg\include');
+
+my $libecpg = $solution->AddProject('libecpg','dll','interfaces','src\interfaces\ecpg\ecpglib');
+$libecpg->AddDefine('FRONTEND');
+$libecpg->AddIncludeDir('src\interfaces\ecpg\include');
+$libecpg->AddIncludeDir('src\interfaces\libpq');
+$libecpg->AddIncludeDir('src\port');
+$libecpg->AddLibrary('wsock32.lib');
+$libecpg->AddLibrary($config->{'pthread'} . '\pthreadVC2.lib');
+$libecpg->AddReference($libpq,$pgtypes);
+
+my $libecpgcompat = $solution->AddProject('libecpg_compat','dll','interfaces','src\interfaces\ecpg\compatlib');
+$libecpgcompat->AddIncludeDir('src\interfaces\ecpg\include');
+$libecpgcompat->AddIncludeDir('src\interfaces\libpq');
+$libecpgcompat->AddReference($pgtypes,$libecpg);
+
+my $ecpg = $solution->AddProject('ecpg','exe','interfaces','src\interfaces\ecpg\preproc');
+$ecpg->AddIncludeDir('src\interfaces\ecpg\include');
+$ecpg->AddIncludeDir('src\interfaces\libpq');
+$ecpg->AddFiles('src\interfaces\ecpg\preproc','pgc.l','preproc.y');
+$ecpg->AddDefine('MAJOR_VERSION=4');
+$ecpg->AddDefine('MINOR_VERSION=2');
+$ecpg->AddDefine('PATCHLEVEL=1');
+$ecpg->AddReference($libpgport);
+
+
+# src/bin
+my $initdb = AddSimpleFrontend('initdb', 1);
+
+my $pgconfig = AddSimpleFrontend('pg_config');
+
+my $pgcontrol = AddSimpleFrontend('pg_controldata');
+
+my $pgctl = AddSimpleFrontend('pg_ctl', 1);
+
+my $pgreset = AddSimpleFrontend('pg_resetxlog');
+
+my $psql = AddSimpleFrontend('psql', 1);
+$psql->AddIncludeDir('src\bin\pg_dump');
+$psql->AddFile('src\bin\psql\psqlscan.l');
+
+my $pgdump = AddSimpleFrontend('pg_dump', 1);
+$pgdump->AddFile('src\bin\pg_dump\pg_dump.c');
+$pgdump->AddFile('src\bin\pg_dump\common.c');
+$pgdump->AddFile('src\bin\pg_dump\pg_dump_sort.c');
+
+my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
+$pgdumpall->{name} = 'pg_dumpall';
+$pgdumpall->AddFile('src\bin\pg_dump\pg_dumpall.c');
+
+my $pgrestore = AddSimpleFrontend('pg_dump', 1);
+$pgrestore->{name} = 'pg_restore';
+$pgrestore->AddFile('src\bin\pg_dump\pg_restore.c');
+
+open(MF,'src\backend\utils\mb\conversion_procs\Makefile') || die 'Could not open src\backend\utils\mb\conversion_procs\Makefile';
+my $t = $/;undef $/;
+my $mf = <MF>;
+close(MF);
+$mf =~ s{\\s*[\r\n]+}{}mg;
+$mf =~ m{DIRS\s*=\s*(.*)$}m || die 'Could not match in conversion makefile' . "\n";
+foreach my $sub (split /\s+/,$1) {
+       open(MF,'src\backend\utils\mb\conversion_procs\\' . $sub . '\Makefile') || die 'Could not open Makefile for $sub';
+       $mf = <MF>;
+       close(MF);
+       my $p = $solution->AddProject($sub, 'dll', 'conversion procs');
+       $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $sub . '.c');
+       if ($mf =~ m{^SRCS\s*\+=\s*(.*)$}m) {
+               $p->AddFile('src\backend\utils\mb\conversion_procs\\' . $sub . '\\' . $1);
+       }
+       $p->AddReference($postgres);
+}
+
+open(MF,'src\bin\scripts\Makefile') || die 'Could not open src\bin\scripts\Makefile';
+$mf = <MF>;
+close(MF);
+$mf =~ s{\\s*[\r\n]+}{}mg;
+$mf =~ m{PROGRAMS\s*=\s*(.*)$}m || die 'Could not match in bin\scripts\Makefile' . "\n";
+foreach my $prg (split /\s+/,$1) {
+       my $proj = $solution->AddProject($prg,'exe','bin');
+       $mf =~ m{$prg\s*:\s*(.*)$}m || die 'Could not find script define for $prg' . "\n";
+       my @files = split /\s+/,$1;
+       foreach my $f (@files) {
+               if ($f =~ /\/keywords\.o$/) {
+                       $proj->AddFile('src\backend\parser\keywords.c');
+               }
+               else {
+                       $f =~ s/\.o$/\.c/;
+                       if ($f eq 'dumputils.c') {
+                               $proj->AddFile('src\bin\pg_dump\dumputils.c');
+                       }
+                       elsif ($f =~ /print\.c$/) { # Also catches mbprint.c
+                               $proj->AddFile('src\bin\psql\\' . $f);
+                       }
+                       else {
+                               $proj->AddFile('src\bin\scripts\\' . $f);
+                       }
+               }
+       }
+       $proj->AddIncludeDir('src\interfaces\libpq');
+       $proj->AddIncludeDir('src\bin\pg_dump');
+       $proj->AddIncludeDir('src\bin\psql');
+       $proj->AddReference($libpq,$libpgport);
+       $proj->AddResourceFile('src\bin\scripts','PostgreSQL Utility');
+       $proj->AddLibrary('debug\libpgport\libpgport.lib');
+       $proj->AddLibrary('debug\libpq\libpq.lib');
+}
+$/ = $t;
+
+
+# Regression DLLs
+my $regress = $solution->AddProject('regress','dll','misc');
+$regress->AddFile('src\test\regress\regress.c');
+$regress->AddReference($postgres);
+
+my $refint = $solution->AddProject('refint','dll','contrib');
+$refint->AddFile('contrib\spi\refint.c');
+$refint->AddReference($postgres);
+$refint->AddDefine('REFINT_VERBOSE');
+
+my $autoinc = $solution->AddProject('autoinc','dll','contrib');
+$autoinc ->AddFile('contrib\spi\autoinc.c');
+$autoinc->AddReference($postgres);
+
+
+$solution->Save();
+
+#####################
+# Utility functions #
+#####################
+
+# Add a simple frontend project (exe)
+sub AddSimpleFrontend { 
+       my $n = shift;
+       my $uselibpq= shift;
+
+       my $p = $solution->AddProject($n,'exe','bin');
+       $p->AddDir('src\bin\\' . $n);
+       $p->AddDefine('FRONTEND');
+       $p->AddReference($libpgport);
+       $p->AddLibrary('debug\libpgport\libpgport.lib');
+       if ($uselibpq) {
+               $p->AddIncludeDir('src\interfaces\libpq');
+               $p->AddReference($libpq);
+               $p->AddLibrary('debug\libpq\libpq.lib');
+       }
+       return $p;
+}
+
diff --git a/src/tools/msvc/pgbison.bat b/src/tools/msvc/pgbison.bat
new file mode 100755 (executable)
index 0000000..8e6bfc8
--- /dev/null
@@ -0,0 +1,27 @@
+@echo off\r
+bison -V > NUL\r
+if errorlevel 1 goto nobison\r
+\r
+if "%1" == "src\backend\parser\gram.y" call :generate %1 src\backend\parser\gram.c src\include\parser\parse.h\r
+if "%1" == "src\backend\bootstrap\bootparse.y" call :generate %1 src\backend\bootstrap\bootparse.c src\backend\bootstrap\bootstrap_tokens.h\r
+if "%1" == "src\pl\plpgsql\src\gram.y" call :generate %1 src\pl\plpgsql\src\pl_gram.c src\pl\plpgsql\src\pl.tab.h\r
+if "%1" == "src\interfaces\ecpg\preproc\preproc.y" call :generate %1 src\interfaces\ecpg\preproc\preproc.c src\interfaces\ecpg\preproc\preproc.h\r
+\r
+echo Unknown bison input: %1\r
+exit 1\r
+\r
+:generate\r
+SET fn=%1\r
+bison -d %fn%\r
+if errorlevel 1 exit 1\r
+copy /y %fn:~0,-2%.tab.c %2\r
+if errorlevel 1 exit 1\r
+copy /y %fn:~0,-2%.tab.h %3\r
+if errorlevel 1 exit 1\r
+del %fn:~0,-2%.tab.*\r
+exit 0\r
+\r
+\r
+:nobison\r
+echo WARNING! Bison install not found, attempting to build without!\r
+exit 0\r
diff --git a/src/tools/msvc/pgflex.bat b/src/tools/msvc/pgflex.bat
new file mode 100755 (executable)
index 0000000..90479b6
--- /dev/null
@@ -0,0 +1,21 @@
+@echo off\r
+flex -V > NUL\r
+if errorlevel 1 goto noflex\r
+\r
+if "%1" == "src\backend\parser\scan.l" call :generate %1 src\backend\parser\scan.c -CF\r
+if "%1" == "src\backend\bootstrap\bootscanner.l" call :generate %1 src\backend\bootstrap\bootscanner.c\r
+if "%1" == "src\backend\utils\misc\guc-file.l" call :generate %1 src\backend\utils\misc\guc-file.c\r
+if "%1" == "src\pl\plpgsql\src\scan.l" call :generate %1 src\pl\plpgsql\src\pl_scan.c\r
+if "%1" == "src\interfaces\ecpg\preproc\pgc.l" call :generate %1 src\interfaces\ecpg\preproc\pgc.c\r
+if "%1" == "src\bin\psql\psqlscan.l" call :generate %1 src\bin\psql\psqlscan.c\r
+\r
+echo Unknown flex input: %1\r
+exit 1\r
+\r
+:generate\r
+flex %3 -o%2 %1\r
+exit %errorlevel%\r
+\r
+:noflex\r
+echo WARNING! flex install not found, attempting to build without\r
+exit 0\r