Thread: vcbuild - conditional regeneration

vcbuild - conditional regeneration

From
Magnus Hagander
Date:
The attached patch changes vcbuild so the project and solution files are
only regenerated if they are actually changed. This helps when you're
developing in the Visual Studio GUI, because updating the files (even to
the same contents) will cause a reload and re-parse of all the projects
in the solution.

As a bonus, it doesn't trash the project file if it for some reason
aborts half-way through.

The patch includes part of the previously sent patch about pthreads
requirements, because they change the same area. Should be workable
without the other one as well, so it's no problem applying just one of
them if the other one is troublesome.

//Magnus
Index: src/tools/msvc/Project.pm
===================================================================
RCS file: c:/prog/cvsrepo/pgsql/pgsql/src/tools/msvc/Project.pm,v
retrieving revision 1.5
diff -c -r1.5 Project.pm
*** src/tools/msvc/Project.pm    4 Jan 2007 17:58:19 -0000    1.5
--- src/tools/msvc/Project.pm    11 Jan 2007 21:24:38 -0000
***************
*** 252,261 ****
      }

  # 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 = ();
--- 252,261 ----
      }

  # Dump the project
!    my $dump = '';
!     $dump .= $self->WriteHeader();
!     $dump .= $self->WriteReferences();
!     $dump .= <<EOF;
   <Files>
  EOF
      my @dirstack = ();
***************
*** 271,277 ****
                  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
--- 271,277 ----
                  last if (length($dir) == length(join('\\',@dirstack)));
                  last if (substr($dir, length(join('\\',@dirstack)),1) eq '\\');
              }
!             $dump .= ' ' x $#dirstack . "  </Filter>\n";
              pop @dirstack;
          }
  # Now walk forwards and create whatever directories are needed
***************
*** 280,317 ****
              $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 '>' . GenerateCustomTool('Running bison on ' . $f, 'cmd /V:ON /c src/tools/msvc\pgbison.bat ' .
$f,$of) . '</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 '>' . GenerateCustomTool('Running flex on ' . $f, 'src/tools/msvc\pgflex.bat ' . $f,$of) .
'</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><FileConfiguration
Name=\"Release|Win32\"><ToolName=\"VCCLCompilerTool\" ObjectFile=\".\\release\\$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);
  }

--- 280,331 ----
              $left =~ s/^\\//;
              my @pieces = split /\\/, $left;
              push @dirstack, $pieces[0];
!             $dump .= ' ' x $#dirstack . "  <Filter Name=\"$pieces[0]\" Filter=\"\">\n";
          }

!         $dump .= ' ' 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};
!             $dump .= '>' . GenerateCustomTool('Running bison on ' . $f, 'cmd /V:ON /c src/tools/msvc\pgbison.bat ' .
$f,$of) . '</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};
!             $dump .= '>' . GenerateCustomTool('Running flex on ' . $f, 'src/tools/msvc\pgflex.bat ' . $f,$of) .
'</File>'. "\n"; 
          }
          elsif (defined($uniquefiles{$file})) {
  # File already exists, so fake a new name
              my $obj = $dir;
              $obj =~ s/\\/_/g;
!             $dump .= "><FileConfiguration Name=\"Debug|Win32\"><Tool Name=\"VCCLCompilerTool\"
ObjectFile=\".\\debug\\$self->{name}\\$obj". "_$file.obj\" /></FileConfiguration><FileConfiguration
Name=\"Release|Win32\"><ToolName=\"VCCLCompilerTool\" ObjectFile=\".\\release\\$self->{name}\\$obj" . "_$file.obj\"
/></FileConfiguration></File>\n";
          }
          else {
              $uniquefiles{$file} = 1;
!             $dump .= " />\n";
          }
      }
      while ($#dirstack >= 0) {
!         $dump .= ' ' x $#dirstack . "  </Filter>\n";
          pop @dirstack;
      }
!     $dump .= $self->Footer();
!     my $oldcont = read_file("$self->{name}.vcproj",1);
!     if ($oldcont) {
!       my $dump2 = $dump;
!       $dump2 =~ s/ProjectGUID="[^"]+"//gs;
!       $dump2 =~ s/ReferencedProjectIdentifier="[^"]+"//gs;
!       $oldcont =~ s/ProjectGUID="[^"]+"//gs;
!       $oldcont =~ s/ReferencedProjectIdentifier="[^"]+"//gs;
!       if ($dump2 eq $oldcont) {
!          #print "Not rewriting $self->{name}\n";
!          return;
!       }
!    }
!     open(F, ">$self->{name}.vcproj") || croak("Could not write to $self->{name}.vcproj\n");
!     print F $dump;
      close(F);
  }

***************
*** 325,357 ****
  }

  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) = @_;
!
!     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>
  EOF
!     $self->WriteConfiguration($f, 'Debug', { defs=>'_DEBUG;DEBUG=1;', wholeopt=>0 , opt=>0, strpool=>'false',
runtime=>3}); 
!     $self->WriteConfiguration($f, 'Release', { defs=>'', wholeopt=>0, opt=>3, strpool=>'true', runtime=>2 });
! print $f <<EOF;
   </Configurations>
  EOF
  }

  sub WriteConfiguration
  {
!     my ($self, $f, $cfgname, $p) = @_;
      my $cfgtype = ($self->{type} eq "exe")?1:($self->{type} eq "dll"?2:4);
      my $libcfg = (uc $cfgname eq "RELEASE")?"MD":"MDd";
      my $libs = '';
--- 339,373 ----
  }

  sub WriteReferences {
!     my ($self) = @_;
!     my $t = " <References>\n";
      foreach my $ref (@{$self->{references}}) {
!         $t .= "  <ProjectReference ReferencedProjectIdentifier=\"$ref->{guid}\" Name=\"$ref->{name}\" />\n";
      }
!     $t .= " </References>\n";
!     return $t;
  }

  sub WriteHeader {
!     my ($self) = @_;
!    my $t = <<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>
  EOF
!     $t .= $self->WriteConfiguration('Debug', { defs=>'_DEBUG;DEBUG=1;', wholeopt=>0 , opt=>0, strpool=>'false',
runtime=>3}); 
!     $t .= $self->WriteConfiguration('Release', { defs=>'', wholeopt=>0, opt=>3, strpool=>'true', runtime=>2 });
! $t .= <<EOF;
   </Configurations>
  EOF
+    return $t;
  }

  sub WriteConfiguration
  {
!     my ($self, $cfgname, $p) = @_;
!     my $t = '';
      my $cfgtype = ($self->{type} eq "exe")?1:($self->{type} eq "dll"?2:4);
      my $libcfg = (uc $cfgname eq "RELEASE")?"MD":"MDd";
      my $libs = '';
***************
*** 367,382 ****
      }
      $libs =~ s/ $//;
      $libs =~ s/__CFGNAME__/$cfgname/g;
!     print $f <<EOF;
    <Configuration Name="$cfgname|Win32" OutputDirectory=".\\$cfgname\\$self->{name}"
IntermediateDirectory=".\\$cfgname\\$self->{name}"
      ConfigurationType="$cfgtype" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="FALSE" CharacterSet="2"
WholeProgramOptimization="$p->{wholeopt}">
      <Tool Name="VCCLCompilerTool" Optimization="$p->{opt}"
!
AdditionalIncludeDirectories="src/include;src/include/port/win32;src/include/port/win32_msvc;$self->{solution}->{options}->{pthread};$self->{includes}"

PreprocessorDefinitions="WIN32;_WINDOWS;__WINDOWS__;__WIN32__;EXEC_BACKEND;WIN32_STACK_RLIMIT=4194304;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE$self->{defines}$p->{defs}"
          StringPooling="$p->{strpool}"
          RuntimeLibrary="$p->{runtime}" DisableSpecificWarnings="$self->{disablewarnings}"
  EOF
!     print $f <<EOF;
          AssemblerOutput="0" AssemblerListingLocation=".\\$cfgname\\$self->{name}\\"
ObjectFile=".\\$cfgname\\$self->{name}\\"
          ProgramDataBaseFileName=".\\$cfgname\\$self->{name}\\" BrowseInformation="0"
          WarningLevel="3" SuppressStartupBanner="TRUE" DebugInformationFormat="3" CompileAs="0"/>
--- 383,400 ----
      }
      $libs =~ s/ $//;
      $libs =~ s/__CFGNAME__/$cfgname/g;
!     my $pth = $self->{solution}->{options}->{pthread};
!     $pth = '' unless $pth;
!     $t .= <<EOF;
    <Configuration Name="$cfgname|Win32" OutputDirectory=".\\$cfgname\\$self->{name}"
IntermediateDirectory=".\\$cfgname\\$self->{name}"
      ConfigurationType="$cfgtype" UseOfMFC="0" ATLMinimizesCRunTimeLibraryUsage="FALSE" CharacterSet="2"
WholeProgramOptimization="$p->{wholeopt}">
      <Tool Name="VCCLCompilerTool" Optimization="$p->{opt}"
!
AdditionalIncludeDirectories="src/include;src/include/port/win32;src/include/port/win32_msvc;$pth;$self->{includes}"

PreprocessorDefinitions="WIN32;_WINDOWS;__WINDOWS__;__WIN32__;EXEC_BACKEND;WIN32_STACK_RLIMIT=4194304;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE$self->{defines}$p->{defs}"
          StringPooling="$p->{strpool}"
          RuntimeLibrary="$p->{runtime}" DisableSpecificWarnings="$self->{disablewarnings}"
  EOF
!     $t .= <<EOF;
          AssemblerOutput="0" AssemblerListingLocation=".\\$cfgname\\$self->{name}\\"
ObjectFile=".\\$cfgname\\$self->{name}\\"
          ProgramDataBaseFileName=".\\$cfgname\\$self->{name}\\" BrowseInformation="0"
          WarningLevel="3" SuppressStartupBanner="TRUE" DebugInformationFormat="3" CompileAs="0"/>
***************
*** 391,419 ****
      if ($self->{implib}) {
          my $l = $self->{implib};
          $l =~ s/__CFGNAME__/$cfgname/g;
!         print $f "\t\tImportLibrary=\"$l\"\n";
      }
      if ($self->{def}) {
          my $d = $self->{def};
          $d =~ s/__CFGNAME__/$cfgname/g;
!         print $f "\t\tModuleDefinitionFile=\"$d\"\n";
      }

!     print $f "\t/>\n";
!     print $f "\t<Tool Name=\"VCLibrarianTool\" OutputFile=\".\\$cfgname\\$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
src\\tools\\msvc\\gendef.pl$cfgname\\$self->{name}\" />\n"; 
      }
!     print $f <<EOF;
    </Configuration>
  EOF
  }

  sub Footer {
!     my ($self, $f) = @_;

!     print $f <<EOF;
   </Files>
   <Globals/>
  </VisualStudioProject>
--- 409,438 ----
      if ($self->{implib}) {
          my $l = $self->{implib};
          $l =~ s/__CFGNAME__/$cfgname/g;
!         $t .= "\t\tImportLibrary=\"$l\"\n";
      }
      if ($self->{def}) {
          my $d = $self->{def};
          $d =~ s/__CFGNAME__/$cfgname/g;
!         $t .= "\t\tModuleDefinitionFile=\"$d\"\n";
      }

!     $t .= "\t/>\n";
!     $t .= "\t<Tool Name=\"VCLibrarianTool\" OutputFile=\".\\$cfgname\\$self->{name}\\$self->{name}.lib\"
IgnoreDefaultLibraryNames=\"libc\"/>\n"; 
!     $t .= "\t<Tool Name=\"VCResourceCompilerTool\" AdditionalIncludeDirectories=\"src\\include\" />\n";
      if ($self->{builddef}) {
!         $t .= "\t<Tool Name=\"VCPreLinkEventTool\" Description=\"Generate DEF file\" CommandLine=\"perl
src\\tools\\msvc\\gendef.pl$cfgname\\$self->{name}\" />\n"; 
      }
!     $t .= <<EOF;
    </Configuration>
  EOF
+    return $t;
  }

  sub Footer {
!     my ($self) = @_;

!     return <<EOF;
   </Files>
   <Globals/>
  </VisualStudioProject>
***************
*** 424,433 ****
--- 443,456 ----
  # Utility function that loads a complete file
  sub read_file {
      my $filename = shift;
+     my $ignorenoexist = shift;
      my $F;
      my $t = $/;

      undef $/;
+     if ($ignorenoexist) {
+       open($F, $filename) || return '';
+    }
      open($F, $filename) || croak "Could not open file $filename\n";
      my $txt = <$F>;
      close($F);
Index: src/tools/msvc/Solution.pm
===================================================================
RCS file: c:/prog/cvsrepo/pgsql/pgsql/src/tools/msvc/Solution.pm,v
retrieving revision 1.5
diff -c -r1.5 Solution.pm
*** src/tools/msvc/Solution.pm    29 Dec 2006 16:49:02 -0000    1.5
--- src/tools/msvc/Solution.pm    11 Jan 2007 21:21:21 -0000
***************
*** 269,297 ****
          }
      }

!     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
--- 268,295 ----
          }
      }

!     my $dump = <<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}}) {
!             $dump .= <<EOF;
  Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "$proj->{name}", "$proj->{name}.vcproj", "$proj->{guid}"
  EndProject
  EOF
          }
          if ($fld ne "") {
              $flduid{$fld} = Win32::GuidGen();
!             $dump .= <<EOF;
  Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "$fld", "$fld", "$flduid{$fld}"
  EndProject
  EOF
          }
      }

!     $dump .= <<EOF;
  Global
      GlobalSection(SolutionConfigurationPlatforms) = preSolution
          Debug|Win32 = Debug|Win32
***************
*** 302,317 ****

      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.ActiveCfg = Release|Win32
          $proj->{guid}.Release|Win32.Build.0 = Release|Win32
  EOF
          }
      }

!     print SLN <<EOF;
      EndGlobalSection
      GlobalSection(SolutionProperties) = preSolution
          HideSolutionNode = FALSE
--- 300,315 ----

      foreach my $fld (keys %{$self->{projects}}) {
          foreach my $proj (@{$self->{projects}->{$fld}}) {
!         $dump .= <<EOF;
          $proj->{guid}.Debug|Win32.ActiveCfg = Debug|Win32
!         $proj->{guid}.Debug|Win32.Build.0  = Debug|Win32
          $proj->{guid}.Release|Win32.ActiveCfg = Release|Win32
          $proj->{guid}.Release|Win32.Build.0 = Release|Win32
  EOF
          }
      }

!     $dump .= <<EOF;
      EndGlobalSection
      GlobalSection(SolutionProperties) = preSolution
          HideSolutionNode = FALSE
***************
*** 322,335 ****
      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);
  }

--- 320,346 ----
      foreach my $fld (keys %{$self->{projects}}) {
          next if ($fld eq "");
          foreach my $proj (@{$self->{projects}->{$fld}}) {
!             $dump .= "\t\t$proj->{guid} = $flduid{$fld}\n";
          }
      }

!     $dump .= <<EOF;
      EndGlobalSection
  EndGlobal
  EOF
+     my $oldcont = Project::read_file("pgsql.sln",1);
+     if ($oldcont) {
+       my $dump2 = $dump;
+       $dump2 =~ s/{[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}}//gs;
+       $oldcont =~ s/{[A-Z0-9]{8}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{12}}//gs;
+       if ($dump2 eq $oldcont) {
+          #print "Not rewriting pgsql.sln\n";
+          return;
+       }
+    }
+     open(SLN,">pgsql.sln") || croak "Could not write to pgsql.sln\n";
+
+     print SLN $dump;
      close(SLN);
  }

Re: vcbuild - conditional regeneration

From
Magnus Hagander
Date:
On Thu, Jan 11, 2007 at 10:36:11PM +0100, Magnus Hagander wrote:
> The attached patch changes vcbuild so the project and solution files are
> only regenerated if they are actually changed. This helps when you're
> developing in the Visual Studio GUI, because updating the files (even to
> the same contents) will cause a reload and re-parse of all the projects
> in the solution.
>
> As a bonus, it doesn't trash the project file if it for some reason
> aborts half-way through.
>
> The patch includes part of the previously sent patch about pthreads
> requirements, because they change the same area. Should be workable
> without the other one as well, so it's no problem applying just one of
> them if the other one is troublesome.

While reviewing this patch for conflicts that Neil reported (seems to
have something to do with my local CVS repository. I think I need to
switch back to using the network based CVS repo and just stop diffing
things when not connected or during travel), I found a case where this
simply breaks functionality completely.

So please ignore this patch compeltely.

//Magnus