summaryrefslogtreecommitdiff
path: root/devtools/bin/mksln.pl
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /devtools/bin/mksln.pl
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'devtools/bin/mksln.pl')
-rw-r--r--devtools/bin/mksln.pl388
1 files changed, 388 insertions, 0 deletions
diff --git a/devtools/bin/mksln.pl b/devtools/bin/mksln.pl
new file mode 100644
index 0000000..aec1c88
--- /dev/null
+++ b/devtools/bin/mksln.pl
@@ -0,0 +1,388 @@
+#!perl
+use XML::Simple;
+use Data::Dumper;
+use Getopt::Long;
+use File::Basename;
+use Cwd 'abs_path';
+use Cwd;
+use Digest::MD5 qw(md5 md5_hex md5_base64);
+
+
+GetOptions( "verbose"=>\$verbose,
+ "projlist"=>\$projlist,
+ "x360"=>\$x360 );
+
+$sln_name=shift || &PrintArgumentSummaryAndExit;
+
+my $curdir=cwd;
+
+$curdir=~ (m@(^.*/[a-z_]*src[0-9]?)@i) || die "Can't determine srcroot from current directory $curdir";
+
+$srcroot=lc($1);
+
+$linker_tool_name="VCLinkerTool";
+$linker_tool_name="VCX360LinkerTool" if ($x360);
+
+@output_only_projects_dependent_upon = ();
+
+&ReadVPCProjects;
+if ( $sln_name =~ /^\@(\S+)/)
+{
+ $sln_name=$1;
+ &ReadGroup($1);
+ foreach $proj (@PROJS)
+ {
+ &AddProject(lc(abs_path($proj)),1);
+ }
+ if ( $projlist )
+ {
+ &WriteProjectListFile( $sln_name );
+ }
+ else
+ {
+ &WriteSolutionFile($sln_name);
+ }
+}
+else
+{
+ # normal mode
+ while($_ = shift )
+ {
+ if ( /^\@(\S+)/)
+ {
+ # accept group names
+ &ReadGroup($1);
+ foreach $proj (@PROJS)
+ {
+ &AddProject(lc(abs_path($proj)),1);
+ }
+ }
+ elsif ( /^\*(\S+)/)
+ {
+ push( @output_only_projects_dependent_upon, lc( $1 ) );
+ &ReadGroup("everything");
+ foreach $proj (@PROJS)
+ {
+ &AddProject(lc(abs_path($proj)),0);
+ }
+ }
+ else
+ {
+ unless(/\.vcproj/) # if no extension specified, assume its a project name from projects.vgc
+ {
+ $_=$projpath{lc($_)} if length($projpath{lc($_)});
+ }
+ foreach $path (split(/\s+/,$_))
+ {
+ $path=~s@\s+@@g;
+ &AddProject(lc(abs_path($path)),1) if length($path);
+ }
+ }
+ }
+ if ( $projlist )
+ {
+ &WriteProjectListFile( $sln_name );
+ }
+ else
+ {
+ &WriteSolutionFile($sln_name);
+ }
+}
+
+
+sub WriteSolutionFile
+{
+ local($sln)=@_;
+ $sln="$sln.sln" unless ( $sln=~/\./); # add extension if needed
+ if ( ( -e $sln && ( ! ( -w $sln ) ) ) )
+ {
+ print STDERR "$sln is write-protected. Doing p4 edit.\n";
+ print `p4 edit $sln`;
+ die "Failed to make $sln writeable" if ( ! ( -w $sln ) );
+ }
+ open(SLN,">$sln" ) || die "can't open output $sln";
+ # generate a guid for the sln
+ my $sln_guid="8BC9CEB8-8B4A-11D0-8D11-".substr(uc(md5_hex(basename($sln))),0,12);
+
+ print SLN "\xef\xbb\xbf\nMicrosoft Visual Studio Solution File, Format Version 9.00\n# Visual Studio 2005\n";
+ foreach $proj (@PROJECTS)
+ {
+ # check dependencies for "*" projects
+ if ( (! length( $force_project_inclusion{$proj} ) ) &&
+ ( @output_only_projects_dependent_upon ))
+ {
+ my $skip_it = 1;
+ foreach $output_only ( @output_only_projects_dependent_upon )
+ {
+ $skip_it = 0 if ( $output_only eq lc( $proj ) );
+ foreach $lib (split(/,/,$depends_on{$proj}))
+ {
+ $skip_it = 0 if ( $output_only eq lc($lib) );
+ foreach $prvd (split(/,/,$provider{$lib}))
+ {
+ $skip_it = 0 if ( $output_only eq $prvd );
+ }
+ }
+ }
+ next if ( $skip_it );
+ }
+
+ print SLN "Project(\"{",$sln_guid,"}\") = \"$proj\", \"$relpath{$proj}\", \"$guid{$proj}\"\n";
+
+ #, now do dependencies
+ if ( length($depends_on{$proj} ) )
+ {
+ print SLN "\tProjectSection(ProjectDependencies) = postProject\n";
+ foreach $lib (split(/,/,$depends_on{$proj}))
+ {
+ if ( length($provider{$lib}) )
+ {
+ foreach $prvd (split(/,/,$provider{$lib}))
+ {
+ print SLN "\t\t$guid{$prvd} = $guid{$prvd}\n" if ( length($prvd) );
+ }
+ }
+ else
+ {
+ print "I don't know who provides $lib for $proj\n" if ( $verbose && length($lib) );
+ }
+
+ }
+ print SLN "\tEndProjectSection\n";
+ }
+ print SLN "EndProject\n";
+ }
+
+ print SLN "Global\n";
+ print SLN "\tGlobalSection(SolutionProperties) = preSolution\n";
+ print SLN "\t\tHideSolutionNode = FALSE\n";
+ print SLN "\tEndGlobalSection\n";
+ print SLN "EndGlobal\n";
+ close SLN;
+}
+
+sub WriteProjectListFile
+{
+ local($txtfile) = @_;
+ $txtfile = "$txtfile.txt" unless ( $txtfile=~/\./); # add extension if needed
+ open(SLN,">$txtfile" ) || die "can't open output $txtfile";
+
+ foreach $proj (@PROJECTS)
+ {
+ # check dependencies for "*" projects
+ if ( (! length( $force_project_inclusion{$proj} ) ) &&
+ ( @output_only_projects_dependent_upon ))
+ {
+ my $skip_it = 1;
+ foreach $output_only ( @output_only_projects_dependent_upon )
+ {
+ $skip_it = 0 if ( $output_only eq lc( $proj ) );
+ foreach $lib (split(/,/,$depends_on{$proj}))
+ {
+ $skip_it = 0 if ( $output_only eq lc($lib) );
+ foreach $prvd (split(/,/,$provider{$lib}))
+ {
+ $skip_it = 0 if ( $output_only eq $prvd );
+ }
+ }
+ }
+ next if ( $skip_it );
+ }
+
+ push @plist, $proj;
+ }
+ # now, we need to satisfy all dependencies
+ while( $#plist >= 0)
+ {
+ @worklist=@plist;
+ undef @plist;
+ PROJECT: foreach $proj( @worklist )
+ {
+ if ( length($depends_on{$proj} ) )
+ {
+ foreach $lib (split(/,/,$depends_on{$proj}))
+ {
+ if ( length($provider{$lib}) )
+ {
+ foreach $prvd (split(/,/,$provider{$lib}))
+ {
+ if ( length( $prvd ) && ( !$already_did{$prvd} ) )
+ {
+ push @plist, $proj; # can't do it yet
+ next PROJECT;
+ }
+ }
+ }
+ }
+ }
+ $already_did{$proj} = 1;
+ print SLN "$relpath{$proj}\n";
+ }
+ }
+ close SLN;
+}
+
+sub PrintArgumentSummaryAndExit
+{
+ print "Format of command is\n";
+ my $switches="[ -projlist -verbose -x360 ]";
+ print "\t MKSLN $switches <solutionname.sln > proj1.vcproj proj2.vcproj ...\n";
+ print "OR\t MKSLN $switches \@vpcgroupname\n";
+ print "OR\t MKSLN $switches sln_name \@vpcgroupname\n";
+ print "OR\t MKSLN $switches sln_name *project create a solution including only that project and things dependent on it.\n";
+}
+
+
+sub AddProject
+{
+ local($fname, $force )=@_;
+ local($/);
+ print "add project $fname\n" if ( $verbose );
+ open( VCP_IN, $fname ) || die "can't open $fname";
+ my $xmltext=<VCP_IN>;
+ close VCP_IN;
+ my $xml=XMLin($xmltext, forcearray => [ 'File', 'Filter' ] ); #, keyattr =>[ 'name', 'key', 'id', 'Name']);
+ my $pname=lc($xml->{Name});
+ $force_project_inclusion{$pname} = "yes" if ( $force );
+ return if ($already_processed{$pname} );
+ $already_processed{$pname}=1;
+ my $id=$xml->{ProjectGUID};
+ unless( length($id) )
+ {
+ die "project $fname doesn't have a guid. Generated by an old VPC?";
+ }
+ $id = "{".$id."}" unless( $id=~ /}/);
+ $guid{$pname}=$id;
+ push @PROJECTS,$pname;
+ $vcprojpath{$pname}=$fname;
+
+ #get targetname
+ my $targetname=$xml->{Name};
+ # get output target
+
+ my $tools=$xml->{Configurations}->{Configuration}[0];
+ # walk the tool list to see if this project outpus a .lib that something might depend on
+ my $outputtarget;
+ foreach $tool (@{$tools->{'Tool'}})
+ {
+ if ( $tool->{Name} eq "VCLibrarianTool" )
+ {
+ my $outputtarget=lc(basename($tool->{OutputFile}));
+ $provider{$outputtarget}.=",$pname";
+ print "$pname provides $outputtarget\n" if ($verbose);
+ }
+ if ( $tool->{Name} eq $linker_tool_name )
+ {
+ my $outputtarget=$tool->{'ImportLibrary'};
+ if ( length($outputtarget) )
+ {
+ $outputtarget=~s/\$\(TargetName\)/$targetname/i;
+ $outputtarget=lc(basename($outputtarget));
+ $outputtarget =~ s/\.lib/_360.lib/ if ( $x360 );
+ $provider{$outputtarget}=basename($pname);
+ print "$pname provides $outputtarget\n" if ($verbose);
+ }
+ }
+ }
+
+ foreach $filter (@{$xml->{Files}->{Filter}})
+ {
+ foreach $file (@{$filter->{File}})
+ {
+ my $f = lc($file->{RelativePath});
+ if ( $f=~/\.lib$/i) # library dependency
+ {
+ my $libname=basename($f);
+ $depends_on{$pname}.=",".$libname;
+ print "$pname depends on $libname\n" if ($verbose);
+ }
+ }
+ }
+ # generate relative pathname
+ $fname=~s@^$srcroot/@@i;
+ $fname=~s@/@\\@g;
+ $relpath{$pname}=$fname;
+
+}
+
+sub ReadGroup
+{
+ local($matchgroup)=@_;
+ my $curmatch=0;
+ open(GROUPS,"$srcroot/vpc_scripts/groups.vgc") || die "can't open groups.vgc";
+ while(<GROUPS>)
+ {
+ &FixupVPCLine;
+ if (/^\$Group\s+(.*)$/)
+ {
+ my $groups=" $1 ";
+ $groups=~s@\"@@g;
+ $curmatch=0;
+ $curmatch=1 if ( $groups=~/ $matchgroup /i );
+ }
+ elsif ( $curmatch && (/^\s*\"([^\"]+)\"/) )
+ {
+ my $proj=lc($1);
+ my $path=$projpath{$proj};
+ if (length($path))
+ {
+ foreach $prj (split(/\s+/, $path))
+ {
+ $prj=~s@\s+@@g;
+ next unless (length($prj));
+ if ( -e $prj )
+ {
+ push @PROJS,$prj;
+ print "found proj $prj\n" if ($verbose);
+ }
+ else
+ {
+ print STDERR "can't find $prj\n";
+ }
+
+ }
+ }
+ else
+ {
+ print STDERR "couldn't find project name $proj (group = $matchgroup )\n";
+ }
+ }
+ else
+ {
+ $curmatch = 0 if (/\}/);
+ }
+
+ }
+}
+
+sub ReadVPCProjects
+{
+ # group mode. ugh 100x harder to parse vpc than .vcproj
+ open(PROJS,"$srcroot/vpc_scripts/projects.vgc" ) || die "can't open projects.vgc";
+ while(<PROJS>)
+ {
+ &FixupVPCLine;
+ if (/^\s*\$Project\s+\"([^\"]+)\"/)
+ {
+ $curproj=$1;
+ }
+ elsif (/^\s*\"([^\"]+)\.vpc\"/)
+ {
+ my $base = $1;
+ $base="$base"."_x360" if ( $x360 );
+ $projpath{lc($curproj)}.=" $base.vcproj";
+ }
+ }
+ close PROJS;
+}
+
+sub FixupVPCLine
+{
+ s@[\n\r]@@g;
+ s@//.*$@@g; # kill comments
+
+ # use [] skips. need something smarter here. for now, implicit /allgames except hl1 and portalmp
+ $_=undef if ( /\$HL1/);
+ $_=undef if ( /\$PORTALMP/);
+}
+