Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

684 lines
15 KiB

  1. #!perl
  2. use IO::File;
  3. use File::Basename;
  4. use File::Find;
  5. use Cwd;
  6. use Cwd 'abs_path';
  7. $nprocs=`grep vendor_id /proc/cpuinfo | wc -l `;
  8. $nprocs=~s/[\n\r]//g;
  9. print "$nprocs processors found\n";
  10. #find where to include master make file from
  11. $srcdir=getcwd;
  12. die "can't determine path to src"
  13. unless ($srcdir=~s@/src.*$@/src@);
  14. find( { wanted=> \&handle_vpc_file } ,"$srcdir"); # search through all directories for .vpc files
  15. @MAINTARGETS=("all", "clean", "objs");
  16. @TARGETS=("all", "clean", "objs", "tags");
  17. # now, write a master makefile in each dir, and a master-master makefile in ~/src
  18. foreach $dir ( keys %dir_written )
  19. {
  20. open( MAKEOUT,">$dir/Makefile" ) || die "can't write $dir/Makefile";
  21. foreach $target ( @TARGETS )
  22. {
  23. print MAKEOUT "$target:\n";
  24. foreach $_ (split(/,/,$dir_written{$dir}) )
  25. {
  26. print MAKEOUT "\tmake -j $nprocs -f $_ $target\n" if length($_);
  27. }
  28. }
  29. close MAKEOUT;
  30. }
  31. # now, write a master makefile in ~/src
  32. open( MAKEOUT,">$srcdir/Makefile" ) || die "can't write master makefile to $srcdir";
  33. foreach $target ( @MAINTARGETS )
  34. {
  35. print MAKEOUT "$target:\n";
  36. foreach $dir ( keys %dir_written )
  37. {
  38. print MAKEOUT "\tmake -j $nprocs -C $dir $target #$dir_conf_type{$dir}\n" if ($dir_conf_type{$dir} eq "lib");
  39. }
  40. foreach $dir ( keys %dir_written )
  41. {
  42. print MAKEOUT "\tmake -j $nprocs -C $dir $target #$dir_conf_type{$dir}\n" if ($dir_conf_type{$dir} ne "lib");
  43. }
  44. }
  45. print MAKEOUT "\n\nmakefiles:\n\tperl $srcdir/devtools/bin/vpc2linuxmake.pl\n";
  46. print MAKEOUT "\ntags:\n\trm -f $srcdir/TAGS\n";
  47. print MAKEOUT "\tetags -a -C -o $srcdir/TAGS public/*.cpp public/*.h public/*/*.cpp public/*/*.h common/*.cpp common/*.h\n";
  48. foreach $dir ( keys %dir_written )
  49. {
  50. print MAKEOUT "\tmake -C $dir tags\n";
  51. }
  52. close MAKEOUT;
  53. sub handle_vpc_file
  54. {
  55. # called for each file in the callers dir tree
  56. my $dir=$File::Find::dir;
  57. return if ( $dir=~/vpc_scripts/i );
  58. if ( /_base\.vpc$/i )
  59. {
  60. unless ( /hk_base\.vpc$/i )
  61. {
  62. return;
  63. }
  64. }
  65. if ( /_include\.vpc$/i )
  66. {
  67. unless ( /hk_base\.vpc$/i )
  68. {
  69. return;
  70. }
  71. }
  72. if (/\.vpc$/)
  73. {
  74. (%ignore_file,@DEFINES, @CPPFILES, @CXXFILES,@CFILES, @LITERAL_LIBFILES,@LIBFILES, %define_seen,%macros,%include_seen,@INCLUDEDIRS)=undef;
  75. undef $buildforlinux;
  76. undef $conf_type;
  77. $OptimizerLevel='$(SAFE_OPTFLAGS_GCC_422)';
  78. $SymbolVisibility='hidden';
  79. # some defines to ignore in vpc files when generating linux include files
  80. $define_seen{'WIN32'}=1;
  81. $define_seen{'_WIN32'}=1;
  82. $define_seen{'_WINDOWS'}=1;
  83. $define_seen{'_USRDLL'}=1;
  84. $define_seen{'DEBUG'}=1;
  85. $define_seen{'_DEBUG'}=1;
  86. $define_seen{'NDEBUG'}=1;
  87. $define_seen{'_CRT_SECURE_NO_DEPRECATE'}=1;
  88. $define_seen{'_CRT_NONSTDC_NO_DEPRECATE'}=1;
  89. $define_seen{'fopen'}=1;
  90. #print "$_\n";
  91. &ParseVPC($_);
  92. $pname=lc($pname);
  93. $pname=~s/\s+/_/g;
  94. $pname=~s/[\(\)]//g;
  95. # if anything seen, output a makefile
  96. if ( $buildforlinux && ( @CPPFILES || @CXXFILES || @CFILES || @LIBFILES ) )
  97. {
  98. print STDERR "writing project $pname\n";
  99. $projdir=getcwd;
  100. $projdir=~s@/$@@;
  101. $dir_written{$projdir}.=",$pname.mak";
  102. $dir_conf_type{$projdir}=$conf_type;
  103. &WriteMakefile("$projdir/$pname.mak");
  104. &WriteCodeBlocksProj("$projdir/$pname.cbp");
  105. }
  106. else
  107. {
  108. die "no .lib or source files found in .vpc" if ( $buildforlinux );
  109. }
  110. }
  111. }
  112. sub WriteCodeBlocksProj
  113. {
  114. local($_)=@_;
  115. open(CBPROJ,">$_") || die "can't write $_";
  116. print CBPROJ <<HEADER
  117. <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
  118. <CodeBlocks_project_file>
  119. <FileVersion major="1" minor="6" />
  120. <Project>
  121. <Option title="$pname" />
  122. <Option pch_mode="2" />
  123. <Option compiler="gcc" />
  124. <Build>
  125. <Target title="Release">
  126. </Target>
  127. </Build>
  128. HEADER
  129. ;
  130. foreach $fl (@CPPFILES)
  131. {
  132. push @cppfiles2, $fl unless ( $ignore_file{$fl} > 0 );
  133. }
  134. foreach $fl (@CXXFILES)
  135. {
  136. push @cxxfiles2, $fl unless ( $ignore_file{$fl} > 0 );
  137. }
  138. printf CBPROJ "\t\t<Compiler>\n";
  139. foreach $_ (@DEFINES)
  140. {
  141. print CBPROJ "\t\t\t<Add option=\"-DSWDS\" />\n";
  142. print CBPROJ "\t\t\t<Add option=\"-D_LINUX\" />\n";
  143. print CBPROJ "\t\t\t<Add option=\"-fpermissive\" />\n";
  144. print CBPROJ "\t\t\t<Add option=\"-Dstricmp=strcasecmp\" />\n";
  145. print CBPROJ "\t\t\t<Add option=\"-D_stricmp=strcasecmp\" />\n";
  146. print CBPROJ "\t\t\t<Add option=\"-D_strnicmp=strncasecmp\" />\n";
  147. print CBPROJ "\t\t\t<Add option=\"-Dstrnicmp=strncasecmp\" />\n";
  148. print CBPROJ "\t\t\t<Add option=\"-D_snprintf=snprintf\" />\n";
  149. print CBPROJ "\t\t\t<Add option=\"-D_vsnprintf=vsnprintf\" />\n";
  150. print CBPROJ "\t\t\t<Add option=\"-D_alloca=alloca\" />\n";
  151. print CBPROJ "\t\t\t<Add option=\"-Dstrcmpi=strcasecmp\" />\n";
  152. print CBPROJ "\t\t\t<Add option=\"-D$_\" />\n";
  153. }
  154. foreach $_ (@INCLUDEDIRS)
  155. {
  156. print CBPROJ "\t\t\t<Add directory=\"$_\" />\n";
  157. }
  158. printf CBPROJ "\t\t</Compiler>\n";
  159. @CPPFILES = sort(@CPPFILES);
  160. @CXXFILES = sort(@CXXFILES);
  161. @CFILES = sort(@CFILES);
  162. # now, output obj dependencies
  163. foreach $_ (@CPPFILES, @CFILES, @CXXFILES)
  164. {
  165. unless (( $ignore_file{$_} > 0 ) || ( length($_) < 2 ) )
  166. {
  167. ($filename,$dir,$suffix) = fileparse($_,qr/\.[^.]*/);
  168. print CBPROJ "\t\t<Unit filename=\"".$dir . $filename. ".cpp\" />\n";
  169. }
  170. }
  171. print CBPROJ <<FOOTER
  172. <Extensions>
  173. <code_completion />
  174. </Extensions>
  175. </Project>
  176. </CodeBlocks_project_file>
  177. FOOTER
  178. ;
  179. close CBPROJ;
  180. }
  181. sub WriteMakefile
  182. {
  183. local($_)=@_;
  184. my $objdir ="obj";
  185. open(MAKEFILE,">$_") || die "can't write $_";
  186. print MAKEFILE "NAME=$pname\n\n";
  187. if ( $pname =~ /(server|client)_(\S+)/i )
  188. {
  189. print MAKEFILE "OBJSUFFIX=_$2\n";
  190. $objdir .= "_$2";
  191. }
  192. print MAKEFILE "SRCROOT=$srcdir\n";
  193. print MAKEFILE "PROJDIR=$projdir\n";
  194. print MAKEFILE "CONFTYPE=$conf_type\n";
  195. print MAKEFILE "OptimizerLevel=$OptimizerLevel\n";
  196. print MAKEFILE "SymbolVisibility=$SymbolVisibility\n";
  197. if (@DEFINES)
  198. {
  199. print MAKEFILE "DEFINES= -D",join(" -D", @DEFINES),"\n";
  200. }
  201. if (@INCLUDEDIRS)
  202. {
  203. print MAKEFILE "INCLUDEDIRS= -I",join(" -I", @INCLUDEDIRS),"\n";
  204. }
  205. undef @cppfiles2;
  206. undef @cxxfiles2;
  207. foreach $fl (@CPPFILES)
  208. {
  209. if ( length($fl) )
  210. {
  211. print "warning file $fl does not exist\n" unless( -e $fl);
  212. push @cppfiles2, $fl unless ( $ignore_file{$fl} > 0 );
  213. }
  214. }
  215. foreach $fl (@CXXFILES)
  216. {
  217. push @cxxfiles2, $fl unless ( $ignore_file{$fl} > 0 );
  218. }
  219. if (@cppfiles2)
  220. {
  221. print MAKEFILE "CPPFILES= \\\n ", join(" \\\n ",@cppfiles2), "\n";
  222. }
  223. if (@cxxfiles2)
  224. {
  225. print MAKEFILE "CXXFILES= \\\n ", join(" \\\n ",@cxxfiles2), "\n";
  226. }
  227. if (@CFILES)
  228. {
  229. print MAKEFILE "CFILES= \\\n ", join(" \\\n ",@CFILES), "\n";
  230. }
  231. if (@LIBFILES)
  232. {
  233. undef @LIBNAMES;
  234. print MAKEFILE "\nLIBFILES= \\\n";
  235. unless( $pname=~/(tier0)|(mathlib)|(tier1)/i)
  236. {
  237. print MAKEFILE " $srcdir/lib/linux/tier1_486.a \\\n"
  238. }
  239. foreach $lib (@LIBFILES)
  240. {
  241. my @DLLNAMES=("tier0", "vstdlib", "steam_api");
  242. unless ( $ignore_file{$lib} > 0 )
  243. {
  244. $lib=lc($lib);
  245. my ($filename,$dir,$suffix) = fileparse($lib,qr/\.[^.]*/);
  246. my $dll=0;
  247. foreach $dllname (@DLLNAMES)
  248. {
  249. $dll=1 if ( $dllname eq $filename);
  250. }
  251. if ( $dll )
  252. {
  253. $lib=~s@^.*/([^/]+)\.lib@$1_i486.so@i;
  254. $lib=~s@^.*/lib/(\S+)@$1@g;
  255. }
  256. else
  257. {
  258. $lib=~s/\.lib/_486.a/i;
  259. $lib=~s@/lib/(\S+)/@/lib/linux/@g;
  260. }
  261. push @LIBNAMES, $lib;
  262. }
  263. }
  264. foreach $lib (@LITERAL_LIBFILES)
  265. {
  266. unless ( $ignore_file{$lib} > 0 )
  267. {
  268. $lib=~s/\\/\//g;
  269. $lib=~s@/linux/([a-zA-Z_0-9\.]+)$@/linux/$1@;
  270. $lib=~s@^.*/linux/([a-zA-Z_0-9]+)\.so$@$1.so@;
  271. push @LIBNAMES, $lib;
  272. }
  273. }
  274. # now, sort libs for link order
  275. foreach $lib ( sort bypriority @LIBNAMES )
  276. {
  277. print MAKEFILE " $lib \\\n";
  278. }
  279. print MAKEFILE "\n\n";
  280. }
  281. if ( $conf_type eq "dll" )
  282. {
  283. print MAKEFILE "OUTPUT_SO_FILE=$srcdir/linux/$pname","_i486.so\n\n";
  284. }
  285. elsif ( $conf_type eq "exe" )
  286. {
  287. if ( $macros{'OUTBINNAME'} eq "" )
  288. {
  289. die "Missing OUTBINNAME macro";
  290. }
  291. print MAKEFILE "OUTPUT_EXECUTABLE=$srcdir/linux/$macros{'OUTBINNAME'}\n\n";
  292. }
  293. print MAKEFILE "\n\n\# include base make file\ninclude $srcdir/devtools/makefile_base_linux.mak\n";
  294. # now, output obj dependencies
  295. foreach $_ (@CPPFILES, @CFILES)
  296. {
  297. unless (( $ignore_file{$_} > 0 ) || ( length($_) < 2 ) )
  298. {
  299. ($filename) = fileparse($_,qr/\.[^.]*/);
  300. print MAKEFILE getcwd,"/$objdir/$filename.o : $_\n\t\$(DO_CC)\n";
  301. }
  302. }
  303. foreach $_ (@CXXFILES)
  304. {
  305. unless (( $ignore_file{$_} > 0 ) || ( length($_) < 2 ) )
  306. {
  307. ($filename) = fileparse($_,qr/\.[^.]*/);
  308. print MAKEFILE getcwd,"/$objdir/$filename.oxx : $_\n\t\$(DO_CC)\n";
  309. }
  310. }
  311. close MAKEFILE;
  312. }
  313. sub bypriority
  314. {
  315. # sort libs for gcc linkgoodness
  316. $priority{"mathlib"}="0005";
  317. $priority{"tier1"}="0010";
  318. $priority{"tier2"}="0020";
  319. $priority{"tier3"}="0030";
  320. my ($filenamea) = fileparse($a,qr/\.[^.]*/);
  321. my ($filenameb) = fileparse($b,qr/\.[^.]*/);
  322. $filenamea =~ s/_.86.*$//; # lose _i486
  323. $filenameb =~ s/_.86.*$//;
  324. my $pa=$priority{$filenamea} || 1000;
  325. my $pb=$priority{$filenameb} || 1000;
  326. return $pb cmp $pa;
  327. }
  328. sub ParseVPC
  329. {
  330. local($fname)=@_;
  331. &startreading($fname);
  332. while(&nextvpcline)
  333. {
  334. # print "$fname - $_\n";
  335. if ( (/^\$linux/i) )
  336. {
  337. &skipblock(0,\&handlelinuxline);
  338. }
  339. if ( (/^\$configuration/i) )
  340. {
  341. &skipblock(0,\&handleconfigline);
  342. }
  343. elsif (/^\s*\$project/i)
  344. {
  345. &parseproject;
  346. }
  347. }
  348. }
  349. sub massageline
  350. {
  351. # strip leading and trailing spaces and carriage returns and comments from vpc lines
  352. s/[\n\r]//g;
  353. s@//.*$@@g;
  354. s@^\s*@@g;
  355. s@\s*$@@g;
  356. }
  357. sub submacros
  358. {
  359. # replace all macros within a line
  360. my $mac;
  361. foreach $mac (keys %macros)
  362. {
  363. s/\$$mac/$macros{$mac}/g;
  364. }
  365. }
  366. sub startreading
  367. {
  368. # initialize recursive file reader
  369. my( $fname)=@_;
  370. #print STDERR "opening $fname\n";
  371. $curfile=IO::File->new($fname) || die "can't open $fname";
  372. }
  373. sub nextvpcline
  374. {
  375. # get the next line from the file, handling line continuations, macro substitution, and $include
  376. # return 0 if out of lines
  377. my $ret=0;
  378. if ( $_ = <$curfile> )
  379. {
  380. $ret=1;
  381. &massageline;
  382. while(s@\\$@ @)
  383. {
  384. my $old=$_;
  385. $_=<$curfile>;
  386. &massageline;
  387. $_=$old.$_;
  388. }
  389. s@\s+@ @g;
  390. my $old=$_;
  391. &submacros;
  392. # now, parse
  393. if (/\$macro (\S+) \"(\S+)\"$/i)
  394. {
  395. $macros{$1}=$2;
  396. return &nextvpcline;
  397. }
  398. s/\[\$WIN32\]//g;
  399. return &nextvpcline if (/\[\$X360\]/);
  400. if ( /^\s*\$include\s+\"(.*)\"/i)
  401. {
  402. # process $include
  403. my $incfile=$1;
  404. push @filestack, $curfile;
  405. $incfile=~s@\\@/@g;
  406. #print STDERR "opening $incfile\n";
  407. #$curfile=IO::File->new($incfile) || die "can't open include $incfile ($pname)";
  408. if ( -e $incfile )
  409. {
  410. push @filestack, $curfile;
  411. #print STDERR "opening $incfile\n";
  412. $curfile=IO::File->new($incfile) || die "can't open include $incfile";
  413. }
  414. else
  415. {
  416. print "can't find include $incfile, ignoring\n";
  417. }
  418. return &nextvpcline;
  419. }
  420. }
  421. else
  422. {
  423. $curfile->close;
  424. if (@filestack)
  425. {
  426. $curfile=pop(@filestack);
  427. return &nextvpcline;
  428. }
  429. else
  430. {
  431. return 0;
  432. }
  433. }
  434. return $ret;
  435. }
  436. sub skipblock
  437. {
  438. # skip a named block in the key values, handling nested {} pairs
  439. my($empty_ok, $callback)=@_;
  440. my $lnstat=&nextvpcline;
  441. die "parse error eof in block" if ( (! $lnstat) && ( ! $empty_ok) );
  442. my $nest=0;
  443. if (/^\{/)
  444. {
  445. $nest++;
  446. }
  447. else
  448. {
  449. die "no start block found, $_ found instead" unless($empty_ok);
  450. }
  451. while ($nest)
  452. {
  453. die "prematur eof" unless &nextvpcline;
  454. &$callback($_) if ( $callback );
  455. $nest++ if (/^\{/);
  456. $nest-- if (/^\}/);
  457. }
  458. }
  459. sub parseproject
  460. {
  461. # handle a project block, picking up files mentioned
  462. $pname="";
  463. $pname=$1 if (/^\s*\$project\s*\"(.*)\"/i);
  464. local($_);
  465. my $nest=0;
  466. &nextvpcline || die "empty project?";
  467. $nest++ if (/^\s*\{/);
  468. while($nest )
  469. {
  470. &nextvpcline || die "premature eof in project?";
  471. $nest++ if (/^\{/);
  472. $nest-- if (/^\}/);
  473. &CheckForFileLine($_);
  474. }
  475. }
  476. sub CheckForFileLine
  477. {
  478. local($_)=@_;
  479. if (/^\s*\-\$File\s+(.*$)/i)
  480. {
  481. foreach $_ (split(/ /,$1))
  482. {
  483. s/\"//g;
  484. $ignore_file{&process_path($_)} = 1;
  485. }
  486. }
  487. elsif (/^\s*\$File\s+(.*$)/i)
  488. {
  489. foreach $_ (split(/ /,$1))
  490. {
  491. s/\"//g;
  492. &handlefile($_);
  493. }
  494. }
  495. }
  496. sub handlefile
  497. {
  498. # given a project file (.cpp, etc), figure out what to do with it
  499. local($_)=@_;
  500. # hardcoded exclusions for linux
  501. return if (/dx9sdk/i);
  502. return if (/_360/i);
  503. return if (/xbox_console.cpp/i);
  504. return if (/xbox_system.cpp/i);
  505. return if (/xbox_win32stubs.cpp/i);
  506. return if (/binkw32/i || /binkxenon/i );
  507. if (/\.cpp$/)
  508. {
  509. push @CPPFILES,process_path($_);
  510. }
  511. if (/\.cxx$/)
  512. {
  513. push @CXXFILES,process_path($_);
  514. }
  515. elsif (/\.c$/)
  516. {
  517. push @CFILES,process_path($_);
  518. }
  519. elsif (/\.lib$/)
  520. {
  521. push @LIBFILES,process_path($_);
  522. }
  523. elsif (/\.a$/)
  524. {
  525. push @LITERAL_LIBFILES, process_path($_);
  526. }
  527. elsif (/\.so$/)
  528. {
  529. push @LITERAL_LIBFILES, process_path($_);
  530. }
  531. }
  532. sub process_path
  533. {
  534. local($_)=@_;
  535. s@\\@/@g;
  536. if ( (! -e $_) && ( -e lc($_)) )
  537. {
  538. # print STDERR "$_ does not exist try lc($_)\n";
  539. $_=lc($_);
  540. }
  541. my $ap=abs_path($_);
  542. if ( (! length($ap) ) && length($_))
  543. {
  544. # print "abs path of $_ is empty. bad dir?\n";
  545. }
  546. $_=$ap;
  547. s@i686@i486@g;
  548. if ( (! -e $_) && ( -e lc($_)) )
  549. {
  550. # print STDERR "$_ does not exist try lc($_)\n";
  551. $_=lc($_);
  552. }
  553. # kill ..s for prettyness
  554. s@/[^/]+/\.\./@/@g;
  555. if (! -e $_)
  556. {
  557. # print STDERR "$_ does not exist\n";
  558. }
  559. return $_;
  560. }
  561. sub handlelinuxline
  562. {
  563. local($_)=@_;
  564. $buildforlinux = 1 if ( /^\s*\$buildforlinux.*1/i);
  565. $OptimizerLevel= $1 if (/^\s*\$OptimizerLevel\s+(.+)/i);
  566. $SymbolVisibility = $1 if (/^\s*\$SymbolVisibility\s+(.+)/i);
  567. $buildforlinux = 1 if ( /^\s*\$buildforlinux.*1/i);
  568. &CheckForFileLine($_); # allows linux-specific file includes and excludes
  569. &handleconfigline($_); # allow linux-specific #defines
  570. }
  571. sub CheckPreprocessorDefs
  572. {
  573. local($_)=@_;
  574. if (/^\s*\$PreprocessorDefinitions\s+\"(.*)\"/i)
  575. {
  576. foreach $_ (split(/[;,]/,$1) )
  577. {
  578. unless( /\$/ || $define_seen{$_} || /fopen/i)
  579. {
  580. push(@DEFINES,$_);
  581. $define_seen{$_}=1;
  582. }
  583. }
  584. }
  585. }
  586. sub handleconfigline
  587. {
  588. # handle a line within a $Configuration block
  589. local($_)=@_; # the line
  590. if (/^\s*\$AdditionalIncludeDirectories\s+\"(.*)\"/i)
  591. {
  592. foreach $_ (split(/[;,]/,$1) )
  593. {
  594. unless( /\$/ || $include_seen{$_} )
  595. {
  596. push(@INCLUDEDIRS,process_path($_));
  597. $include_seen{$_}=1;
  598. }
  599. }
  600. }
  601. if (/^\s*\$ConfigurationType\s*\"(.*)\"/)
  602. {
  603. undef $conf_type;
  604. $conf_type="lib" if ($1 =~ /Static Library/i);
  605. $conf_type="dll" if ($1 =~ /Dynamic Library/i);
  606. $conf_type="exe" if ($1 =~ /Application/i);
  607. print STDERR " unknown conf type $1\n" if (! length($conf_type) );
  608. }
  609. &CheckPreprocessorDefs($_);
  610. }