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; }