summaryrefslogtreecommitdiff
path: root/src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
committer3gg <3gg@shellblade.net>2025-08-30 16:53:58 -0700
commit6aaedb813fa11ba0679c3051bc2eb28646b9506c (patch)
tree34acbfc9840e02cb4753e6306ea7ce978bf8b58e /src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl
parent8f228ade99dd3d4c8da9b78ade1815c9adf85c8f (diff)
Update to SDL3
Diffstat (limited to 'src/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl')
-rwxr-xr-xsrc/contrib/SDL-3.2.20/build-scripts/add-source-to-projects.pl599
1 files changed, 599 insertions, 0 deletions
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 @@
1#!/usr/bin/perl -w
2
3# Add source files and headers to Xcode and Visual Studio projects.
4# THIS IS NOT ROBUST, THIS IS JUST RYAN AVOIDING RUNNING BETWEEN
5# THREE COMPUTERS AND A BUNCH OF DEVELOPMENT ENVIRONMENTS TO ADD
6# A STUPID FILE TO THE BUILD.
7
8
9use warnings;
10use strict;
11use File::Basename;
12
13
14my %xcode_references = ();
15sub generate_xcode_id {
16 my @chars = ('0'..'9', 'A'..'F');
17 my $str;
18
19 do {
20 my $len = 16;
21 $str = '0000'; # start and end with '0000' so we know we added it.
22 while ($len--) {
23 $str .= $chars[rand @chars]
24 };
25 $str .= '0000'; # start and end with '0000' so we know we added it.
26 } while (defined($xcode_references{$str}));
27
28 $xcode_references{$str} = 1; # so future calls can't generate this one.
29
30 return $str;
31}
32
33sub process_xcode {
34 my $addpath = shift;
35 my $pbxprojfname = shift;
36 my $lineno;
37
38 %xcode_references = ();
39
40 my $addfname = basename($addpath);
41 my $addext = '';
42 if ($addfname =~ /\.(.*?)\Z/) {
43 $addext = $1;
44 }
45
46 my $is_public_header = ($addpath =~ /\Ainclude\/SDL3\//) ? 1 : 0;
47 my $filerefpath = $is_public_header ? "SDL3/$addfname" : $addfname;
48
49 my $srcs_or_headers = '';
50 my $addfiletype = '';
51
52 if ($addext eq 'c') {
53 $srcs_or_headers = 'Sources';
54 $addfiletype = 'sourcecode.c.c';
55 } elsif ($addext eq 'm') {
56 $srcs_or_headers = 'Sources';
57 $addfiletype = 'sourcecode.c.objc';
58 } elsif ($addext eq 'h') {
59 $srcs_or_headers = 'Headers';
60 $addfiletype = 'sourcecode.c.h';
61 } else {
62 die("Unexpected file extension '$addext'\n");
63 }
64
65 my $fh;
66
67 open $fh, '<', $pbxprojfname or die("Failed to open '$pbxprojfname': $!\n");
68 chomp(my @pbxproj = <$fh>);
69 close($fh);
70
71 # build a table of all ids, in case we duplicate one by some miracle.
72 $lineno = 0;
73 foreach (@pbxproj) {
74 $lineno++;
75
76 # like "F3676F582A7885080091160D /* SDL3.dmg */ = {"
77 if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) {
78 $xcode_references{$1} = $2;
79 }
80 }
81
82 # build out of a tree of PBXGroup items.
83 my %pbxgroups = ();
84 my $thispbxgroup;
85 my $pbxgroup_children;
86 my $pbxgroup_state = 0;
87 my $pubheaders_group_hash = '';
88 my $libsrc_group_hash = '';
89 $lineno = 0;
90 foreach (@pbxproj) {
91 $lineno++;
92 if ($pbxgroup_state == 0) {
93 $pbxgroup_state++ if /\A\/\* Begin PBXGroup section \*\/\Z/;
94 } elsif ($pbxgroup_state == 1) {
95 # like "F3676F582A7885080091160D /* SDL3.dmg */ = {"
96 if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) {
97 my %newhash = ();
98 $pbxgroups{$1} = \%newhash;
99 $thispbxgroup = \%newhash;
100 $pubheaders_group_hash = $1 if $2 eq 'Public Headers';
101 $libsrc_group_hash = $1 if $2 eq 'Library Source';
102 $pbxgroup_state++;
103 } elsif (/\A\/\* End PBXGroup section \*\/\Z/) {
104 last;
105 } else {
106 die("Expected pbxgroup obj on '$pbxprojfname' line $lineno\n");
107 }
108 } elsif ($pbxgroup_state == 2) {
109 if (/\A\t\t\tisa \= PBXGroup;\Z/) {
110 $pbxgroup_state++;
111 } else {
112 die("Expected pbxgroup obj's isa field on '$pbxprojfname' line $lineno\n");
113 }
114 } elsif ($pbxgroup_state == 3) {
115 if (/\A\t\t\tchildren \= \(\Z/) {
116 my %newhash = ();
117 $$thispbxgroup{'children'} = \%newhash;
118 $pbxgroup_children = \%newhash;
119 $pbxgroup_state++;
120 } else {
121 die("Expected pbxgroup obj's children field on '$pbxprojfname' line $lineno\n");
122 }
123 } elsif ($pbxgroup_state == 4) {
124 if (/\A\t\t\t\t([A-F0-9]{24}) \/\* (.*?) \*\/,\Z/) {
125 $$pbxgroup_children{$1} = $2;
126 } elsif (/\A\t\t\t\);\Z/) {
127 $pbxgroup_state++;
128 } else {
129 die("Expected pbxgroup obj's children element on '$pbxprojfname' line $lineno\n");
130 }
131 } elsif ($pbxgroup_state == 5) {
132 if (/\A\t\t\t(.*?) \= (.*?);\Z/) {
133 $$thispbxgroup{$1} = $2;
134 } elsif (/\A\t\t\};\Z/) {
135 $pbxgroup_state = 1;
136 } else {
137 die("Expected pbxgroup obj field on '$pbxprojfname' line $lineno\n");
138 }
139 } else {
140 die("bug in this script.");
141 }
142 }
143
144 die("Didn't see PBXGroup section in '$pbxprojfname'. Bug?\n") if $pbxgroup_state == 0;
145 die("Didn't see Public Headers PBXGroup in '$pbxprojfname'. Bug?\n") if $pubheaders_group_hash eq '';
146 die("Didn't see Library Source PBXGroup in '$pbxprojfname'. Bug?\n") if $libsrc_group_hash eq '';
147
148 # Some debug log dumping...
149 if (0) {
150 foreach (keys %pbxgroups) {
151 my $k = $_;
152 my $g = $pbxgroups{$k};
153 print("$_:\n");
154 foreach (keys %$g) {
155 print(" $_:\n");
156 if ($_ eq 'children') {
157 my $kids = $$g{$_};
158 foreach (keys %$kids) {
159 print(" $_ -> " . $$kids{$_} . "\n");
160 }
161 } else {
162 print(' ' . $$g{$_} . "\n");
163 }
164 }
165 print("\n");
166 }
167 }
168
169 # Get some unique IDs for our new thing.
170 my $fileref = generate_xcode_id();
171 my $buildfileref = generate_xcode_id();
172
173
174 # Figure out what group to insert this into (or what groups to make)
175 my $add_to_group_fileref = $fileref;
176 my $add_to_group_addfname = $addfname;
177 my $newgrptext = '';
178 my $grphash = '';
179 if ($is_public_header) {
180 $grphash = $pubheaders_group_hash; # done!
181 } else {
182 $grphash = $libsrc_group_hash;
183 my @splitpath = split(/\//, dirname($addpath));
184 if ($splitpath[0] eq 'src') {
185 shift @splitpath;
186 }
187 while (my $elem = shift(@splitpath)) {
188 my $g = $pbxgroups{$grphash};
189 my $kids = $$g{'children'};
190 my $found = 0;
191 foreach (keys %$kids) {
192 my $hash = $_;
193 my $fname = $$kids{$hash};
194 if (uc($fname) eq uc($elem)) {
195 $grphash = $hash;
196 $found = 1;
197 last;
198 }
199 }
200 unshift(@splitpath, $elem), last if (not $found);
201 }
202
203 if (@splitpath) { # still elements? We need to build groups.
204 my $newgroupref = generate_xcode_id();
205
206 $add_to_group_fileref = $newgroupref;
207 $add_to_group_addfname = $splitpath[0];
208
209 while (my $elem = shift(@splitpath)) {
210 my $lastelem = @splitpath ? 0 : 1;
211 my $childhash = $lastelem ? $fileref : generate_xcode_id();
212 my $childpath = $lastelem ? $addfname : $splitpath[0];
213 $newgrptext .= "\t\t$newgroupref /* $elem */ = {\n";
214 $newgrptext .= "\t\t\tisa = PBXGroup;\n";
215 $newgrptext .= "\t\t\tchildren = (\n";
216 $newgrptext .= "\t\t\t\t$childhash /* $childpath */,\n";
217 $newgrptext .= "\t\t\t);\n";
218 $newgrptext .= "\t\t\tpath = $elem;\n";
219 $newgrptext .= "\t\t\tsourceTree = \"<group>\";\n";
220 $newgrptext .= "\t\t};\n";
221 $newgroupref = $childhash;
222 }
223 }
224 }
225
226 my $tmpfname = "$pbxprojfname.tmp";
227 open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n");
228
229 my $add_to_this_group = 0;
230 $pbxgroup_state = 0;
231 $lineno = 0;
232 foreach (@pbxproj) {
233 $lineno++;
234 if ($pbxgroup_state == 0) {
235 # Drop in new references at the end of their sections...
236 if (/\A\/\* End PBXBuildFile section \*\/\Z/) {
237 print $fh "\t\t$buildfileref /* $addfname in $srcs_or_headers */ = {isa = PBXBuildFile; fileRef = $fileref /* $addfname */;";
238 if ($is_public_header) {
239 print $fh " settings = {ATTRIBUTES = (Public, ); };";
240 }
241 print $fh " };\n";
242 } elsif (/\A\/\* End PBXFileReference section \*\/\Z/) {
243 print $fh "\t\t$fileref /* $addfname */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = $addfiletype; name = $addfname; path = $filerefpath; sourceTree = \"<group>\"; };\n";
244 } elsif (/\A\/\* Begin PBXGroup section \*\/\Z/) {
245 $pbxgroup_state = 1;
246 } elsif (/\A\/\* Begin PBXSourcesBuildPhase section \*\/\Z/) {
247 $pbxgroup_state = 5;
248 }
249 } elsif ($pbxgroup_state == 1) {
250 if (/\A\t\t([A-F0-9]{24}) \/\* (.*?) \*\/ \= \{\Z/) {
251 $pbxgroup_state++;
252 $add_to_this_group = $1 eq $grphash;
253 } elsif (/\A\/\* End PBXGroup section \*\/\Z/) {
254 print $fh $newgrptext;
255 $pbxgroup_state = 0;
256 }
257 } elsif ($pbxgroup_state == 2) {
258 if (/\A\t\t\tchildren \= \(\Z/) {
259 $pbxgroup_state++;
260 }
261 } elsif ($pbxgroup_state == 3) {
262 if (/\A\t\t\t\);\Z/) {
263 if ($add_to_this_group) {
264 print $fh "\t\t\t\t$add_to_group_fileref /* $add_to_group_addfname */,\n";
265 }
266 $pbxgroup_state++;
267 }
268 } elsif ($pbxgroup_state == 4) {
269 if (/\A\t\t\};\Z/) {
270 $add_to_this_group = 0;
271 }
272 $pbxgroup_state = 1;
273 } elsif ($pbxgroup_state == 5) {
274 if (/\A\t\t\t\);\Z/) {
275 if ($srcs_or_headers eq 'Sources') {
276 print $fh "\t\t\t\t$buildfileref /* $addfname in $srcs_or_headers */,\n";
277 }
278 $pbxgroup_state = 0;
279 }
280 }
281
282 print $fh "$_\n";
283 }
284
285 close($fh);
286 rename($tmpfname, $pbxprojfname);
287}
288
289my %visualc_references = ();
290sub generate_visualc_id { # these are just standard Windows GUIDs.
291 my @chars = ('0'..'9', 'a'..'f');
292 my $str;
293
294 do {
295 my $len = 24;
296 $str = '0000'; # start and end with '0000' so we know we added it.
297 while ($len--) {
298 $str .= $chars[rand @chars]
299 };
300 $str .= '0000'; # start and end with '0000' so we know we added it.
301 $str =~ s/\A(........)(....)(....)(............)\Z/$1-$2-$3-$4/; # add dashes in the appropriate places.
302 } while (defined($visualc_references{$str}));
303
304 $visualc_references{$str} = 1; # so future calls can't generate this one.
305
306 return $str;
307}
308
309
310sub process_visualstudio {
311 my $addpath = shift;
312 my $vcxprojfname = shift;
313 my $lineno;
314
315 %visualc_references = ();
316
317 my $is_public_header = ($addpath =~ /\Ainclude\/SDL3\//) ? 1 : 0;
318
319 my $addfname = basename($addpath);
320 my $addext = '';
321 if ($addfname =~ /\.(.*?)\Z/) {
322 $addext = $1;
323 }
324
325 my $isheader = 0;
326 if ($addext eq 'c') {
327 $isheader = 0;
328 } elsif ($addext eq 'm') {
329 return; # don't add Objective-C files to Visual Studio projects!
330 } elsif ($addext eq 'h') {
331 $isheader = 1;
332 } else {
333 die("Unexpected file extension '$addext'\n");
334 }
335
336 my $fh;
337
338 open $fh, '<', $vcxprojfname or die("Failed to open '$vcxprojfname': $!\n");
339 chomp(my @vcxproj = <$fh>);
340 close($fh);
341
342 my $vcxgroup_state;
343
344 my $rawaddvcxpath = "$addpath";
345 $rawaddvcxpath =~ s/\//\\/g;
346
347 # Figure out relative path from vcxproj file...
348 my $addvcxpath = '';
349 my @subdirs = split(/\//, $vcxprojfname);
350 pop @subdirs;
351 foreach (@subdirs) {
352 $addvcxpath .= "..\\";
353 }
354 $addvcxpath .= $rawaddvcxpath;
355
356 my $prevname = undef;
357
358 my $tmpfname;
359
360 $tmpfname = "$vcxprojfname.tmp";
361 open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n");
362
363 my $added = 0;
364
365 $added = 0;
366 $vcxgroup_state = 0;
367 $prevname = undef;
368 $lineno = 0;
369 foreach (@vcxproj) {
370 $lineno++;
371 if ($vcxgroup_state == 0) {
372 if (/\A \<ItemGroup\>\Z/) {
373 $vcxgroup_state = 1;
374 $prevname = undef;
375 }
376 } elsif ($vcxgroup_state == 1) {
377 if (/\A \<ClInclude .*\Z/) {
378 $vcxgroup_state = 2 if $isheader;
379 } elsif (/\A \<ClCompile .*\Z/) {
380 $vcxgroup_state = 3 if not $isheader;
381 } elsif (/\A \<\/ItemGroup\>\Z/) {
382 $vcxgroup_state = 0;
383 $prevname = undef;
384 }
385 }
386
387 # Don't do elsif, we need to check this line again.
388 if ($vcxgroup_state == 2) {
389 if (/\A <ClInclude Include="(.*?)" \/\>\Z/) {
390 my $nextname = $1;
391 if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) {
392 print $fh " <ClInclude Include=\"$addvcxpath\" />\n";
393 $vcxgroup_state = 0;
394 $added = 1;
395 }
396 $prevname = $nextname;
397 } elsif (/\A \<\/ItemGroup\>\Z/) {
398 if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) {
399 print $fh " <ClInclude Include=\"$addvcxpath\" />\n";
400 $vcxgroup_state = 0;
401 $added = 1;
402 }
403 }
404 } elsif ($vcxgroup_state == 3) {
405 if (/\A <ClCompile Include="(.*?)" \/\>\Z/) {
406 my $nextname = $1;
407 if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) {
408 print $fh " <ClCompile Include=\"$addvcxpath\" />\n";
409 $vcxgroup_state = 0;
410 $added = 1;
411 }
412 $prevname = $nextname;
413 } elsif (/\A \<\/ItemGroup\>\Z/) {
414 if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) {
415 print $fh " <ClCompile Include=\"$addvcxpath\" />\n";
416 $vcxgroup_state = 0;
417 $added = 1;
418 }
419 }
420 }
421
422 print $fh "$_\n";
423 }
424
425 close($fh);
426 rename($tmpfname, $vcxprojfname);
427
428 my $vcxfiltersfname = "$vcxprojfname.filters";
429 open $fh, '<', $vcxfiltersfname or die("Failed to open '$vcxfiltersfname': $!\n");
430 chomp(my @vcxfilters = <$fh>);
431 close($fh);
432
433 my $newgrptext = '';
434 my $filter = '';
435 if ($is_public_header) {
436 $filter = 'API Headers';
437 } else {
438 $filter = lc(dirname($addpath));
439 $filter =~ s/\Asrc\///; # there's no filter for the base "src/" dir, where SDL.c and friends live.
440 $filter =~ s/\//\\/g;
441 $filter = '' if $filter eq 'src';
442
443 if ($filter ne '') {
444 # see if the filter already exists, otherwise add it.
445 my %existing_filters = ();
446 my $current_filter = '';
447 my $found = 0;
448 foreach (@vcxfilters) {
449 # These lines happen to be unique, so we don't have to parse down to find this section.
450 if (/\A \<Filter Include\="(.*?)"\>\Z/) {
451 $current_filter = lc($1);
452 if ($current_filter eq $filter) {
453 $found = 1;
454 }
455 } elsif (/\A \<UniqueIdentifier\>\{(.*?)\}\<\/UniqueIdentifier\>\Z/) {
456 $visualc_references{$1} = $current_filter; # gather up existing GUIDs to avoid duplicates.
457 $existing_filters{$current_filter} = $1;
458 }
459 }
460
461 if (not $found) { # didn't find it? We need to build filters.
462 my $subpath = '';
463 my @splitpath = split(/\\/, $filter);
464 while (my $elem = shift(@splitpath)) {
465 $subpath .= "\\" if ($subpath ne '');
466 $subpath .= $elem;
467 if (not $existing_filters{$subpath}) {
468 my $newgroupref = generate_visualc_id();
469 $newgrptext .= " <Filter Include=\"$subpath\">\n";
470 $newgrptext .= " <UniqueIdentifier>{$newgroupref}</UniqueIdentifier>\n";
471 $newgrptext .= " </Filter>\n"
472 }
473 }
474 }
475 }
476 }
477
478 $tmpfname = "$vcxfiltersfname.tmp";
479 open $fh, '>', $tmpfname or die("Failed to open '$tmpfname': $!\n");
480
481 $added = 0;
482 $vcxgroup_state = 0;
483 $prevname = undef;
484 $lineno = 0;
485 foreach (@vcxfilters) {
486 $lineno++;
487
488 # We cheat here, because these lines are unique, we don't have to fully parse this file.
489 if ($vcxgroup_state == 0) {
490 if (/\A \<Filter Include\="(.*?)"\>\Z/) {
491 if ($newgrptext ne '') {
492 $vcxgroup_state = 1;
493 $prevname = undef;
494 }
495 } elsif (/\A \<ClInclude .*\Z/) {
496 if ($isheader) {
497 $vcxgroup_state = 2;
498 $prevname = undef;
499 }
500 } elsif (/\A \<ClCompile .*\Z/) {
501 if (not $isheader) {
502 $vcxgroup_state = 3;
503 $prevname = undef;
504 }
505 }
506 }
507
508 # Don't do elsif, we need to check this line again.
509 if ($vcxgroup_state == 1) {
510 if (/\A \<\/ItemGroup\>\Z/) {
511 print $fh $newgrptext;
512 $newgrptext = '';
513 $vcxgroup_state = 0;
514 }
515 } elsif ($vcxgroup_state == 2) {
516 if (/\A <ClInclude Include="(.*?)"/) {
517 my $nextname = $1;
518 if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) {
519 print $fh " <ClInclude Include=\"$addvcxpath\"";
520 if ($filter ne '') {
521 print $fh ">\n";
522 print $fh " <Filter>$filter</Filter>\n";
523 print $fh " </ClInclude>\n";
524 } else {
525 print $fh " />\n";
526 }
527 $added = 1;
528 }
529 $prevname = $nextname;
530 } elsif (/\A \<\/ItemGroup\>\Z/) {
531 if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) {
532 print $fh " <ClInclude Include=\"$addvcxpath\"";
533 if ($filter ne '') {
534 print $fh ">\n";
535 print $fh " <Filter>$filter</Filter>\n";
536 print $fh " </ClInclude>\n";
537 } else {
538 print $fh " />\n";
539 }
540 $added = 1;
541 }
542 $vcxgroup_state = 0;
543 }
544 } elsif ($vcxgroup_state == 3) {
545 if (/\A <ClCompile Include="(.*?)"/) {
546 my $nextname = $1;
547 if ((not $added) && (((not defined $prevname) || (uc($prevname) lt uc($addvcxpath))) && (uc($nextname) gt uc($addvcxpath)))) {
548 print $fh " <ClCompile Include=\"$addvcxpath\"";
549 if ($filter ne '') {
550 print $fh ">\n";
551 print $fh " <Filter>$filter</Filter>\n";
552 print $fh " </ClCompile>\n";
553 } else {
554 print $fh " />\n";
555 }
556 $added = 1;
557 }
558 $prevname = $nextname;
559 } elsif (/\A \<\/ItemGroup\>\Z/) {
560 if ((not $added) && ((not defined $prevname) || (uc($prevname) lt uc($addvcxpath)))) {
561 print $fh " <ClCompile Include=\"$addvcxpath\"";
562 if ($filter ne '') {
563 print $fh ">\n";
564 print $fh " <Filter>$filter</Filter>\n";
565 print $fh " </ClCompile>\n";
566 } else {
567 print $fh " />\n";
568 }
569 $added = 1;
570 }
571 $vcxgroup_state = 0;
572 }
573 }
574
575 print $fh "$_\n";
576 }
577
578 close($fh);
579 rename($tmpfname, $vcxfiltersfname);
580}
581
582
583# Mainline!
584
585chdir(dirname($0)); # assumed to be in build-scripts
586chdir('..'); # head to root of source tree.
587
588foreach (@ARGV) {
589 s/\A\.\///; # Turn "./path/to/file.txt" into "path/to/file.txt"
590 my $arg = $_;
591 process_xcode($arg, 'Xcode/SDL/SDL.xcodeproj/project.pbxproj');
592 process_visualstudio($arg, 'VisualC/SDL/SDL.vcxproj');
593 process_visualstudio($arg, 'VisualC-GDK/SDL/SDL.vcxproj');
594}
595
596print("Done. Please run `git diff` and make sure this looks okay!\n");
597
598exit(0);
599