PageRenderTime 69ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/pmake

https://bitbucket.org/ImmortalPC/calcucomplex
PHP | 1410 lines | 982 code | 148 blank | 280 comment | 159 complexity | 277f572d197a617d0a9e0bfff4afe92f MD5 | raw file
  1. #!/usr/bin/php5
  2. <?php
  3. /*******************************************************************************
  4. * pmake config
  5. *
  6. * Liste des variables:
  7. * OBJ_DIR {String} Dossier des objets
  8. * BIN_DIR {String} Dossier de l'executable
  9. * EXEC_NAME {String} Nom de l'executable
  10. * SRC {String} Sources (Peut être: une suite fichiers / dossiers, un masque. ( 'file1.cpp file2.cpp file\ 3.cpp directory/*.cpp' ))
  11. * SRC_RECURSIV {Bool} If there is a directory in SRC => recurse ?
  12. * INCLUDE_DIR {String} Dossier a inclure pour la recherche
  13. * LIBS {String} Librairie a link
  14. * CONSOLE {Bool} Afficher la console ? ( Aucun effet sous UNIX )
  15. * CFLAGS {String} Flags a passer a gcc/g++
  16. * LDFLAGS {String} Flags a passer au linker (ld)
  17. * CMD_AFTER {Array} Commandes a executer après une compilation réussi. ( PAS DE PRISE EN CHARGE POUR '+' ( concat ) )
  18. * Il est aussi a noter que l'on peut utiliser les variables de cette liste. ($LIBS sera remplacé)
  19. *
  20. * Le parser analyse les options dans l'odre suivant:
  21. * 1) $_CONFIG['global'][OPTION]
  22. * 2) $_CONFIG['global'][release|debug][OPTION]
  23. * 3) $_CONFIG[win|unix][OPTION]
  24. * 4) $_CONFIG[win|unix][release|debug][OPTION]
  25. * Les étapes remplaces la valeur précédante. ( Donc si vous avez def LIBS dans 1,2,3,4 alors on ne vera que la LIB de l'etape 4 )
  26. * Pour concaténer les valeurs, ajouter +
  27. * ex:
  28. * $_CONFIG['global']['OBJ_DIR'] = 'obj/';
  29. * $_CONFIG['global']['release']['OBJ_DIR'] = '+release/';
  30. * $_CONFIG['global']['debug']['OBJ_DIR'] = '+debug/';
  31. * // Ainsi, avec cette exemple en mode release, on aura OBJ_DIR = obj/release/
  32. * // NOTE: si on ajoute un espace '+ release/' => obj/ release/
  33. */
  34. $_CONFIG = array(
  35. 'global' => array(
  36. 'OBJ_DIR' => 'obj/'
  37. ,'BIN_DIR' => 'bin/'
  38. ,'EXEC_NAME' => 'mturing'
  39. ,'SRC' => 'src/*.c'
  40. ,'SRC_RECURSIV' => true
  41. ,'INCLUDE_DIR' => 'src'
  42. ,'LIBS' => ''
  43. ,'CONSOLE' => true
  44. ,'CFLAGS' => '-W -Wall -Wextra -Wdeprecated -Wuninitialized -Wunused-variable -Wvariadic-macros -Wredundant-decls -Wunused-macros -Wundef'
  45. //.' -Wlogical-op -Wdouble-promotion'
  46. .' -Wfloat-equal'//avertit si l'on teste l'égalité de deux nombres à virgule.
  47. .' -Wwrite-strings'
  48. .' -Wredundant-decls -Winit-self'
  49. //.' -Winline'// Avertis si une fonction demandé inline n'a pas été inline
  50. .' -Wpointer-arith'//qui affiche des messages si l'on fait des calculs du type pointeur + nombre
  51. //.' -Wcast-qual'//qui affiche des messages si l'on convertit un pointeur sur une constante en un pointeur sur une variable non constante
  52. .' -Wcast-align'// qui affiche des messages si l'on convertit des pointeurs d'un type à l'autre alors que leur taille en mémoire est différente (par exemple de char* vers int*).
  53. //.' -Wshadow'// affiche un message s'il y a deux variables de même nom dans la même portion de code.
  54. .' -std=c99'
  55. ,'release' => array(
  56. 'OBJ_DIR' => '+release/'
  57. ,'CFLAGS' => '+ -Os -fdata-sections -ffunction-sections'// Ligne d'optimisation
  58. ,'LDFLAGS' => '+ -s -Wl,--gc-sections -Wl,-O1'// Ligne d'optimisation: -s <=> strip --strip-unneeded
  59. //,'CMD_AFTER'=> array('strip --strip-unneeded $BIN_DIR$EXEC_NAME')// On remove tout les symboles
  60. )
  61. ,'debug' => array(
  62. 'OBJ_DIR' => '+debug/'
  63. ,'CFLAGS' => '+ -ggdb3'// -D_GLIBCXX_DEBUG pour le debug de la std lib (NON compactible avec OIS)
  64. ,'EXEC_NAME'=> '+_d'
  65. )
  66. ),
  67. 'win' => array(
  68. 'INCLUDE_DIR' => ''
  69. ,'EXEC_NAME' => '+.exe'
  70. ,'LDFLAGS' => ''
  71. ,'release' => array(
  72. 'CONSOLE' => false
  73. )
  74. ,'debug' => array(
  75. 'LDFLAGS' => '+ -rdynamic -Wl,--export-all-symbols'
  76. ,'CONSOLE' => true
  77. )
  78. ),
  79. 'unix' => array(
  80. 'INCLUDE_DIR' => ''// /usr/include
  81. //'INCLUDE_DIR' => '+ /usr/i586-mingw32msvc/include/OGRE/ /usr/i586-mingw32msvc/include/OIS/'// /usr/include
  82. //,'LDFLAGS' => '+ -Wl,--enable-auto-image-base -Wl,--add-stdcall-alias -Wl,--enable-auto-import'
  83. ,'release' => array()
  84. ,'debug' => array(
  85. 'LDFLAGS' => '+ -rdynamic'
  86. )
  87. )
  88. );
  89. // If TRUE => the project will always be compiled in debug mode
  90. define('FORCE_DEBUG_MODE', false);
  91. // Compil
  92. define('CXX', '/usr/bin/gcc');
  93. //define('CXX', 'i586-mingw32msvc-c++');
  94. define('USE_THREAD', 2);// Forcer N thread pour la compilation
  95. // Inclure tout les includes ( même systeme ) lors de la génération des dépendances ?
  96. // Cela peut prendre beaucoup de temps !
  97. // OBLIGATOIRE aver clang++
  98. define('GEN_DEP_WITH_ALL_INCLUDE', false);
  99. // Compiler en 64bits ?
  100. // Cette fonction ne marche que si le système est en 64bits
  101. define('BUILD_64BYTES', false);
  102. /*******************************************************************************
  103. * DO NOT TOUCH
  104. */
  105. define('OS_UNIX', 0);
  106. define('OS_WINDOWS', 1);
  107. define('OS_RUNNING', (PHP_SHLIB_SUFFIX === 'dll')?1:0);// Permet de savoir quel OS TOURNE
  108. define('CONSOLE_WIDTH', 80);
  109. define('MAKEFILE_TIME', filemtime(__FILE__));//!< Dernière modification du makefile
  110. define('ENABLED_COLOR', OS_RUNNING === OS_UNIX && !in_array('noColor', $argv));
  111. // Mode debug ?
  112. define('IS_DEBUG_MODE', in_array('debug', $argv) || FORCE_DEBUG_MODE);
  113. define('IS_VERBOSE_MODE', in_array('verbose', $argv) || in_array('v', $argv));
  114. if( function_exists('pcntl_fork') && OS_RUNNING !== OS_WINDOWS ){
  115. // On détermine le nombre de thread a utiliser
  116. foreach( $argv as $val )
  117. {
  118. if( substr($val, 0, 2) === '-j' ){
  119. $val = intval(substr($val, 2));
  120. if( $val <= 0 ){
  121. define('NB_THREAD', 1);
  122. }else{
  123. define('NB_THREAD', $val);
  124. }
  125. break;
  126. }
  127. }
  128. if( !defined('NB_THREAD') ){
  129. if( defined('USE_THREAD') ){
  130. define('NB_THREAD', USE_THREAD);
  131. }else{
  132. define('NB_THREAD', 1);
  133. }
  134. }
  135. }else{
  136. define('NB_THREAD', 1);
  137. }
  138. if( NB_THREAD > 1 )
  139. Thread::init();
  140. $_CMD_AFTER = array();//!< Liste des commandes a exec après une compilation
  141. if( OS_RUNNING === OS_WINDOWS )
  142. execute('@chcp 1252 > nul');// On permet a la console de window de prendre en compte les accents
  143. if( BUILD_64BYTES && is_64bit() ){
  144. if( !IsSet($_CONFIG['global']) )
  145. $_CONFIG['global'] = array();
  146. if( !IsSet($_CONFIG['global']) )
  147. $_CONFIG['global']['CFLAGS'] = '';
  148. $_CONFIG['global']['CFLAGS'] .= ' -m64';
  149. if( !IsSet($_CONFIG['global']) )
  150. $_CONFIG['global']['LDFLAGS'] = '';
  151. $_CONFIG['global']['LDFLAGS'] .= ' -m64';
  152. }
  153. /*******************************************************************************
  154. * Color list
  155. */
  156. if( OS_RUNNING === OS_UNIX ){
  157. define('COLOR_BLACK', 0);
  158. define('COLOR_RED', 1);
  159. define('COLOR_GREEN', 2);
  160. define('COLOR_YELLOW', 3);
  161. define('COLOR_BLUE', 4);
  162. define('COLOR_MAGENTA', 5);
  163. define('COLOR_CYAN', 6);
  164. define('COLOR_WHITE', 7);
  165. }else{
  166. define('COLOR_BLACK', '0F');
  167. define('COLOR_RED', 'C0');
  168. define('COLOR_GREEN', '20');
  169. define('COLOR_YELLOW', 'E0');
  170. define('COLOR_BLUE', '10');
  171. define('COLOR_MAGENTA', '90');
  172. define('COLOR_CYAN', 'B0');
  173. define('COLOR_WHITE', 'F0');
  174. /*
  175. 0 = Noir 8 = Gris
  176. 1 = Bleu fonc‚ 9 = Bleu clair
  177. 2 = Vert A = Vert clair
  178. 3 = Bleu-gris B = Cyan
  179. 4 = Marron C = Rouge
  180. 5 = Pourpre D = Rose
  181. 6 = Kaki E = Jaune
  182. 7 = Gris clair F = Blanc
  183. */
  184. }
  185. // On parse les options
  186. parseOptions();
  187. /*******************************************************************************
  188. * Affichage de l'aide
  189. */
  190. if( in_array('help', $argv) || in_array('-help', $argv) || in_array('--help', $argv) || in_array('-h', $argv) || in_array('/?', $argv) )
  191. showHelp();
  192. /*******************************************************************************
  193. * Re build
  194. */
  195. if( in_array('re', $argv) || in_array('rebuild', $argv) )
  196. execute(__FILE__.' clean '.(IS_DEBUG_MODE?'debug':''));
  197. /*******************************************************************************
  198. * Nétoyage
  199. */
  200. if( in_array('clean', $argv) || in_array('clear', $argv) || in_array('ca', $argv) || in_array('cleanall', $argv) ){
  201. rrmdir(OBJ_DIR);
  202. if( in_array('all', $argv) || in_array('ca', $argv) || in_array('cleanall', $argv) ){
  203. $OS = (OS_RUNNING === OS_UNIX)?'unix':'win';
  204. $MODE = (!IS_DEBUG_MODE)?'debug':'release';
  205. if( IsSet($_CONFIG['global']) ){
  206. if( IsSet($_CONFIG['global']['OBJ_DIR']) )
  207. $OBJ = $_CONFIG['global']['OBJ_DIR'];
  208. if( IsSet($_CONFIG['global'][$MODE],$_CONFIG['global'][$MODE]['OBJ_DIR']) )
  209. appendOrReset($OBJ, $_CONFIG['global'][$MODE]['OBJ_DIR']);
  210. }
  211. if( IsSet($_CONFIG[$OS]) ){
  212. if( IsSet($_CONFIG[$OS]['OBJ_DIR']) )
  213. appendOrReset($OBJ, $_CONFIG[$OS]['OBJ_DIR']);
  214. if( IsSet($_CONFIG[$OS][$MODE],$_CONFIG[$OS][$MODE]['OBJ_DIR']) )
  215. appendOrReset($OBJ, $_CONFIG[$OS][$MODE]['OBJ_DIR']);
  216. }
  217. rrmdir($OBJ);
  218. }
  219. exit;
  220. }
  221. /*******************************************************************************
  222. * On génère les dépendances
  223. */
  224. $INCLUDE_DIR = array('local'=>'', 'system'=>'');
  225. // On détermine les dossiers a inclure
  226. if( strlen(INCLUDE_DIR) ){
  227. foreach( split_RespectEscape(INCLUDE_DIR) as $val )
  228. {
  229. if( substr($val, 0, 1) === '/' || (OS_RUNNING === OS_WINDOWS && substr($val, 1, 2) === ':/') ){
  230. $INCLUDE_DIR['system'] .= ' -isystem '.$val;// Les lib externes sont considérés comme fiables => no warning
  231. }else{
  232. $INCLUDE_DIR['local'] .= ' -I'.$val;
  233. }
  234. }
  235. }
  236. $INCLUDE_DIR['system'] = trim($INCLUDE_DIR['system']);
  237. $INCLUDE_DIR['local'] = trim($INCLUDE_DIR['local']);
  238. /*******************************************************************************
  239. * Création des dossiers manquant
  240. */
  241. makeDir(OBJ_DIR);
  242. makeDir(BIN_DIR);
  243. // Contient la liste des fichiers a traiter
  244. $fileList = getListOfFile(SRC);
  245. $time = time();
  246. /*******************************************************************************
  247. * On génère les dépendances
  248. */
  249. $returned = null;
  250. $cmd = '';
  251. $stdout = '';
  252. $stderr = '';
  253. echo cutOrFill('Génération des dépendances', CONSOLE_WIDTH-3),(IS_VERBOSE_MODE?"\r\n":'[');
  254. if( GEN_DEP_WITH_ALL_INCLUDE ){
  255. $cmd = CXX.' '.implode(' ',$INCLUDE_DIR).' -MM '.implode(' ', array_keys($fileList));
  256. }else{
  257. $cmd = CXX.' '.$INCLUDE_DIR['local'].' -MM '.implode(' ', array_keys($fileList));
  258. }
  259. if( IS_VERBOSE_MODE )//implode(' ',$INCLUDE_DIR)
  260. echo $cmd,"\r\n";
  261. // Version remplacant la version commenté qui suit. Cette version ne provoque pas de "Broken pipe"
  262. $stderrFile = tempnam(sys_get_temp_dir(), 'pmake');// Création d'un recepteur temporaire
  263. exec($cmd.' 2> '.$stderrFile, $stdout, $returned);// Génération des dépendances
  264. $stderr = file_get_contents($stderrFile);// On lit le "flux" d'erreur
  265. unlink($stderrFile);// Fermeture du "flux" d'erreur
  266. if( $returned !== 0 || !empty($stderr) ){
  267. if( $returned !== 0 ){
  268. echo (IS_VERBOSE_MODE?'[':''),color('FAIL', COLOR_RED),"]\r\n";
  269. }else{
  270. echo (IS_VERBOSE_MODE?'[':''),color('WARNING', COLOR_YELLOW),"]\r\n";
  271. }
  272. echo str_replace(array('fatal error','^','not found'), array(color('fatal error', COLOR_RED),color('^', COLOR_GREEN),color('not found', COLOR_RED, true)), $stderr);
  273. if( $returned !== 0 )
  274. exit($returned);
  275. }
  276. unset($stderr,$returned,$stderrFile,$cmd);
  277. /*// Ne pas utiliser cette version. Provoque un "Broken pipe" avec clang++
  278. // On lance la commande de génération des dépendances. Si elle plante => on arrête tout
  279. if( ($returned=execute($cmd, null, $stdout, $stderr)) !== 0 || !empty($stderr) ){
  280. echo (IS_VERBOSE_MODE?'[':''),color('FAIL', COLOR_RED),"]\r\n",str_replace(array('fatal error','^','not found'), array(color('fatal error', COLOR_RED),color('^', COLOR_GREEN),color('not found', COLOR_RED, true)), $stderr);
  281. exit($returned);
  282. }
  283. $stdout = explode("\n", trim($stdout));
  284. //*/
  285. for( $i=0; $i<count($stdout); $i++ )
  286. {
  287. if( substr(trim($stdout[$i]), -1, 1) === '\\' ){
  288. $stdout[$i] = trim(substr($stdout[$i], 0, -2)).' '.trim($stdout[$i+1]);
  289. array_splice($stdout, $i+1, 1);
  290. $i--;
  291. }
  292. }
  293. unset($i);
  294. /*******************************************************************************
  295. * Traitement des dépendances
  296. */
  297. $EXEC_DEP = array();
  298. foreach( $stdout as $key => &$val )
  299. {
  300. $tmp = explode(':', $val);
  301. $tmp[1] = split_RespectEscape(trim($tmp[1]));
  302. // On cherche a supprimer les redondances. Ex: src/../Block.h et src/Block.h
  303. $simplify = array();
  304. foreach( $tmp[1] as &$path )
  305. $simplify[relativePath($path)] = true;
  306. $fileList[$tmp[1][0]] = array_keys($simplify);
  307. $fileList[$tmp[1][0]]['obj'] = OBJ_DIR.$tmp[0];
  308. $EXEC_DEP[] = OBJ_DIR.$tmp[0];
  309. unset($simplify, $tmp);
  310. }
  311. unset($tmp,$stdout,$key,$val);
  312. echo color(time()-$time, COLOR_GREEN)," sec]\r\n";
  313. /*******************************************************************************
  314. * Word Count
  315. */
  316. if( in_array('wc', $argv) ){
  317. echo center('Number of lines for the project '.EXEC_NAME, COLOR_MAGENTA, true),"\r\n";
  318. $nbLine = 0;
  319. $n = 0;
  320. $READ = array();
  321. foreach( $fileList as $file => $val )
  322. {
  323. for( $i=0,$size=count($val)-1; $i<$size; $i++ )
  324. {
  325. $val[$i] = relativePath($val[$i]);
  326. if( !IsSet($READ[$val[$i]]) ){
  327. $READ[$val[$i]] = count(file($val[$i]));
  328. echo cutOrFill($val[$i], CONSOLE_WIDTH-3),$READ[$val[$i]],"\r\n";
  329. $nbLine += $READ[$val[$i]];
  330. }
  331. }
  332. }
  333. echo cutOrFill('Total', CONSOLE_WIDTH-3),color($nbLine, COLOR_GREEN, true),"\r\n";
  334. exit;
  335. }
  336. /*******************************************************************************
  337. * Lancement de CppCheck
  338. */
  339. if( in_array('cppcheck', $argv) ){
  340. echo 'Running CppCheck',"\r\n";
  341. // Génération des fichiers a analyser
  342. $tmp = array();
  343. foreach( $fileList as $key => $list )
  344. for( $i=0, $size=count($list)-1; $i<$size; $i++ )
  345. $tmp[$list[$i]] = true;
  346. $tmp = implode(' ', array_keys($tmp));
  347. if( IS_VERBOSE_MODE )
  348. echo 'cppcheck --enable=all -q ',$tmp,"\r\n";
  349. execute('cppcheck --enable=all -q '.$tmp);
  350. exit;
  351. }
  352. // Compilation des objets
  353. $incl = implode(' ', $INCLUDE_DIR);
  354. /*******************************************************************************
  355. * Lancement du générateur de makefile
  356. */
  357. if( in_array('makefile', $argv) ){
  358. echo 'Running makefile generator',"\r\n";
  359. $EXEC_DEP = implode(' ', $EXEC_DEP);
  360. $makefile = 'ifeq ($(SHELL), sh.exe)'."\r\n"
  361. ."\t".'CMD_DEL = del /F /Q'."\r\n"
  362. .'else'."\r\n"
  363. ."\t".'CMD_DEL = rm -f'."\r\n"
  364. .'endif'."\r\n"
  365. .'all: '.BIN_DIR.EXEC_NAME."\r\n"
  366. ."\t".'@echo Done'."\r\n"
  367. .BIN_DIR.EXEC_NAME.': '.BIN_DIR.' '.OBJ_DIR.' '.$EXEC_DEP."\r\n"
  368. ."\t".'@echo Compilation de '.BIN_DIR.EXEC_NAME."\r\n"
  369. ."\t".CXX.' '.LDFLAGS.' -o '.BIN_DIR.EXEC_NAME.' '.$EXEC_DEP.' '.LIBS."\r\n"
  370. .rtrim(BIN_DIR,'/ ').':'."\r\n"
  371. ."\t".'@echo Création du dossier: '.BIN_DIR."\r\n";
  372. $fullPath = '';
  373. foreach( explode('/', rtrim(BIN_DIR,'/ ')) as $dir )
  374. {
  375. $makefile .= "\t".'@mkdir '.$fullPath.$dir."\r\n";
  376. $fullPath .= $dir.'/';
  377. }
  378. $makefile .= rtrim(OBJ_DIR,'/ ').':'."\r\n"
  379. ."\t".'@echo Création du dossier: '.OBJ_DIR."\r\n";
  380. $fullPath = '';
  381. foreach( explode('/', rtrim(OBJ_DIR,'/ ')) as $dir )
  382. {
  383. $makefile .= "\t".'@mkdir '.$fullPath.$dir."\r\n";
  384. $fullPath .= $dir.'/';
  385. }
  386. $tmp = null;
  387. $obj = null;
  388. foreach( $fileList as $file => $list )
  389. {
  390. $obj = $list['obj'];
  391. unset($list['obj']);
  392. $makefile .= $obj.': '.implode(' ', $list)."\r\n"
  393. ."\t".'@echo Compilation de '.$file."\r\n"
  394. ."\t".CXX.' '.$incl.' '.CFLAGS.' -c -pipe '.$file.' -o '.$obj."\r\n";
  395. }
  396. // Création de la règle make clean
  397. $makefile .= 'clean:'."\r\n"
  398. ."\t".'@echo Suppression des fichiers temporaires'."\r\n"
  399. ."\t".'$(CMD_DEL) '.$EXEC_DEP."\r\n";
  400. // Création de la règle make exec
  401. $makefile .= 'exec: '.BIN_DIR.EXEC_NAME."\r\n"
  402. ."\t".'cd '.BIN_DIR.' && '.((OS_RUNNING === OS_UNIX)?'./':'').EXEC_NAME."\r\n";
  403. file_put_contents('Makefile', $makefile);
  404. exit('Done'."\r\n");
  405. }
  406. $time = time();
  407. /*******************************************************************************
  408. * Compilation
  409. */
  410. foreach( $fileList as $file => $dep )
  411. {
  412. if( isMakeNeeded($dep['obj'], $dep) ){
  413. if( NB_THREAD === 1 ){
  414. compile(CXX.' '.$incl.' '.CFLAGS.' -c -pipe '.$file.' -o '.$dep['obj'], $file, $dep['obj']);
  415. }else{
  416. echo '* Processing for : ',$file,"\r\n";
  417. Thread::start('compile', array('cmd'=>CXX.' '.$incl.' '.CFLAGS.' -c -pipe '.$file.' -o '.$dep['obj'], 'file'=>$file, 'target'=>$dep['obj'], 'waitForPrint'=>true));
  418. }
  419. }
  420. if( NB_THREAD > 1 )
  421. Thread::wait();
  422. }
  423. unset($INCLUDE_DIR, $file, $dep);
  424. // On wait tout les thread
  425. if( NB_THREAD > 1 )
  426. Thread::wait(true);
  427. // Compilation du fichier final
  428. $EXEC_DEP[] = '';// Pour compenser le -1
  429. if( isMakeNeeded(BIN_DIR.EXEC_NAME, $EXEC_DEP) ){
  430. compile(CXX.' '.LDFLAGS.' -o '.BIN_DIR.EXEC_NAME.' '.implode(' ', $EXEC_DEP).' '.LIBS, BIN_DIR.EXEC_NAME, BIN_DIR.EXEC_NAME);
  431. }else{
  432. echo cutOrFill(BIN_DIR.EXEC_NAME, CONSOLE_WIDTH-3),'[',color('ALL READY DONE', COLOR_YELLOW),"]\r\n";
  433. }
  434. unset($EXEC_DEP);
  435. echo 'Done in ',(time()-$time),'secs',"\r\n";
  436. /*******************************************************************************
  437. * Lancement des commandes suplémentaires
  438. */
  439. $SRC = trim(implode(' ', array_keys($fileList)));
  440. unset($fileList, $key, $val);
  441. foreach( $_CMD_AFTER as $key => $val )
  442. {
  443. $stdout='';
  444. $stderr='';
  445. $val = str_replace('$SRC', $SRC, $val);
  446. echo cutOrFill('Running '.$val, CONSOLE_WIDTH-3),'[';
  447. if( execute($val, $stdout, $stderr) === 0 ){
  448. echo color('OK', COLOR_GREEN),"]\r\n";
  449. }else{
  450. echo color('FAILL', COLOR_RED),"]\r\n";
  451. }
  452. }
  453. /*******************************************************************************
  454. * Lancement de valgrind
  455. */
  456. if( in_array('valgrind', $argv) ){
  457. echo 'Running Valgrind on ',BIN_DIR.EXEC_NAME,"\r\n";
  458. execute('valgrind --tool=memcheck --leak-check=full --track-origins=yes --log-file=valgrind.log ./'.EXEC_NAME, BIN_DIR);
  459. echo file_get_contents(BIN_DIR.'valgrind.log');
  460. exit;
  461. }
  462. else
  463. /*******************************************************************************
  464. * Lancement du fichier obtenu
  465. */
  466. if( in_array('exec', $argv) ){
  467. echo 'Running ',BIN_DIR.EXEC_NAME,"\r\n";
  468. if( IS_DEBUG_MODE ){
  469. execute('echo 0 | gdb -batch-silent -ex "run" -ex "set logging overwrite on" -ex "set logging file gdb.bt" -ex "set logging on" -ex "set pagination off" -ex "handle SIG33 pass nostop noprint" -ex "echo backtrace:\n" -ex "backtrace full" -ex "echo \n\nregisters:\n" -ex "info registers" -ex "echo \n\ncurrent instructions:\n" -ex "x/16i \$pc" -ex "echo \n\nthreads backtrace:\n" -ex "thread apply all backtrace" -ex "set logging off" -ex "quit" --args '.EXEC_NAME, BIN_DIR);
  470. if( is_file(BIN_DIR.'gdb.bt') )
  471. echo file_get_contents(BIN_DIR.'gdb.bt');
  472. }else{
  473. execute('./'.EXEC_NAME, BIN_DIR);
  474. }
  475. }
  476. exit();
  477. /******************************************************************************/
  478. /***************************************************************************//*!
  479. * @brief Permet de compiler un fichier. (.cpp => .o)
  480. * @param[in] $cmd {String} La commande a executer
  481. * @param[in] $file {String} L'adresse vers le fichier a compiler
  482. * @param[in] $target {String} La cible a obtenir
  483. * @return[NONE]
  484. */
  485. function compile( $cmd, $file='', $target='', $waitForPrint=false )
  486. {
  487. if( is_array($cmd) ){
  488. $file = $cmd['file'];
  489. $target = $cmd['target'];
  490. $waitForPrint = $cmd['waitForPrint'];
  491. $cmd = $cmd['cmd'];
  492. }
  493. $printInfo = '';
  494. if( $waitForPrint ){
  495. if( IS_VERBOSE_MODE )
  496. $printInfo = $cmd."\r\n";
  497. $printInfo .= cutOrFill($file, CONSOLE_WIDTH-3).'[';
  498. }else{
  499. if( IS_VERBOSE_MODE )
  500. echo $cmd,"\r\n";
  501. echo cutOrFill($file, CONSOLE_WIDTH-3),'[';
  502. }
  503. $descriptorspec = array(
  504. 0 => array('pipe', 'r'),// stdin est un pipe où le processus va lire
  505. 1 => array('pipe', 'w'),// stdout est un pipe où le processus va écrire
  506. 2 => array('pipe', 'w')// stderr est un fichier
  507. );
  508. $pipes = null;// On récup les pointeurs de lecture via cet variable
  509. // On supprime l'ancien fichier objet
  510. if( is_file($target) )
  511. unlink($target);
  512. $stdout = '';
  513. $stderr = '';
  514. $return_value = 0;
  515. if( ($return_value=execute($cmd, null, $stdout, $stderr)) || !empty($stderr) ){
  516. if( $waitForPrint )
  517. echo $printInfo;
  518. if( is_file($target) ){
  519. echo color('WARNING', COLOR_YELLOW),"]\r\n";
  520. fwrite(STDERR, parse_gcc_error($stderr));
  521. return ;
  522. }else{
  523. echo color('FAIL', COLOR_RED),"]\r\n";
  524. fwrite(STDERR, parse_gcc_error($stderr));
  525. exit($return_value);
  526. }
  527. }
  528. if( $waitForPrint )
  529. echo $printInfo;
  530. echo color('OK', COLOR_GREEN),"]\r\n";
  531. }
  532. /***************************************************************************//*!
  533. * @brief Permet de déterminer si un objet a besoin d'être recompilé
  534. * @param[in] $target {String} Fichier a obtenir
  535. * @param[in] $dep {Array} Les dépendances de $file. ( Doit contenir $dep['obj'] )
  536. * @return {Bool} TRUE si l'objet doit être recompilé
  537. */
  538. function isMakeNeeded( $target, &$dep )
  539. {
  540. if( !is_file($target) )
  541. return true;
  542. $objFiletime = filemtime($target);
  543. if( MAKEFILE_TIME > $objFiletime )
  544. return true;
  545. for( $i=0,$size=count($dep)-1; $i<$size; $i++ )
  546. if( filemtime($dep[$i]) > $objFiletime )
  547. return true;
  548. return false;
  549. }
  550. /***************************************************************************//*!
  551. * @brief Permet d'obtenir la liste des fichiers a traiter
  552. * @param[in] $src {String}
  553. * @return {Array} La liste des fichiers a traiter
  554. */
  555. function getListOfFile( $src )
  556. {
  557. // Fichier
  558. if( is_file($src) )
  559. return array(relativePath($src)=>'');
  560. // Dossier
  561. if( is_dir($src) )
  562. return getListOfFile($src.((substr($src, -1, 1) === '/')?'*':'/*'));
  563. // Liste ?
  564. // file1.cpp file2.cpp file\ 3.cpp directory/*.cpp
  565. $array_src = split_RespectEscape($src);
  566. if( count($array_src) > 1 ){
  567. $return = array();
  568. foreach( $array_src as $key => $file )
  569. $return = array_merge($return, getListOfFile($file));
  570. return $return;
  571. }
  572. unset($array_src);
  573. // Masque ?
  574. if( strpos($src, '*') ){
  575. $return = array();
  576. foreach( glob($src) as $key => $file )
  577. $return = array_merge($return, getListOfFile($file));
  578. if( SRC_RECURSIV ){
  579. $match = null;
  580. if( preg_match_all('`(.+)(\*.*)`', $src, $match) ){
  581. $folders = glob($match[1][0].'*', GLOB_ONLYDIR);
  582. if( $folders ){
  583. foreach($folders as $key => $dir)
  584. $return = array_merge($return, getListOfFile($dir.'/'.$match[2][0]));
  585. }
  586. }
  587. }
  588. return $return;
  589. }
  590. throw new Exception('file or folder not found for '.$src."\r\n");
  591. }
  592. /***************************************************************************//*!
  593. * @brief Permet d'afficher l'aide
  594. * @return[NONE]
  595. * @warning Cette fonction appel exit
  596. */
  597. function showHelp()
  598. {
  599. exit(
  600. color('Assistance for the Project '.EXEC_NAME, COLOR_MAGENTA, true)."\r\n"
  601. .' help Show this manual.'."\r\n"
  602. .' exec Build and run.'."\r\n"
  603. .' debug Build in debug mode.'."\r\n"
  604. .' re|rebuild Clean & build (current mode).'."\r\n"
  605. .' valgrind Build and run with Valgrind.'."\r\n"
  606. .' cppcheck Run an analysis on source code with CppCheck.'."\r\n"
  607. .' clean Remove all .o for the current mode (release or debug).'."\r\n"
  608. .' cleanall|ca Remove all .o for all mode (release & debug).'."\r\n"
  609. .' wc Show how many line there is in this project.'."\r\n"
  610. .' v|verbose Show variables info.'."\r\n"
  611. .' noColor Disable color.'."\r\n"
  612. .' makefile Generate a makefile.'."\r\n"
  613. .' -jX Build with X thread.'."\r\n"
  614. );
  615. }
  616. /***************************************************************************//*!
  617. * @brief Permet de parser correctement une chaine contenant des fichiers.
  618. * Exemple: file1.cpp file2.cpp file\ 3.cpp dossier/*.cpp
  619. * Va retourner: array('file1.cpp', 'file2.cpp', 'file\ 3.cpp', 'dossier/*.cpp')
  620. * @return {Array} Liste des fichiers séparé par un espace.
  621. */
  622. function split_RespectEscape( $str )
  623. {
  624. return str_replace(':/:', '\ ', explode(' ', str_replace('\ ', ':/:', $str)));
  625. }
  626. /***************************************************************************//*!
  627. * @brief Permet de coloriser le texte {$txt} avec la couleur {$color}.
  628. * De plus, le texte peut être souligné {$underline}
  629. * @param[in] $txt {String} Le texte a coloriser
  630. * @param[in] $color {int} Couleur du texte. VOIR les define commencant par COLOR_
  631. * @param[in,opt] $underline {bool} Activer le soulignement ?
  632. * @return Le texte colorisé.
  633. *
  634. * @warning Cette fonction utilise les caractères d'échapement des consoles UNIX pour coloriser le texte.
  635. * Cela implique donc que ça ne marchera pas sous Windows.
  636. */
  637. function color( $txt, $color, $underline=false )
  638. {
  639. if( !ENABLED_COLOR )
  640. return $txt;
  641. if( $underline )
  642. return "\033[3".$color.";4m"."\033[3".$color.";1m".$txt."\033[0m";
  643. return "\033[3".$color.";1m".$txt."\033[0m";
  644. }
  645. /***************************************************************************//*!
  646. * @brief Permet de couper ou d'allonger un texte en fonction de $max
  647. * @param[in] $str {String} La chaine a ajuster
  648. * @param[in] $max {uint} La taille max a retourner
  649. * @return {String} Exemple:
  650. * cutOrFill("j'aime les fleurs", 10) => "j'aime ..."
  651. * cutOrFill("j'aime les fleurs", 20) => "j'aime les fleurs "
  652. */
  653. function cutOrFill( $str, $max )
  654. {
  655. if( $max < 0 )
  656. return $str.' ';
  657. if( count($str) > $max )
  658. return substr($str, 0, $max-3).'...';
  659. return str_pad($str, $max-count($str), ' ');
  660. }
  661. /***************************************************************************//*!
  662. * @brief Permet de center le texte
  663. * @param[in] $text {String} Le texte a centrer
  664. * @param[in] $color {int} Couleur du texte. VOIR les define commencant par COLOR_
  665. * @param[in,opt] $underline {bool} Activer le soulignement ?
  666. * @return {String} Le texte centré
  667. */
  668. function center( $text, $color=-1, $underline=false )
  669. {
  670. $rest = CONSOLE_WIDTH - strlen($text);
  671. if( $rest < 0 ){
  672. if( $color !== -1 )
  673. return color($text, $color, $underline);
  674. return $text;
  675. }
  676. if( $color !== -1 )
  677. return str_pad('', $rest/2).color($text, $color, $underline);
  678. return str_pad('', $rest/2).$text;
  679. }
  680. /***************************************************************************//*!
  681. * @brief Permet de créer un dossier avec gestion des erreurs
  682. * @param[in] $dir {String} Le dossier a créer
  683. * @return[NONE]
  684. *
  685. * @warning Cette fonction appel EXIT en cas d'echec
  686. */
  687. function makeDir( $dir )
  688. {
  689. if( is_dir($dir) )
  690. return ;
  691. echo 'Création du dossier ',cutOrFill($dir, 56),' [';
  692. if( !mkdir($dir, 0755, true) )
  693. exit(color('FAIL', COLOR_RED)."]\r\n");
  694. echo color('OK', COLOR_GREEN),"]\r\n";
  695. }
  696. /***************************************************************************//*!
  697. * @brief Mini parser. Permet d'afficher la ligne qui contient l'erreur.
  698. * @param[in] $err {String} L'erreur gcc
  699. * @return {String} L'erreur GCC modifiée
  700. */
  701. function parse_gcc_error( $err )
  702. {
  703. $match = null;
  704. if( preg_match_all('`([^:\r\n]+):([0-9]+):([0-9]+):([^\r\n]+)`i', $err, $match) ){
  705. for( $i=0,$size=count($match[1]); $i<$size; $i++ )
  706. {
  707. $tmp = file($match[1][$i]);
  708. $err = str_replace($match[0][$i], $match[0][$i]."\r\n ".cpp(trim($tmp[$match[2][$i]-1])), $err);
  709. }
  710. }
  711. return $err;
  712. }
  713. /***************************************************************************//*!
  714. * @brief Colorateur syntaxique pour C++
  715. * @param[in] $code {String} Le code a coloriser
  716. * @return {String} Le code colorisé
  717. */
  718. function cpp( $code )
  719. {
  720. static $keyWord = array(
  721. 'return', 'if', 'else', 'false', 'true',
  722. 'double', 'int', 'float', 'char', 'void', 'bool',
  723. 'for', 'while',
  724. 'const', 'static', 'inline',
  725. 'new', 'delete',
  726. 'class', 'struct', 'typedef', 'enum'
  727. );
  728. if( !ENABLED_COLOR )
  729. return $code;
  730. if( is_file('/usr/bin/source-highlight') ){
  731. $stdout = '';
  732. $stderr = '';
  733. execute('/usr/bin/source-highlight --src-lang=cc --out-format=esc', null, $stdout, $stderr, $code);
  734. if( $stderr ){
  735. echo $stderr;
  736. return $code;
  737. }
  738. return $stdout;
  739. }
  740. // Permet de parser les erreurs du type
  741. // Block* World::getBlock( double x, double y, double z )
  742. if( preg_match_all('`^([ \t\r\n]*)([^ ]+)([ \t\r\n]*)([^\:]+)\:\:([^\(]+)\(([^\)]+)\)`', $code, $match) ){
  743. $hasStar = (substr($match[2][0], -1, 1) === '*')?'*':'';
  744. // Analyse des arguments
  745. $arg = explode(',', $match[6][0]);
  746. foreach( $arg as $key => &$val )
  747. {
  748. $tmp = explode(' ', trim($val));
  749. $star = (substr($tmp[0], -1, 1) === '*')?'*':'';
  750. $tmp[0] = str_replace('*', '', $tmp[0]);
  751. if( in_array($tmp[0], $keyWord) ){
  752. $tmp[0] = color($tmp[0], COLOR_YELLOW).$star;
  753. }else{
  754. $tmp[0] = color($tmp[0], COLOR_GREEN).$star;
  755. }
  756. $val = implode(' ', $tmp);
  757. }
  758. if( count($arg) ){
  759. $arg = ' '.implode(', ', $arg).' ';
  760. }else{
  761. $arg = ' ';
  762. }
  763. return
  764. // Block*
  765. color(str_replace('*', '', $match[2][0]), COLOR_GREEN).$hasStar
  766. // Wolrd
  767. .' '.color($match[4][0], COLOR_GREEN)
  768. // ::getBlock
  769. .'::'.color($match[5][0], COLOR_BLUE)
  770. .'('.$arg.')';
  771. }
  772. // static Chunk* chk = new Chunk(0,0,0,0);
  773. if( preg_match_all('`^[ \r\n\t]*(static|const)?[ \t]*([^ ]+)[ \t]+([^ ]+)([ \t]=[ \t]([^;]+))?;`', $code, $match) ){
  774. $star = (substr($match[2][0], -1, 1) === '*')?'*':'';
  775. $match[2][0] = str_replace('*', '', $match[2][0]);
  776. if( in_array($match[2][0], $keyWord) ){
  777. $match[2][0] = color($match[2][0], COLOR_YELLOW).$star;
  778. }else{
  779. $match[2][0] = color($match[2][0], COLOR_GREEN).$star;
  780. }
  781. $equal = '';
  782. if( IsSet($match[5]) && $match[5][0] ){
  783. $equal = ' = ';
  784. $match[5][0] = trim($match[5][0]);
  785. if( substr($match[5][0], 0, 3) === 'new' ){
  786. $equal .= color('new', COLOR_YELLOW);
  787. if( preg_match_all('`new[ \t]([^(;]+)[ \t]*([^;]*)`', $match[5][0], $match2) ){
  788. $star = (substr($match2[1][0], -1, 1) === '*')?'*':'';
  789. $match2[1][0] = str_replace('*', '', $match2[1][0]);
  790. if( in_array($match2[1][0], $keyWord) ){
  791. $equal .= ' '.color($match2[1][0], COLOR_YELLOW).$star;
  792. }else{
  793. $equal .= ' '.color($match2[1][0], COLOR_GREEN).$star;
  794. }
  795. $equal .= $match2[2][0];
  796. }
  797. }else{
  798. $equal .= $match[5][0];
  799. }
  800. }
  801. return trim(
  802. // Static|const
  803. ($match[1][0]?color($match[1][0], COLOR_YELLOW).' ':'')
  804. // Chunk*
  805. .$match[2][0].' '
  806. // chk
  807. .($match[3][0]?trim($match[3][0]):'')
  808. .$equal.';'
  809. );
  810. }
  811. // inline Real normalise()
  812. if( preg_match_all('`^[ \r\n\t]*(static|const|inline)?[ \t]*([^ ]+)[ \t]+([^ ]+)([ \t]([^;]+));`', $code, $match) ){
  813. $star = (substr($match[2][0], -1, 1) === '*')?'*':'';
  814. $match[2][0] = str_replace('*', '', $match[2][0]);
  815. if( in_array($match[2][0], $keyWord) ){
  816. $match[2][0] = color($match[2][0], COLOR_YELLOW).$star;
  817. }else{
  818. $match[2][0] = color($match[2][0], COLOR_GREEN).$star;
  819. }
  820. $equal = '';
  821. if( IsSet($match[5]) && $match[5][0] ){
  822. $equal = ' = ';
  823. $match[5][0] = trim($match[5][0]);
  824. if( substr($match[5][0], 0, 3) === 'new' ){
  825. $equal .= color('new', COLOR_YELLOW);
  826. if( preg_match_all('`new[ \t]([^(;]+)[ \t]*([^;]*)`', $match[5][0], $match2) ){
  827. $star = (substr($match2[1][0], -1, 1) === '*')?'*':'';
  828. $match2[1][0] = str_replace('*', '', $match2[1][0]);
  829. if( in_array($match2[1][0], $keyWord) ){
  830. $equal .= ' '.color($match2[1][0], COLOR_YELLOW).$star;
  831. }else{
  832. $equal .= ' '.color($match2[1][0], COLOR_GREEN).$star;
  833. }
  834. $equal .= $match2[2][0];
  835. }
  836. }else{
  837. $equal .= $match[5][0];
  838. }
  839. }
  840. return trim(
  841. // Static|const
  842. ($match[1][0]?color($match[1][0], COLOR_YELLOW).' ':'')
  843. // Chunk*
  844. .$match[2][0].' '
  845. // chk
  846. .($match[3][0]?trim($match[3][0]):'')
  847. .$equal.';'
  848. );
  849. }
  850. // #if OGRE_WCHAR_T_STRINGS
  851. if( preg_match_all('`^[ \r\n\t]*#if[ \t]+(.+)`', $code, $match) ){
  852. return trim(
  853. // #if
  854. color('#if', COLOR_BLUE).' '
  855. // OGRE_WCHAR_T_STRINGS
  856. .$match[1][0]
  857. );
  858. }
  859. return $code;
  860. }
  861. /***************************************************************************//*!
  862. * @brief Permet de supprimer un dossier de façon récusive
  863. * @param[in] $dir {String} Le dossier a supprimer
  864. * @return[NONE]
  865. */
  866. function rrmdir( $dir )
  867. {
  868. if( substr($dir, -1, 1) !== '/' )
  869. $dir .= '/';
  870. if( !is_dir($dir) ){
  871. echo 'Suppression dossier ',cutOrFill($dir, 56),' [',color('ALL READY DONE', COLOR_YELLOW),"]\r\n";
  872. return ;
  873. }
  874. foreach( glob($dir.'*') as $file )
  875. {
  876. if( is_dir($file) ){
  877. rrmdir($file);
  878. }else{
  879. echo 'Suppression du fichier ',cutOrFill($file, 53),' [';
  880. if( unlink($file) ){
  881. echo color('OK', COLOR_GREEN),"]\r\n";
  882. }else{
  883. echo color('FAIL', COLOR_RED),"]\r\n";
  884. }
  885. }
  886. }
  887. echo 'Suppression du dossier ',cutOrFill($dir, 53),' [';
  888. if( rmdir($dir) ){
  889. echo color('OK', COLOR_GREEN),"]\r\n";
  890. }else{
  891. echo color('FAIL', COLOR_RED),"]\r\n";
  892. }
  893. }
  894. /***************************************************************************//*!
  895. * @brief Permet de résoudre les ./ et les ../
  896. * @param[in] $path {String} Une adresse
  897. * @return {String} L'adresse résolue
  898. */
  899. function relativePath( $path )
  900. {
  901. $relativePath = $path;
  902. $pattern = '/\w+\/\.\.\//';
  903. while( preg_match($pattern, $relativePath) )
  904. $relativePath = preg_replace($pattern, '', $relativePath);
  905. return preg_replace('`^./`', '', str_replace('/./', '/', $relativePath));
  906. }
  907. /***************************************************************************//*!
  908. * @brief Permet d'executer la commande $cmd
  909. * @param[in] $cmd {String} Commande a executer
  910. * @param[in,opt] $path {String} Dossier d'execution
  911. * @return Le code de retour. (-1 En cas d'erreur d'execution)
  912. */
  913. function execute( $cmd, $path=null, &$stdout=null, &$stderr=null, $stdin=null )
  914. {
  915. $descriptorspec = array(
  916. 0 => array('pipe', 'r'),// stdin est un pipe où le processus va lire
  917. 1 => array('pipe', 'w'),// stdout est un pipe où le processus va écrire
  918. 2 => array('pipe', 'w')// stderr est un fichier
  919. );
  920. $pipes = null;// On récup les pointeurs de lecture via cet variable
  921. $process = proc_open($cmd, $descriptorspec, $pipes, $path, null);
  922. if( is_resource($process) ){
  923. // $pipes ressemble à :
  924. // 0 => fichier accessible en écriture, connecté à l'entrée standard du processus fils
  925. // 1 => fichier accessible en lecture, connecté à la sortie standard du processus fils
  926. // 2 => fichier accessible en lecture, connecté à la sortie stderr du processus fils
  927. if( $stdin !== null )
  928. fwrite($pipes[0], $stdin);
  929. fclose($pipes[0]);
  930. $timeout = time()+5;
  931. stream_set_blocking($pipes[1], 0);
  932. while( !feof($pipes[1]) && ($read = fread($pipes[1], 1000)) !== false )
  933. {
  934. if( !empty($read) ){
  935. if( $stdout === null ){
  936. echo $read;
  937. }else{
  938. $stdout .= $read;
  939. }
  940. }
  941. usleep(500);
  942. if( time() >= $timeout )
  943. break;
  944. }
  945. fclose($pipes[1]);
  946. $timeout = time()+5;
  947. stream_set_blocking($pipes[2], 0);
  948. while( !feof($pipes[2]) && ($read = fread($pipes[2], 1000)) !== false )
  949. {
  950. if( !empty($read) ){
  951. if( $stderr === null ){
  952. echo $read;
  953. }else{
  954. $stderr .= $read;
  955. }
  956. }
  957. usleep(500);
  958. if( time() >= $timeout )
  959. break;
  960. }
  961. fclose($pipes[2]);
  962. // Il est important que vous fermiez les pipes avant d'appeler
  963. // proc_close afin d'éviter un verrouillage.
  964. return proc_close($process);
  965. }
  966. return -1;
  967. }
  968. /***************************************************************************//*!
  969. * @brief Fonction de concatenation.
  970. * Ex:
  971. * $def = 'obj/' et $val = '+release/' => $def = 'obj/release/'
  972. * $def = 'obj/' et $val = 'release/' => $def = 'release/'
  973. * @param[in,out] $def {String}
  974. * @param[in] $val {String}
  975. * @return[NONE]
  976. */
  977. function appendOrReset( &$def, $val )
  978. {
  979. if( is_string($val) && substr($val, 0, 1) === '+' ){
  980. $def .= substr($val, 1);
  981. return ;
  982. }
  983. $def = $val;
  984. }
  985. /***************************************************************************//*!
  986. * @brief Permet de parser les options dans $_CONFIG
  987. * @return[NONE]
  988. *
  989. * @warning NE PAS APPELER 2 FOIS CETTE FONCTION
  990. * @note Cette fonction fait appel a $_CONFIG
  991. */
  992. function parseOptions()
  993. {
  994. global $_CONFIG, $_CMD_AFTER;
  995. $OS = (OS_RUNNING === OS_UNIX)?'unix':'win';
  996. $MODE = IS_DEBUG_MODE?'debug':'release';
  997. $defines = array(
  998. 'CONSOLE',
  999. 'OBJ_DIR',
  1000. 'BIN_DIR',
  1001. 'EXEC_NAME',
  1002. 'SRC',
  1003. 'SRC_RECURSIV',
  1004. 'INCLUDE_DIR',
  1005. 'LIBS',
  1006. 'CFLAGS',
  1007. 'LDFLAGS'
  1008. );
  1009. $def = null;
  1010. $var = array();
  1011. $LIB = '';
  1012. foreach( $defines as $key => $val )
  1013. {
  1014. $def = '';
  1015. if( IsSet($_CONFIG['global']) ){
  1016. if( IsSet($_CONFIG['global'][$val]) )
  1017. $def = $_CONFIG['global'][$val];
  1018. if( IsSet($_CONFIG['global'][$MODE],$_CONFIG['global'][$MODE][$val]) )
  1019. appendOrReset($def, $_CONFIG['global'][$MODE][$val]);
  1020. }
  1021. if( IsSet($_CONFIG[$OS]) ){
  1022. if( IsSet($_CONFIG[$OS][$val]) )
  1023. appendOrReset($def, $_CONFIG[$OS][$val]);
  1024. if( IsSet($_CONFIG[$OS][$MODE],$_CONFIG[$OS][$MODE][$val]) )
  1025. appendOrReset($def, $_CONFIG[$OS][$MODE][$val]);
  1026. }
  1027. if( IS_VERBOSE_MODE )
  1028. echo cutOrFill($val, CONSOLE_WIDTH-strlen($def)),color($def, COLOR_GREEN),"\r\n";
  1029. // Règle spécial pour désactier la console sous windows
  1030. if( defined('CONSOLE') && CONSOLE && OS_RUNNING === OS_WINDOWS && $val === 'LIBS' )
  1031. $def .= ' -mwindows';
  1032. define($val, $def);
  1033. }
  1034. if( IsSet($_CONFIG['global']) ){
  1035. if( IsSet($_CONFIG['global']['CMD_AFTER']) )
  1036. $_CMD_AFTER = array_merge($_CMD_AFTER, $_CONFIG['global']['CMD_AFTER']);
  1037. if( IsSet($_CONFIG['global'][$MODE],$_CONFIG['global'][$MODE]['CMD_AFTER']) )
  1038. $_CMD_AFTER = array_merge($_CMD_AFTER, $_CONFIG['global'][$MODE]['CMD_AFTER']);
  1039. }
  1040. if( IsSet($_CONFIG[$OS]) ){
  1041. if( IsSet($_CONFIG[$OS]['CMD_AFTER']) )
  1042. $_CMD_AFTER = array_merge($_CMD_AFTER, $_CONFIG[$OS]['CMD_AFTER']);
  1043. if( IsSet($_CONFIG[$OS][$MODE],$_CONFIG[$OS][$MODE]['CMD_AFTER']) )
  1044. $_CMD_AFTER = array_merge($_CMD_AFTER, $_CONFIG[$OS][$MODE]['CMD_AFTER']);
  1045. }
  1046. if( IS_VERBOSE_MODE ){
  1047. $def = count($_CMD_AFTER)?count($_CMD_AFTER):'[NONE]';
  1048. echo cutOrFill('CMD_AFTER', CONSOLE_WIDTH-strlen($def)),color($def, COLOR_GREEN),"\r\n";
  1049. }
  1050. $res = array(
  1051. '$CONSOLE' => CONSOLE,
  1052. '$OBJ_DIR' => OBJ_DIR,
  1053. '$BIN_DIR' => BIN_DIR,
  1054. '$EXEC_NAME' => EXEC_NAME,
  1055. //'$SRC' => SRC, //<! Les Sources sont mise après
  1056. '$SRC_RECURSIV' => SRC_RECURSIV,
  1057. '$INCLUDE_DIR' => INCLUDE_DIR,
  1058. '$LIBS' => LIBS,
  1059. '$CFLAGS' => CFLAGS,
  1060. '$LDFLAGS' => LDFLAGS
  1061. );
  1062. foreach( $_CMD_AFTER as $key => &$val )
  1063. {
  1064. $val = str_replace(array_keys($res), array_values($res), $val);
  1065. if( IS_VERBOSE_MODE )
  1066. echo cutOrFill(' '.$val, CONSOLE_WIDTH),"\r\n";
  1067. }
  1068. if( IS_VERBOSE_MODE )
  1069. echo "\r\n";
  1070. }
  1071. /***************************************************************************//*!
  1072. * @brief Permet de gérer une file de thread
  1073. *
  1074. * Utilisation:
  1075. * @code
  1076. * define('NB_THREAD', 5);// On veux 5 thread
  1077. *
  1078. * Thread::start(function($arg){
  1079. * echo $arg;// Va afficher 'argument'
  1080. * }, 'argument');
  1081. *
  1082. * Thread::start(function($arg){
  1083. * echo $arg;// Va afficher 'argument'
  1084. * return 'lol';
  1085. * }, 'argument', function($ret){
  1086. * echo $ret;// Va afficher 'lol'
  1087. * });
  1088. * @endcode
  1089. */
  1090. class Thread
  1091. {
  1092. private static $m_thread = array();
  1093. private static $m_parentPid = -1;
  1094. private function __construct() {}//!< Constructeur interdit. Class Static
  1095. /***********************************************************************//*!
  1096. * @brief Permet d'init le système de communication
  1097. * @return[NONE]
  1098. */
  1099. public static function init()
  1100. {
  1101. if( defined('MSG_QUEUE') )
  1102. return ;
  1103. self::$m_parentPid = posix_getpid();
  1104. register_shutdown_function('Thread::killAll');
  1105. // Création d'un canal de communication pour les thread
  1106. define('MSG_QUEUE', rand());
  1107. // On clean le canal de communication
  1108. if( msg_queue_exists(MSG_QUEUE) )
  1109. msg_remove_queue(msg_get_queue(MSG_QUEUE));
  1110. // Création d'un canal de communication
  1111. define('MSG_HANDLER', msg_get_queue(MSG_QUEUE));
  1112. }
  1113. /***********************************************************************//*!
  1114. * @brief Permet de lancer un thread
  1115. * @param[in] $function {Function} La fonction a appeler
  1116. * @param[in] $arg {Mixed} Les données a passer à $function
  1117. * @param[in,opt] $communication {Function} La fonction a executer lors de
  1118. * la fin du thread. ( Un argument est passé à
  1119. * celle-ci. La var contient le return de $function )
  1120. * @return[NONE]
  1121. */
  1122. public static function start( $function, $arg )
  1123. {
  1124. $pid = pcntl_fork();
  1125. if( $pid === -1 ){
  1126. $function($arg);
  1127. // Error
  1128. fclose($fp);
  1129. }elseif( $pid ){
  1130. // Parent
  1131. self::$m_thread['p'.$pid] = true;
  1132. return ;
  1133. }else{
  1134. register_shutdown_function(function(){
  1135. msg_send(MSG_HANDLER, 1/*msg type*/, posix_getpid(), true, true, $err);
  1136. if( $err )
  1137. echo $err;
  1138. });
  1139. // Child
  1140. $function($arg);
  1141. exit(0);
  1142. }
  1143. }
  1144. /***********************************************************************//*!
  1145. * @brief Permet d'attendre NB_THREAD ou si $all => tout les thread
  1146. * @param[in,opt] $all {Bool} Si true => la fonction wait tout les thread
  1147. * @return[NONE]
  1148. */
  1149. public static function wait( $all=false )
  1150. {
  1151. if( $all ){
  1152. while( count(self::$m_thread) > 0 )
  1153. {
  1154. self::getMessage();
  1155. usleep(500);
  1156. }
  1157. return ;
  1158. }
  1159. if( count(self::$m_thread) >= NB_THREAD ){
  1160. while( count(self::$m_thread) >= NB_THREAD )
  1161. {
  1162. self::getMessage();
  1163. usleep(500);
  1164. }
  1165. return ;
  1166. }
  1167. self::getMessage();
  1168. }
  1169. /***********************************************************************//*!
  1170. * @brief Permet de kill tout les thread lancé
  1171. * @return[NONE]
  1172. */
  1173. public static function killAll()
  1174. {
  1175. if( self::$m_parentPid !== posix_getpid() )
  1176. return ;
  1177. foreach( self::$m_thread as $key => $data )
  1178. posix_kill(substr($key, 1), SIGINT);
  1179. }
  1180. /***********************************************************************//*!
  1181. * @brief La fonction va traiter tout les messages de fin de thread et va se charger
  1182. * de transmettre le résultat à la fonction final si elle a été défini dans
  1183. * start( ..., ..., $communication=function(){....})
  1184. * @return[NONE]
  1185. */
  1186. private static function getMessage()
  1187. {
  1188. $queue_status = msg_stat_queue(MSG_HANDLER);
  1189. if( $queue_status['msg_qnum'] == 0 )
  1190. return ;
  1191. for( $i=0; $i<$queue_status['msg_qnum']; $i++ )
  1192. {
  1193. msg_receive(MSG_HANDLER, 0, $msgtype, 8, $data, true, null, $err);
  1194. if( IsSet(self::$m_thread['p'.$data]) ){
  1195. $status = 0;
  1196. pcntl_waitpid($data, $status);
  1197. if( $status !== 0 )
  1198. exit(pcntl_wexitstatus($status));
  1199. }
  1200. unset(self::$m_thread['p'.$data]);
  1201. }
  1202. }
  1203. }
  1204. /***********************************************************************//*!
  1205. * @brief Permet de déterminer l'architecture: 32 ou 64bits
  1206. * @return TRUE si 64bits
  1207. */
  1208. function is_64bit()
  1209. {
  1210. if( PHP_INT_SIZE === 8 )
  1211. return true;
  1212. if( PHP_INT_SIZE === 4 )
  1213. return false;
  1214. $int = intval("9223372036854775807");
  1215. if( $int === 9223372036854775807 )
  1216. return true;
  1217. if( $int == 2147483647 )
  1218. return false;
  1219. throw new Exception('Error ! Systeme has returned an incorrect value: '.$int);
  1220. }
  1221. ?>