PageRenderTime 84ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/pmake

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