Hi,

At the moment we do very basic parsing of makefiles to build the
visual studio project file in order to build our contrib modules on
MSVC.  This parsing is quite basic and still requires a number of
special cases to get enough information into the project file in order
for the build to succeed.  It might be nice if we could reduce some of
those special cases so that:

a) We reduce the amount of work specific to windows when we add new
contrib modules, and;
b) We can work towards a better way for people to build their own
extensions on windows.

I admit to not being much of an expert in either perl or make, but I
came up with the attached which does allow a good number of the
special cases to be removed.

I'm keen to get some feedback on this idea.

Patch attached.

David
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 90594bd41b..491a465e2f 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -32,16 +32,13 @@ my $libpq;
 my @unlink_on_exit;
 
 # Set of variables for modules in contrib/ and src/test/modules/
-my $contrib_defines = { 'refint' => 'REFINT_VERBOSE' };
-my @contrib_uselibpq = ('dblink', 'oid2name', 'postgres_fdw', 'vacuumlo');
-my @contrib_uselibpgport   = ('oid2name', 'pg_standby', 'vacuumlo');
-my @contrib_uselibpgcommon = ('oid2name', 'pg_standby', 'vacuumlo');
+my $contrib_defines = undef;
+my @contrib_uselibpq = undef;
+my @contrib_uselibpgport   = ('pg_standby');
+my @contrib_uselibpgcommon = ('pg_standby');
 my $contrib_extralibs      = undef;
 my $contrib_extraincludes = { 'dblink' => ['src/backend'] };
-my $contrib_extrasource = {
-       'cube' => [ 'contrib/cube/cubescan.l', 'contrib/cube/cubeparse.y' ],
-       'seg'  => [ 'contrib/seg/segscan.l',   'contrib/seg/segparse.y' ],
-};
+my $contrib_extrasource = undef;
 my @contrib_excludes = (
        'bool_plperl',      'commit_ts',
        'hstore_plperl',    'hstore_plpython',
@@ -163,7 +160,7 @@ sub mkvcbuild
        $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->AddFile('src/backend/utils/fmgrtab.c', 1);
        $postgres->ReplaceFile('src/backend/port/pg_sema.c',
                'src/backend/port/win32_sema.c');
        $postgres->ReplaceFile('src/backend/port/pg_shmem.c',
@@ -316,8 +313,8 @@ sub mkvcbuild
 
        my $pgregress_ecpg =
          $solution->AddProject('pg_regress_ecpg', 'exe', 'misc');
-       $pgregress_ecpg->AddFile('src/interfaces/ecpg/test/pg_regress_ecpg.c');
-       $pgregress_ecpg->AddFile('src/test/regress/pg_regress.c');
+       $pgregress_ecpg->AddFile('src/interfaces/ecpg/test/pg_regress_ecpg.c', 
1);
+       $pgregress_ecpg->AddFile('src/test/regress/pg_regress.c', 1);
        $pgregress_ecpg->AddIncludeDir('src/port');
        $pgregress_ecpg->AddIncludeDir('src/test/regress');
        $pgregress_ecpg->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
@@ -327,10 +324,10 @@ sub mkvcbuild
 
        my $isolation_tester =
          $solution->AddProject('isolationtester', 'exe', 'misc');
-       $isolation_tester->AddFile('src/test/isolation/isolationtester.c');
-       $isolation_tester->AddFile('src/test/isolation/specparse.y');
-       $isolation_tester->AddFile('src/test/isolation/specscanner.l');
-       $isolation_tester->AddFile('src/test/isolation/specparse.c');
+       $isolation_tester->AddFile('src/test/isolation/isolationtester.c', 1);
+       $isolation_tester->AddFile('src/test/isolation/specparse.y', 1);
+       $isolation_tester->AddFile('src/test/isolation/specscanner.l', 1);
+       $isolation_tester->AddFile('src/test/isolation/specparse.c', 1);
        $isolation_tester->AddIncludeDir('src/test/isolation');
        $isolation_tester->AddIncludeDir('src/port');
        $isolation_tester->AddIncludeDir('src/test/regress');
@@ -342,8 +339,8 @@ sub mkvcbuild
 
        my $pgregress_isolation =
          $solution->AddProject('pg_isolation_regress', 'exe', 'misc');
-       $pgregress_isolation->AddFile('src/test/isolation/isolation_main.c');
-       $pgregress_isolation->AddFile('src/test/regress/pg_regress.c');
+       $pgregress_isolation->AddFile('src/test/isolation/isolation_main.c', 1);
+       $pgregress_isolation->AddFile('src/test/regress/pg_regress.c', 1);
        $pgregress_isolation->AddIncludeDir('src/port');
        $pgregress_isolation->AddIncludeDir('src/test/regress');
        $pgregress_isolation->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
@@ -363,22 +360,22 @@ sub mkvcbuild
        }
 
        my $pgbasebackup = AddSimpleFrontend('pg_basebackup', 1);
-       $pgbasebackup->AddFile('src/bin/pg_basebackup/pg_basebackup.c');
+       $pgbasebackup->AddFile('src/bin/pg_basebackup/pg_basebackup.c', 1);
        $pgbasebackup->AddLibrary('ws2_32.lib');
 
        my $pgreceivewal = AddSimpleFrontend('pg_basebackup', 1);
        $pgreceivewal->{name} = 'pg_receivewal';
-       $pgreceivewal->AddFile('src/bin/pg_basebackup/pg_receivewal.c');
+       $pgreceivewal->AddFile('src/bin/pg_basebackup/pg_receivewal.c', 1);
        $pgreceivewal->AddLibrary('ws2_32.lib');
 
        my $pgrecvlogical = AddSimpleFrontend('pg_basebackup', 1);
        $pgrecvlogical->{name} = 'pg_recvlogical';
-       $pgrecvlogical->AddFile('src/bin/pg_basebackup/pg_recvlogical.c');
+       $pgrecvlogical->AddFile('src/bin/pg_basebackup/pg_recvlogical.c', 1);
        $pgrecvlogical->AddLibrary('ws2_32.lib');
 
        my $pgrewind = AddSimpleFrontend('pg_rewind', 1);
        $pgrewind->{name} = 'pg_rewind';
-       $pgrewind->AddFile('src/backend/access/transam/xlogreader.c');
+       $pgrewind->AddFile('src/backend/access/transam/xlogreader.c', 1);
        $pgrewind->AddLibrary('ws2_32.lib');
        $pgrewind->AddDefine('FRONTEND');
 
@@ -392,9 +389,9 @@ sub mkvcbuild
 
        my $pgdump = AddSimpleFrontend('pg_dump', 1);
        $pgdump->AddIncludeDir('src/backend');
-       $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');
+       $pgdump->AddFile('src/bin/pg_dump/pg_dump.c', 1);
+       $pgdump->AddFile('src/bin/pg_dump/common.c', 1);
+       $pgdump->AddFile('src/bin/pg_dump/pg_dump_sort.c', 1);
        $pgdump->AddLibrary('ws2_32.lib');
 
        my $pgdumpall = AddSimpleFrontend('pg_dump', 1);
@@ -408,14 +405,14 @@ sub mkvcbuild
        delete @{ $pgdumpall->{files} }{@nodumpall};
        $pgdumpall->{name} = 'pg_dumpall';
        $pgdumpall->AddIncludeDir('src/backend');
-       $pgdumpall->AddFile('src/bin/pg_dump/pg_dumpall.c');
-       $pgdumpall->AddFile('src/bin/pg_dump/dumputils.c');
+       $pgdumpall->AddFile('src/bin/pg_dump/pg_dumpall.c', 1);
+       $pgdumpall->AddFile('src/bin/pg_dump/dumputils.c', 1);
        $pgdumpall->AddLibrary('ws2_32.lib');
 
        my $pgrestore = AddSimpleFrontend('pg_dump', 1);
        $pgrestore->{name} = 'pg_restore';
        $pgrestore->AddIncludeDir('src/backend');
-       $pgrestore->AddFile('src/bin/pg_dump/pg_restore.c');
+       $pgrestore->AddFile('src/bin/pg_dump/pg_restore.c', 1);
        $pgrestore->AddLibrary('ws2_32.lib');
 
        my $zic = $solution->AddProject('zic', 'exe', 'utils');
@@ -795,7 +792,7 @@ sub mkvcbuild
        {
                my $dir = 'src/backend/utils/mb/conversion_procs/' . $sub;
                my $p = $solution->AddProject($sub, 'dll', 'conversion procs', 
$dir);
-               $p->AddFile("$dir/$sub.c");    # implicit source file
+               $p->AddFile("$dir/$sub.c", 1);    # implicit source file
                $p->AddReference($postgres);
        }
 
@@ -814,7 +811,7 @@ sub mkvcbuild
                        $f =~ s/\.o$/\.c/;
                        if ($f =~ /\.c$/)
                        {
-                               $proj->AddFile('src/bin/scripts/' . $f);
+                               $proj->AddFile('src/bin/scripts/' . $f, 1);
                        }
                }
                $proj->AddIncludeDir('src/interfaces/libpq');
@@ -825,13 +822,13 @@ sub mkvcbuild
 
        # Regression DLL and EXE
        my $regress = $solution->AddProject('regress', 'dll', 'misc');
-       $regress->AddFile('src/test/regress/regress.c');
+       $regress->AddFile('src/test/regress/regress.c', 1);
        $regress->AddDirResourceFile('src/test/regress');
        $regress->AddReference($postgres);
 
        my $pgregress = $solution->AddProject('pg_regress', 'exe', 'misc');
-       $pgregress->AddFile('src/test/regress/pg_regress.c');
-       $pgregress->AddFile('src/test/regress/pg_regress_main.c');
+       $pgregress->AddFile('src/test/regress/pg_regress.c', 1);
+       $pgregress->AddFile('src/test/regress/pg_regress_main.c', 1);
        $pgregress->AddIncludeDir('src/port');
        $pgregress->AddDefine('HOST_TUPLE="i686-pc-win32vc"');
        $pgregress->AddLibrary('ws2_32.lib');
@@ -844,9 +841,9 @@ sub mkvcbuild
        $pg_waldump->AddDefine('FRONTEND');
        foreach my $xf (glob('src/backend/access/rmgrdesc/*desc.c'))
        {
-               $pg_waldump->AddFile($xf);
+               $pg_waldump->AddFile($xf, 1);
        }
-       $pg_waldump->AddFile('src/backend/access/transam/xlogreader.c');
+       $pg_waldump->AddFile('src/backend/access/transam/xlogreader.c', 1);
 
        $solution->Save();
        return $solution->{vcver};
@@ -917,7 +914,7 @@ sub AddTransformModule
        my $p = $solution->AddProject($n, 'dll', 'contrib', $n_src);
        for my $file (glob("$n_src/*.c"))
        {
-               $p->AddFile($file);
+               $p->AddFile($file, 1);
        }
        $p->AddReference($postgres);
 
@@ -951,6 +948,7 @@ sub AddContrib
        my $subdir = shift;
        my $n      = shift;
        my $mf     = Project::read_file("$subdir/$n/Makefile");
+       my @projects;
 
        if ($mf =~ /^MODULE_big\s*=\s*(.*)$/mg)
        {
@@ -958,6 +956,7 @@ sub AddContrib
                my $proj = $solution->AddProject($dn, 'dll', 'contrib', 
"$subdir/$n");
                $proj->AddReference($postgres);
                AdjustContribProj($proj);
+               push @projects, $proj;
        }
        elsif ($mf =~ /^MODULES\s*=\s*(.*)$/mg)
        {
@@ -966,21 +965,95 @@ sub AddContrib
                        my $proj =
                          $solution->AddProject($mod, 'dll', 'contrib', 
"$subdir/$n");
                        my $filename = $mod . '.c';
-                       $proj->AddFile("$subdir/$n/$filename");
+                       $proj->AddFile("$subdir/$n/$filename", 1);
                        $proj->AddReference($postgres);
                        AdjustContribProj($proj);
+                       push @projects, $proj;
                }
        }
        elsif ($mf =~ /^PROGRAM\s*=\s*(.*)$/mg)
        {
                my $proj = $solution->AddProject($1, 'exe', 'contrib', 
"$subdir/$n");
                AdjustContribProj($proj);
+               push @projects, $proj;
        }
        else
        {
                croak "Could not determine contrib module type for $n\n";
        }
 
+       # Process custom compiler flags
+       if ($mf =~ /^PG_CPPFLAGS\s*=\s*(.*)$/mg)
+       {
+               foreach my $flag (split /\s+/, $1)
+               {
+                       if ($flag =~ /^-D(.*)$/)
+                       {
+                               foreach my $proj (@projects)
+                               {
+                                       $proj->AddDefine($1);
+                               }
+                       }
+                       elsif ($flag =~ /^-I(.*)$/)
+                       {
+                               foreach my $proj (@projects)
+                               {
+                                       if ($1 eq '$(libpq_srcdir)')
+                                       {
+                                               
$proj->AddIncludeDir('src\interfaces\libpq');
+                                               $proj->AddReference($libpq);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if ($mf =~ /^SHLIB_LINK_INTERNAL\s*=\s*(.*)$/mg)
+       {
+               foreach my $lib (split /\s+/, $1)
+               {
+                       if ($lib eq '$(libpq)')
+                       {
+                               foreach my $proj (@projects)
+                               {
+                                       
$proj->AddIncludeDir('src\interfaces\libpq');
+                                       $proj->AddReference($libpq);
+                               }
+                       }
+               }
+       }
+
+       if ($mf =~ /^PG_LIBS_INTERNAL\s*=\s*(.*)$/mg)
+       {
+               foreach my $lib (split /\s+/, $1)
+               {
+                       if ($lib eq '$(libpq_pgport)')
+                       {
+                               foreach my $proj (@projects)
+                               {
+                                       $proj->AddReference($libpgport);
+                                       $proj->AddReference($libpgcommon);
+                               }
+                       }
+               }
+       }
+
+       foreach my $line (split /\n/, $mf)
+       {
+               if ($line =~ /^[A-Za-z0-9_]*\.o:\s(.*)/)
+               {
+                       foreach my $file (split /\s+/, $1)
+                       {
+                               foreach my $proj (@projects)
+                               {
+                                       printf("Adding $subdir/$n/$file to 
project\n");
+                                       $proj->AddFile("$subdir/$n/$file", 0);
+                               }
+                       }
+
+               }
+       }
+
        # Are there any output data files to build?
        GenerateContribSqlFiles($n, $mf);
        return;
@@ -1106,7 +1179,7 @@ sub AdjustModule
                foreach my $i (@{ $module_extrasource->{$n} })
                {
                        print "Files $i\n";
-                       $proj->AddFile($i);
+                       $proj->AddFile($i, 1);
                }
        }
        return;
diff --git a/src/tools/msvc/Project.pm b/src/tools/msvc/Project.pm
index 20f79b382b..50e2cb529d 100644
--- a/src/tools/msvc/Project.pm
+++ b/src/tools/msvc/Project.pm
@@ -42,12 +42,16 @@ sub _new
 
 sub AddFile
 {
-       my ($self, $filename) = @_;
+       my ($self, $filename, $alwaysAddOriginal) = @_;
 
-       $self->{files}->{$filename} = 1;
+       if (AdditionalFileRules($self, $filename) != 1 || $alwaysAddOriginal == 
1)
+       {
+               $self->{files}->{$filename} = 1;
+       }
        return;
 }
 
+
 sub AddFiles
 {
        my $self = shift;
@@ -55,11 +59,40 @@ sub AddFiles
 
        while (my $f = shift)
        {
-               $self->{files}->{ $dir . "/" . $f } = 1;
+               AddFile($self, $dir . "/" . $f, 1);
        }
        return;
 }
 
+# Handle makefile rules for when file to be added to the project
+# does not exist.  Returns 1 when the original file add should be
+# skipped.
+sub AdditionalFileRules
+{
+       my $self = shift;
+       my $fname = shift;
+       my ($ext) = $fname =~ /(\.[^.]+)$/;
+
+       # For missing .c files, check if a .l file of the same name
+       # exists and add that too.
+       if ($ext eq ".c")
+       {
+               my $filenoext = $fname;
+               $filenoext =~ s{\.[^.]+$}{};
+               if (-e "$filenoext.l")
+               {
+                       AddFile($self, "$filenoext.l", 0);
+                       return 1;
+               }
+               if (-e "$filenoext.y")
+               {
+                       AddFile($self, "$filenoext.y", 0);
+                       return 0;
+               }
+       }
+       return 0;
+}
+
 sub ReplaceFile
 {
        my ($self, $filename, $newname) = @_;
@@ -74,14 +107,14 @@ sub ReplaceFile
                        if ($file eq $filename)
                        {
                                delete $self->{files}{$file};
-                               $self->{files}{$newname} = 1;
+                               AddFile($self, $newname, 1);
                                return;
                        }
                }
                elsif ($file =~ m/($re)/)
                {
                        delete $self->{files}{$file};
-                       $self->{files}{"$newname/$filename"} = 1;
+                       AddFile($self, "$newname/$filename", 1);
                        return;
                }
        }
@@ -109,7 +142,7 @@ sub RelocateFiles
                if ($r)
                {
                        $self->RemoveFile($f);
-                       $self->AddFile($targetdir . '/' . basename($f));
+                       $self->AddFile($targetdir . '/' . basename($f), 1);
                }
        }
        return;
@@ -256,11 +289,11 @@ sub AddDir
                        if ($f =~ /^\$\(top_builddir\)\/(.*)/)
                        {
                                $f = $1;
-                               $self->{files}->{$f} = 1;
+                               AddFile($self, $f, 1);
                        }
                        else
                        {
-                               $self->{files}->{"$reldir/$f"} = 1;
+                               AddFile($self, "$reldir/$f", 1);
                        }
                }
                $mf =~ s{OBJS[^=]*=\s*(.*)$}{}m;
@@ -352,7 +385,7 @@ sub AddResourceFile
                close($o);
                close($i);
        }
-       $self->AddFile("$dir/win32ver.rc");
+       $self->AddFile("$dir/win32ver.rc", 1);
        return;
 }
 

Reply via email to