n l i t e d

:



Thread Links
next

VerUpdate.pl

📢 PUBLIC Page 1023:1/1 | edit | chip 2018-03-28 16:30:09

August 18 2017

The VerUpdate.pl is a Perl script that I use to automatically update the version information during every build. This makes sure every build has a unique version number.

Update 20180328: Added BUILD_NAME option. This is used to "patch up" the version info in the resource script in the pre-link step. Versioning

VerUpdate.pl: ############################################################################ ## VerUpdate.pl: Updates build info in VerFile.h and Resource.rc files ## ## Chip Doran ## ## May 2011: Initial version ## ## Jul 2012: Unicode support ## ############################################################################ use strict; use Encode; use File::stat; use POSIX qw(strftime); ############################################################################ ## Input files ## ## VerProd.h: Global to the entire product line. ## ## This file should contain (at least) these lines: ## ## #define VER_PROD_MAJOR 1 ## ## #define VER_PROD_MINOR 1 ## ## #define VER_PROD_BUILD 1 ## ## VerFile.h: For each executable, library, etc. ## ## This file should contain (at least) these lines: ## ## #define VER_FILE_MAJOR 1 ## ## #define VER_FILE_MINOR 0 ## ## #define VER_FILE_BUILD 2 ## ## Resource.rc: Windows Visual Studio resource script. ## ## The following lines will be updated to reflect VerProd.h, VerFile.h: ## ## FILEVERSION 1,0,0,0 ## ## PRODUCTVERSION 1,0,0,0 ## ## VALUE "FileVersion", "1,0,0,0" ## ## VALUE "ProductVersion", "1,0,0,0" ## ## VALUE "Builder", "$BuilderID" ## ## VALUE "BuildTime", "$BuildTime" ## ############################################################################ ############################################################################ ## Globals ## ############################################################################ our $DoProdIncr= 0; ##Do increment VerProd.h:BUILD? our $DoDebug= 0; ##Do print debug text? our $DoOverwrite= 1; ##Do rewrite input files? our $DoEcho= 0; ##Do echo file read/write? our $DoSet_BUILD_NAME= 0; ##Do overwrite version/OriginalName with BUILD_NAME? our $FileFName; ##VerFile.h file our $ProdFName= ''; ##VerProd.h file our $ResourceFName; ##Resource.rc file our $ProdMajor= 1; ##Product version info our $ProdMinor= 0; our $ProdBuild= 0; our $FileMajor= 1; ##File version info our $FileMinor= 0; our $FileBuild= 0; our $BuildTime= strftime("%Y%m%d%H%M%S",localtime); our $BuilderID= $ENV{"COMPUTERNAME"}; ##Builder machine name our @Lines= (); ##Holds entire file, without newlines our $BOM; ##Set if not ASCII text. our $Encoding; ##Set to encoding name (UTF-16LE) our $NewLine= "\r\n"; ##Newline to be appended to each line ############################################################################ ## Command line arguments ## ############################################################################ foreach(@ARGV) { if(/^prod=(.*)/i) { $ProdFName= $1; } elsif(/^prodincr/i) { $DoProdIncr= 1; } elsif(/^builder=(.*)/i) { $BuilderID= $1; } elsif(/^resource=(.*)/i) { $ResourceFName= $1; } elsif(/^help/i) { DoHelp(); } elsif(/^debug/i) { $DoDebug= 1; } elsif(/^readonly/i) { $DoOverwrite= 0; } elsif(/^write/i) { $DoOverwrite= 1; } elsif(/^echo/i) { $DoEcho= 1; } elsif(/^build_name/i) { $DoSet_BUILD_NAME= 1; } else { $FileFName= $_; } } if($ProdFName) { print "Reading product info from $ProdFName...\n"; ReadLines($ProdFName); $ProdMajor= UpdateBuildNumber("VER_PROD_MAJOR",0); $ProdMinor= UpdateBuildNumber("VER_PROD_MINOR",0); $ProdBuild= UpdateBuildNumber("VER_PROD_BUILD",$DoProdIncr); WriteLines($ProdFName); } if($FileFName) { print "Reading file info from $FileFName...\n"; ReadLines($FileFName); UpdateBuilderID($BuilderID); $FileMajor= UpdateBuildNumber("VER_FILE_MAJOR",0); $FileMinor= UpdateBuildNumber("VER_FILE_MINOR",0); $FileBuild= UpdateBuildNumber("VER_FILE_BUILD",1); UpdateBuildTime(); WriteLines($FileFName); if($ResourceFName) { print "Updating resource script $ResourceFName...\n"; UpdateResource(); } } print "DONE\n" if $DoDebug; sub DoHelp { print "VerUpdate filename [debug] [prod=file.h] [builder=name] [resource=project.rc]\n"; print "Updates version information.\n"; print " debug Enables verbose output\n"; print " prod=file Read product version from file\n"; print " prodincr Increment product build\n"; print " builder=name Set Builder name\n"; print " resource=file Update resource script's version block\n"; print " help Display usage help\n"; print " readonly Write output files to .new\n"; print " echo Print files as read and written.\n"; exit; } ############################################################################ ## Determine the Unicode encoding by reading the BOM (Byte Order Marker) ## ## from the first 2 bytes of the file. ## ## Currently only supports UTF-16LE (0xFEFF) (Windows default). ## ## Everything else is assumed to be 8bit ASCII. ## ############################################################################ sub GetEncoding { my $FName= shift(@_); open(FILE,"<:raw",$FName) or die "Unable to get encoding for $FName.\n"; binmode(FILE); $BOM= unpack('S!',substr(<FILE>,0,2)); if($BOM==0xFEFF) { printf("BOM[%04X] Using UTF-16LE\n",$BOM) if $DoDebug; $Encoding= 'UTF-16LE'; $NewLine= encode($Encoding,"\r\n"); } else { printf("BOM[%04X] Assuming ASCII\n",$BOM) if $DoDebug; $Encoding= 0; $BOM= 0; } close(FILE); } ############################################################################ ## Read the entire file into the @Lines array. ## ## Dealing with Unicode, BOM, and CRLF is a real PitA with perl! ## ############################################################################ sub ReadLines { my $FName= shift(@_); @Lines= (); printf("Reading \'%s\'\n",$FName) if $DoDebug; GetEncoding($FName); if($BOM) { ReadLinesUnicode($FName); } else { ReadLinesAscii($FName); } chomp(@Lines); } #Reading a Unicode file. #The entire file needs to be read in RAW mode, decoded, then split into lines. #Otherwise, perl messes up the 0D0A sequences and garbles the unicode. sub ReadLinesUnicode { my $FName= shift(@_); my $ContentRaw; my $ContentDec; open(FILE,"<:raw",$FName) or die "Unable to open '$FName' for reading.\n"; $ContentRaw= do { local $/; <FILE> }; close(FILE); $ContentDec= decode($Encoding,$ContentRaw); @Lines= split("\r\n",$ContentDec); } sub ReadLinesAscii { my $FName= shift(@_); open(FILE,"<",$FName) or die "Unable to open '$FName' for reading.\n"; while(<FILE>) { print "$_" if $DoEcho; push(@Lines,$_); } close(FILE); } ############################################################################ ## Write the entire @Lines array back out to the file. ## ############################################################################ sub WriteLines { my $FName= shift(@_); $FName= $FName.".new" if !$DoOverwrite; print "Writing $FName using '$Encoding'\n" if $DoDebug; print "------\n" if $DoDebug; ClearReadOnly($FName); if($BOM) { WriteLinesUnicode($FName); } else { WriteLinesAscii($FName); } } #Writing a Unicode file. #The file needs to be written in RAW mode, otherwise the CRLF's will be #all messed up. The NewLine needs to be encoded before being written. #The BOM needs to be updated after the file has been written. sub WriteLinesUnicode { my $FName= shift(@_); my $ContentDec; open(FILE,">:raw",$FName) or die "Unable to open '$FName' for writing.\n"; foreach(@Lines) { print FILE encode($Encoding,$_).$NewLine; } close(FILE); printf("Writing BOM[%04X]\n",$BOM) if $DoDebug; open(FILE,"+<:raw",$FName); binmode(FILE); print FILE pack('S!',$BOM); close(FILE); } sub WriteLinesAscii { my $FName= shift(@_); open(FILE,">",$FName) or die "Unable to open '$FName' for writing.\n"; foreach (@Lines) { print "$_\n" if $DoEcho; print FILE "$_\n"; } close(FILE); } ############################################################################ ## Clear the ReadOnly flag for both Windows and Linux. ## ############################################################################ sub ClearReadOnly { my $FName= shift(@_); my $Attr= stat($FName); if(-r $FName) { printf("$FName attribute: %x\n",$Attr->mode) if $DoDebug; print "$FName: Enable Writes\n" if $DoDebug; chmod($Attr->mode|0222,$FName); } } ############################################################################ ## Find and increment the builder number ## ## This is performed on the @Lines array. ## ############################################################################ sub UpdateBuildNumber { my $Token= shift(@_); my $DoIncr= shift(@_); my $IsFound= 0; my $BuildID= 0; foreach (@Lines) { if(/^#define $Token(\s+?)([0-9]+)(.*)/) { $BuildID= $2+$DoIncr; $_= "#define $Token$1$BuildID$3"; print "Found: $_\n" if $DoDebug; $IsFound= 1; } } if(!$IsFound) { $BuildID= $DoIncr; print "$Token not found.\n"; $Lines[$#Lines]= "#define $Token $BuildID"; } return($BuildID); } #Find and set the VER_BUILDER ident. sub UpdateBuilderID { my $Builder= shift(@_); my $IsFound= 0; foreach (@Lines) { if(/^#define VER_BUILDER(\s+?)\"([^"])*\"(.*)/) { $_= "#define VER_BUILDER$1\"$Builder\"$3"; print "Found: $_\n" if $DoDebug; $IsFound= 1; } } if(!$IsFound) { print "VER_BUILDER not found.\n"; $Lines[$#Lines]= "#define VER_BUILDER \"$Builder\""; } } #Find and set the VER_BUILD_TIME line. sub UpdateBuildTime { my $IsFound= 0; foreach(@Lines) { if(/^#define VER_BUILD_TIME(\s+?)\"([^"])*\"(.*)/) { $_= "#define VER_BUILD_TIME$1\"$BuildTime\"$3"; print "Found: $_\n" if $DoDebug; $IsFound= 1; } } if(!$IsFound) { print "VER_BUILD_TIME not found.\n"; $Lines[$#Lines]= "#define VER_BUILD_TIME \"$BuildTime\""; } } ############################################################################ ## Resource Script ## ## Update the version information in a resource script to match. ## ############################################################################ sub UpdateResource { my $IsUpdate; ReadLines($ResourceFName); foreach(@Lines) { $IsUpdate= 1; if(/^( *)(FILEVERSION) */) { $_= "$1$2 $FileMajor,$FileMinor,0,$FileBuild"; } elsif(/^( *)(PRODUCTVERSION) */) { $_= "$1$2 $ProdMajor,$ProdMinor,0,$ProdBuild"; } elsif(/^( *)(VALUE \"FileVersion\",)/i) { $_= "$1$2 \"$FileMajor,$FileMinor,0,$FileBuild\""; } elsif(/^( *)(VALUE \"ProductVersion\",)/i) { $_= "$1$2 \"$ProdMajor,$ProdMinor,0,$ProdBuild\""; } elsif(/^( *)(VALUE \"Builder\",)/i) { $_= "$1$2 \"$BuilderID\""; } elsif(/^( *)(VALUE \"BuildTime\",)/i) { $_= "$1$2 \"$BuildTime\""; } elsif($DoSet_BUILD_NAME && /^( *)(VALUE \"OriginalFilename",)/i) { $_= "$1$2 BUILD_NAME"; } else { $IsUpdate= 0; } print "UPDATE: $_\n" if $IsUpdate && $DoDebug; } ClearReadOnly($ResourceFName); WriteLines($ResourceFName); } #/**EOF: VerUpdate.pl**/


close comments Comments are closed.

Comments are moderated. Anonymous comments are not visible to other users until approved. The content of comments remains the intellectual property of the poster. Comments may be removed or reused (but not modified) by this site at any time without notice.

  1. [] ok delete


Page rendered by tikope in 114.705ms