From 6aaedb813fa11ba0679c3051bc2eb28646b9506c Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 30 Aug 2025 16:53:58 -0700 Subject: Update to SDL3 --- .../build-scripts/add-source-to-projects.pl | 599 +++++++++++++++++++++ 1 file changed, 599 insertions(+) create mode 100755 src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl (limited to 'src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl') diff --git a/src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl b/src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl new file mode 100755 index 0000000..5ba0a69 --- /dev/null +++ b/src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl @@ -0,0 +1,599 @@ +#!/usr/bin/perl -w + +# Add source files and headers to Xcode and Visual Studio projects. +# THIS IS NOT ROBUST, THIS IS JUST RYAN AVOIDING RUNNING BETWEEN +# THREE COMPUTERS AND A BUNCH OF DEVELOPMENT ENVIRONMENTS TO ADD +# A STUPID FILE TO THE BUILD. + + +use warnings; +use strict; +use File::Basename; + + +my %xcode_references = (); +sub generate_xcode_id { + my @chars = ('0'..'9', 'A'..'F'); + my $str; + + do { + my $len = 16; + $str = '0000'; # start and end with '0000' so we know we added it. + while ($len--) { + $str .= $chars[rand @chars] + }; + $str .= '0000'; # start and end with '0000' so we know we added it. + } while (defined($xcode_references{$str})); + + $xcode_references{$str} = 1; # so future calls can't generate this one. + + return $str; +} + +sub process_xcode { + my $addpath = shift; + my $pbxprojfname = shift; + my $lineno; + + %xcode_references = (); + + my $addfname = basename($addpath); + my $addext = ''; + if ($addfname =~ /\.(.*?)\Z/) { + $addext = $1; + } + + my $is_public_header = ($addpath =~ /\Ainclude\/SDL3\//) ? 1 : 0; + my $filerefpath = $is_public_header ? "SDL3/$addfname" : $addfname; + + my $srcs_or_headers = ''; + my $addfiletype = ''; + + if ($addext eq 'c') { + $srcs_or_headers = 'Sources'; + $addfiletype = 'sourcecode.c.c'; + } elsif ($addext eq 'm') { + $srcs_or_headers = 'Sources'; + $addfiletype = 'sourcecode.c.objc'; + } elsif ($addext eq 'h') { + $srcs_or_headers = 'Headers'; + $addfiletype = 'sourcecode.c.h'; + } else { + die("Unexpected file extension '$addext'\n"); + } + + my $fh; + + open $fh, '<', $pbxprojfname or die("Failed to open '$pbxprojfname': $!\n"); + chomp(my @pbxproj = <$fh>); + close($fh); + + # build a table of all ids, in case we duplicate one by some miracle. + $lineno = 0; + foreach (@pbxproj) { + $lineno++; + + # like "F3676F582A7885080091160D /* SDL3.dmg */ = {" + if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) { + $xcode_references{$1} = $2; + } + } + + # build out of a tree of PBXGroup items. + my %pbxgroups = (); + my $thispbxgroup; + my $pbxgroup_children; + my $pbxgroup_state = 0; + my $pubheaders_group_hash = ''; + my $libsrc_group_hash = ''; + $lineno = 0; + foreach (@pbxproj) { + $lineno++; + if ($pbxgroup_state == 0) { + $pbxgroup_state++ if /\A\/\* Begin PBXGroup section \*\/\Z/; + } elsif ($pbxgroup_state == 1) { + # like "F3676F582A7885080091160D /* SDL3.dmg */ = {" + if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) { + my %newhash = (); + $pbxgroups{$1} = \%newhash; + $thispbxgroup = \%newhash; + $pubheaders_group_hash = $1 if $2 eq 'Public Headers'; + $libsrc_group_hash = $1 if $2 eq 'Library Source'; + $pbxgroup_state++; + } elsif (/\A\/\* End PBXGroup section \*\/\Z/) { + last; + } else { + die("Expected pbxgroup obj on '$pbxprojfname' line $lineno\n"); + } + } elsif ($pbxgroup_state == 2) { + if (/\A\t\t\tisa \= PBXGroup;\Z/) { + $pbxgroup_state++; + } else { + die("Expected pbxgroup obj's isa field on '$pbxprojfname' line $lineno\n"); + } + } elsif ($pbxgroup_state == 3) { + if (/\A\t\t\tchildren \= \(\Z/) { + my %newhash = (); + $$thispbxgroup{'children'} = \%newhash; + $pbxgroup_children = \%newhash; + $pbxgroup_state++; + } else { + die("Expected pbxgroup obj's children field on '$pbxprojfname' line $lineno\n"); + } + } elsif ($pbxgroup_state == 4) { + if (/\A\t\t\t\t([A-F0-9]{24}) \/\* (.*?) \*\/,\Z/) { + $$pbxgroup_children{$1} = $2; + } elsif (/\A\t\t\t\);\Z/) { + $pbxgroup_state++; + } else { + die("Expected pbxgroup obj's children element on '$pbxprojfname' line $lineno\n"); + } + } elsif ($pbxgroup_state == 5) { + if (/\A\t\t\t(.*?) \= (.*?);\Z/) { + $$thispbxgroup{$1} = $2; + } elsif (/\A\t\t\};\Z/) { + $pbxgroup_state = 1; + } else { + die("Expected pbxgroup obj field on '$pbxprojfname' line $lineno\n"); + } + } else { + die("bug in this script."); + } + } + + die("Didn't see PBXGroup section in '$pbxprojfname'. Bug?\n") if $pbxgroup_state == 0; + die("Didn't see Public Headers PBXGroup in '$pbxprojfname'. Bug?\n") if $pubheaders_group_hash eq ''; + die("Didn't see Library Source PBXGroup in '$pbxprojfname'. Bug?\n") if $libsrc_group_hash eq ''; + + # Some debug log dumping... + if (0) { + foreach (keys %pbxgroups) { + my $k = $_; + my $g = $pbxgroups{$k}; + print("$_:\n"); + foreach (keys %$g) { + print(" $_:\n"); + if ($_ eq 'children') { + my $kids = $$g{$_}; + foreach (keys %$kids) { + print(" $_ -> " . $$kids{$_} . "\n"); + } + } else { + print(' ' . $$g{$_} . "\n"); + } + } + print("\n"); + } + } + + # Get some unique IDs for our new thing. + my $fileref = generate_xcode_id(); + my $buildfileref = generate_xcode_id(); + + + # Figure out what group to insert this into (or what groups to make) + my $add_to_group_fileref = $fileref; + my $add_to_group_addfname = $addfname; + my $newgrptext = ''; + my $grphash = ''; + if ($is_public_header) { + $grphash = $pubheaders_group_hash; # done! + } else { + $grphash = $libsrc_group_hash; + my @splitpath = split(/\//, dirname($addpath)); + if ($splitpath[0] eq 'src') { + shift @splitpath; + } + while (my $elem = shift(@splitpath)) { + my $g = $pbxgroups{$grphash}; + my $kids = $$g{'children'}; + my $found = 0; + foreach (keys %$kids) { + my $hash = $_; + my $fname = $$kids{$hash}; + if (uc($fname) eq uc($elem)) { + $grphash = $hash; + $found = 1; + last; + } + } + unshift(@splitpath, $elem), last if (not $found); + } + + if (@splitpath) { # still elements? We need to build groups. + my $newgroupref = generate_xcode_id(); + + $add_to_group_fileref = $newgroupref; + $add_to_group_addfname = $splitpath[0]; + + while (my $elem = shift(@splitpath)) { + my $lastelem = @splitpath ? 0 : 1; + my $childhash = $lastelem ? $fileref : generate_xcode_id(); + my $childpath = $lastelem ? $addfname : $splitpath[0]; + $newgrptext .= "\t\t$newgroupref /* $elem */ = {\n"; + $newgrptext .= "\t\t\tisa = PBXGroup;\n"; + $newgrptext .= "\t\t\tchildren = (\n"; + $newgrptext .= "\t\t\t\t$childhash /* $childpath */,\n"; + $newgrptext .= "\t\t\t);\n"; + $newgrptext .= "\t\t\tpath = $elem;\n"; + $newgrptext .= "\t\t\tsourceTree = \"\";\n"; + $newgrptext .= "\t\t};\n"; + $newgroupref = $childhash; + } + } + } + + my $tmpfname = "$pbxprojfname.tmp"; + open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n"); + + my $add_to_this_group = 0; + $pbxgroup_state = 0; + $lineno = 0; + foreach (@pbxproj) { + $lineno++; + if ($pbxgroup_state == 0) { + # Drop in new references at the end of their sections... + if (/\A\/\* End PBXBuildFile section \*\/\Z/) { + print $fh "\t\t$buildfileref /* $addfname in $srcs_or_headers */ = {isa = PBXBuildFile; fileRef = $fileref /* $addfname */;"; + if ($is_public_header) { + print $fh " settings = {ATTRIBUTES = (Public, ); };"; + } + print $fh " };\n"; + } elsif (/\A\/\* End PBXFileReference section \*\/\Z/) { + print $fh "\t\t$fileref /* $addfname */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = $addfiletype; name = $addfname; path = $filerefpath; sourceTree = \"\"; };\n"; + } elsif (/\A\/\* Begin PBXGroup section \*\/\Z/) { + $pbxgroup_state = 1; + } elsif (/\A\/\* Begin PBXSourcesBuildPhase section \*\/\Z/) { + $pbxgroup_state = 5; + } + } elsif ($pbxgroup_state == 1) { + if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) { + $pbxgroup_state++; + $add_to_this_group = $1 eq $grphash; + } elsif (/\A\/\* End PBXGroup section \*\/\Z/) { + print $fh $newgrptext; + $pbxgroup_state = 0; + } + } elsif ($pbxgroup_state == 2) { + if (/\A\t\t\tchildren \= \(\Z/) { + $pbxgroup_state++; + } + } elsif ($pbxgroup_state == 3) { + if (/\A\t\t\t\);\Z/) { + if ($add_to_this_group) { + print $fh "\t\t\t\t$add_to_group_fileref /* $add_to_group_addfname */,\n"; + } + $pbxgroup_state++; + } + } elsif ($pbxgroup_state == 4) { + if (/\A\t\t\};\Z/) { + $add_to_this_group = 0; + } + $pbxgroup_state = 1; + } elsif ($pbxgroup_state == 5) { + if (/\A\t\t\t\);\Z/) { + if ($srcs_or_headers eq 'Sources') { + print $fh "\t\t\t\t$buildfileref /* $addfname in $srcs_or_headers */,\n"; + } + $pbxgroup_state = 0; + } + } + + print $fh "$_\n"; + } + + close($fh); + rename($tmpfname, $pbxprojfname); +} + +my %visualc_references = (); +sub generate_visualc_id { # these are just standard Windows GUIDs. + my @chars = ('0'..'9', 'a'..'f'); + my $str; + + do { + my $len = 24; + $str = '0000'; # start and end with '0000' so we know we added it. + while ($len--) { + $str .= $chars[rand @chars] + }; + $str .= '0000'; # start and end with '0000' so we know we added it. + $str =~ s/\A(........)(....)(....)(............)\Z/$1-$2-$3-$4/; # add dashes in the appropriate places. + } while (defined($visualc_references{$str})); + + $visualc_references{$str} = 1; # so future calls can't generate this one. + + return $str; +} + + +sub process_visualstudio { + my $addpath = shift; + my $vcxprojfname = shift; + my $lineno; + + %visualc_references = (); + + my $is_public_header = ($addpath =~ /\Ainclude\/SDL3\//) ? 1 : 0; + + my $addfname = basename($addpath); + my $addext = ''; + if ($addfname =~ /\.(.*?)\Z/) { + $addext = $1; + } + + my $isheader = 0; + if ($addext eq 'c') { + $isheader = 0; + } elsif ($addext eq 'm') { + return; # don't add Objective-C files to Visual Studio projects! + } elsif ($addext eq 'h') { + $isheader = 1; + } else { + die("Unexpected file extension '$addext'\n"); + } + + my $fh; + + open $fh, '<', $vcxprojfname or die("Failed to open '$vcxprojfname': $!\n"); + chomp(my @vcxproj = <$fh>); + close($fh); + + my $vcxgroup_state; + + my $rawaddvcxpath = "$addpath"; + $rawaddvcxpath =~ s/\//\\/g; + + # Figure out relative path from vcxproj file... + my $addvcxpath = ''; + my @subdirs = split(/\//, $vcxprojfname); + pop @subdirs; + foreach (@subdirs) { + $addvcxpath .= "..\\"; + } + $addvcxpath .= $rawaddvcxpath; + + my $prevname = undef; + + my $tmpfname; + + $tmpfname = "$vcxprojfname.tmp"; + open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n"); + + my $added = 0; + + $added = 0; + $vcxgroup_state = 0; + $prevname = undef; + $lineno = 0; + foreach (@vcxproj) { + $lineno++; + if ($vcxgroup_state == 0) { + if (/\A \\Z/) { + $vcxgroup_state = 1; + $prevname = undef; + } + } elsif ($vcxgroup_state == 1) { + if (/\A \\Z/) { + $vcxgroup_state = 0; + $prevname = undef; + } + } + + # Don't do elsif, we need to check this line again. + if ($vcxgroup_state == 2) { + if (/\A \Z/) { + my $nextname = $1; + if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) { + print $fh " \n"; + $vcxgroup_state = 0; + $added = 1; + } + $prevname = $nextname; + } elsif (/\A \<\/ItemGroup\>\Z/) { + if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) { + print $fh " \n"; + $vcxgroup_state = 0; + $added = 1; + } + } + } elsif ($vcxgroup_state == 3) { + if (/\A \Z/) { + my $nextname = $1; + if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) { + print $fh " \n"; + $vcxgroup_state = 0; + $added = 1; + } + $prevname = $nextname; + } elsif (/\A \<\/ItemGroup\>\Z/) { + if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) { + print $fh " \n"; + $vcxgroup_state = 0; + $added = 1; + } + } + } + + print $fh "$_\n"; + } + + close($fh); + rename($tmpfname, $vcxprojfname); + + my $vcxfiltersfname = "$vcxprojfname.filters"; + open $fh, '<', $vcxfiltersfname or die("Failed to open '$vcxfiltersfname': $!\n"); + chomp(my @vcxfilters = <$fh>); + close($fh); + + my $newgrptext = ''; + my $filter = ''; + if ($is_public_header) { + $filter = 'API Headers'; + } else { + $filter = lc(dirname($addpath)); + $filter =~ s/\Asrc\///; # there's no filter for the base "src/" dir, where SDL.c and friends live. + $filter =~ s/\//\\/g; + $filter = '' if $filter eq 'src'; + + if ($filter ne '') { + # see if the filter already exists, otherwise add it. + my %existing_filters = (); + my $current_filter = ''; + my $found = 0; + foreach (@vcxfilters) { + # These lines happen to be unique, so we don't have to parse down to find this section. + if (/\A \\Z/) { + $current_filter = lc($1); + if ($current_filter eq $filter) { + $found = 1; + } + } elsif (/\A \\{(.*?)\}\<\/UniqueIdentifier\>\Z/) { + $visualc_references{$1} = $current_filter; # gather up existing GUIDs to avoid duplicates. + $existing_filters{$current_filter} = $1; + } + } + + if (not $found) { # didn't find it? We need to build filters. + my $subpath = ''; + my @splitpath = split(/\\/, $filter); + while (my $elem = shift(@splitpath)) { + $subpath .= "\\" if ($subpath ne ''); + $subpath .= $elem; + if (not $existing_filters{$subpath}) { + my $newgroupref = generate_visualc_id(); + $newgrptext .= " \n"; + $newgrptext .= " {$newgroupref}\n"; + $newgrptext .= " \n" + } + } + } + } + } + + $tmpfname = "$vcxfiltersfname.tmp"; + open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n"); + + $added = 0; + $vcxgroup_state = 0; + $prevname = undef; + $lineno = 0; + foreach (@vcxfilters) { + $lineno++; + + # We cheat here, because these lines are unique, we don't have to fully parse this file. + if ($vcxgroup_state == 0) { + if (/\A \\Z/) { + if ($newgrptext ne '') { + $vcxgroup_state = 1; + $prevname = undef; + } + } elsif (/\A \\Z/) { + print $fh $newgrptext; + $newgrptext = ''; + $vcxgroup_state = 0; + } + } elsif ($vcxgroup_state == 2) { + if (/\A \n"; + print $fh " $filter\n"; + print $fh " \n"; + } else { + print $fh " />\n"; + } + $added = 1; + } + $prevname = $nextname; + } elsif (/\A \<\/ItemGroup\>\Z/) { + if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) { + print $fh " \n"; + print $fh " $filter\n"; + print $fh " \n"; + } else { + print $fh " />\n"; + } + $added = 1; + } + $vcxgroup_state = 0; + } + } elsif ($vcxgroup_state == 3) { + if (/\A \n"; + print $fh " $filter\n"; + print $fh " \n"; + } else { + print $fh " />\n"; + } + $added = 1; + } + $prevname = $nextname; + } elsif (/\A \<\/ItemGroup\>\Z/) { + if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) { + print $fh " \n"; + print $fh " $filter\n"; + print $fh " \n"; + } else { + print $fh " />\n"; + } + $added = 1; + } + $vcxgroup_state = 0; + } + } + + print $fh "$_\n"; + } + + close($fh); + rename($tmpfname, $vcxfiltersfname); +} + + +# Mainline! + +chdir(dirname($0)); # assumed to be in build-scripts +chdir('..'); # head to root of source tree. + +foreach (@ARGV) { + s/\A\.\///; # Turn "./path/to/file.txt" into "path/to/file.txt" + my $arg = $_; + process_xcode($arg, 'Xcode/SDL/SDL.xcodeproj/project.pbxproj'); + process_visualstudio($arg, 'VisualC/SDL/SDL.vcxproj'); + process_visualstudio($arg, 'VisualC-GDK/SDL/SDL.vcxproj'); +} + +print("Done. Please run `git diff` and make sure this looks okay!\n"); + +exit(0); + -- cgit v1.2.3