add-source-to-projects.pl 21 KB

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