[ Index ] |
|
Code source de SPIP Agora 1.4 |
1 <?php 2 // 3 // +----------------------------------------------------------------------+ 4 // | PHP Version 5 | 5 // +----------------------------------------------------------------------+ 6 // | Copyright (c) 1997-2004 The PHP Group | 7 // +----------------------------------------------------------------------+ 8 // | This source file is subject to version 3.0 of the PHP license, | 9 // | that is bundled with this package in the file LICENSE, and is | 10 // | available through the world-wide-web at the following url: | 11 // | http://www.php.net/license/3_0.txt. | 12 // | If you did not receive a copy of the PHP license and are unable to | 13 // | obtain it through the world-wide-web, please send a note to | 14 // | license@php.net so we can mail you a copy immediately. | 15 // +----------------------------------------------------------------------+ 16 // | Authors: Stig Sæther Bakken <ssb@php.net> | 17 // +----------------------------------------------------------------------+ 18 // 19 // $Id: Builder.php,v 1.16.2.3 2005/02/17 17:55:01 cellog Exp $ 20 21 require_once 'PEAR/Common.php'; 22 23 /** 24 * Class to handle building (compiling) extensions. 25 * 26 * @author Stig Sæther Bakken <ssb@php.net> 27 */ 28 class PEAR_Builder extends PEAR_Common 29 { 30 // {{{ properties 31 32 var $php_api_version = 0; 33 var $zend_module_api_no = 0; 34 var $zend_extension_api_no = 0; 35 36 var $extensions_built = array(); 37 38 var $current_callback = null; 39 40 // used for msdev builds 41 var $_lastline = null; 42 var $_firstline = null; 43 // }}} 44 // {{{ constructor 45 46 /** 47 * PEAR_Builder constructor. 48 * 49 * @param object $ui user interface object (instance of PEAR_Frontend_*) 50 * 51 * @access public 52 */ 53 function PEAR_Builder(&$ui) 54 { 55 parent::PEAR_Common(); 56 $this->setFrontendObject($ui); 57 } 58 59 // }}} 60 61 // {{{ _build_win32() 62 63 /** 64 * Build an extension from source on windows. 65 * requires msdev 66 */ 67 function _build_win32($descfile, $callback = null) 68 { 69 if (PEAR::isError($info = $this->infoFromDescriptionFile($descfile))) { 70 return $info; 71 } 72 $dir = dirname($descfile); 73 $old_cwd = getcwd(); 74 75 if (!@chdir($dir)) { 76 return $this->raiseError("could not chdir to $dir"); 77 } 78 $this->log(2, "building in $dir"); 79 80 $dsp = $info['package'].'.dsp'; 81 if (!@is_file("$dir/$dsp")) { 82 return $this->raiseError("The DSP $dsp does not exist."); 83 } 84 // XXX TODO: make release build type configurable 85 $command = 'msdev '.$dsp.' /MAKE "'.$info['package']. ' - Release"'; 86 87 $this->current_callback = $callback; 88 $err = $this->_runCommand($command, array(&$this, 'msdevCallback')); 89 if (PEAR::isError($err)) { 90 return $err; 91 } 92 93 // figure out the build platform and type 94 $platform = 'Win32'; 95 $buildtype = 'Release'; 96 if (preg_match('/.*?'.$info['package'].'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) { 97 $platform = $matches[1]; 98 $buildtype = $matches[2]; 99 } 100 101 if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/',$this->_lastline,$matches)) { 102 if ($matches[2]) { 103 // there were errors in the build 104 return $this->raiseError("There were errors during compilation."); 105 } 106 $out = $matches[1]; 107 } else { 108 return $this->raiseError("Did not understand the completion status returned from msdev.exe."); 109 } 110 111 // msdev doesn't tell us the output directory :/ 112 // open the dsp, find /out and use that directory 113 $dsptext = join(file($dsp),''); 114 115 // this regex depends on the build platform and type having been 116 // correctly identified above. 117 $regex ='/.*?!IF\s+"\$\(CFG\)"\s+==\s+("'. 118 $info['package'].'\s-\s'. 119 $platform.'\s'. 120 $buildtype.'").*?'. 121 '\/out:"(.*?)"/is'; 122 123 if ($dsptext && preg_match($regex,$dsptext,$matches)) { 124 // what we get back is a relative path to the output file itself. 125 $outfile = realpath($matches[2]); 126 } else { 127 return $this->raiseError("Could not retrieve output information from $dsp."); 128 } 129 if (@copy($outfile, "$dir/$out")) { 130 $outfile = "$dir/$out"; 131 } 132 133 $built_files[] = array( 134 'file' => "$outfile", 135 'php_api' => $this->php_api_version, 136 'zend_mod_api' => $this->zend_module_api_no, 137 'zend_ext_api' => $this->zend_extension_api_no, 138 ); 139 140 return $built_files; 141 } 142 // }}} 143 144 // {{{ msdevCallback() 145 function msdevCallback($what, $data) 146 { 147 if (!$this->_firstline) 148 $this->_firstline = $data; 149 $this->_lastline = $data; 150 } 151 // }}} 152 153 // {{{ _harventInstDir 154 /** 155 * @param string 156 * @param string 157 * @param array 158 * @access private 159 */ 160 function _harvestInstDir($dest_prefix, $dirname, &$built_files) 161 { 162 $d = opendir($dirname); 163 if (!$d) 164 return false; 165 166 $ret = true; 167 while (($ent = readdir($d)) !== false) { 168 if ($ent{0} == '.') 169 continue; 170 171 $full = $dirname . DIRECTORY_SEPARATOR . $ent; 172 if (is_dir($full)) { 173 if (!$this->_harvestInstDir( 174 $dest_prefix . DIRECTORY_SEPARATOR . $ent, 175 $full, $built_files)) { 176 $ret = false; 177 break; 178 } 179 } else { 180 $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent; 181 $built_files[] = array( 182 'file' => $full, 183 'dest' => $dest, 184 'php_api' => $this->php_api_version, 185 'zend_mod_api' => $this->zend_module_api_no, 186 'zend_ext_api' => $this->zend_extension_api_no, 187 ); 188 } 189 } 190 closedir($d); 191 return $ret; 192 } 193 194 // }}} 195 196 // {{{ build() 197 198 /** 199 * Build an extension from source. Runs "phpize" in the source 200 * directory, but compiles in a temporary directory 201 * (/var/tmp/pear-build-USER/PACKAGE-VERSION). 202 * 203 * @param string $descfile path to XML package description file 204 * 205 * @param mixed $callback callback function used to report output, 206 * see PEAR_Builder::_runCommand for details 207 * 208 * @return array an array of associative arrays with built files, 209 * format: 210 * array( array( 'file' => '/path/to/ext.so', 211 * 'php_api' => YYYYMMDD, 212 * 'zend_mod_api' => YYYYMMDD, 213 * 'zend_ext_api' => YYYYMMDD ), 214 * ... ) 215 * 216 * @access public 217 * 218 * @see PEAR_Builder::_runCommand 219 * @see PEAR_Common::infoFromDescriptionFile 220 */ 221 function build($descfile, $callback = null) 222 { 223 if (PEAR_OS == "Windows") { 224 return $this->_build_win32($descfile,$callback); 225 } 226 if (PEAR_OS != 'Unix') { 227 return $this->raiseError("building extensions not supported on this platform"); 228 } 229 if (PEAR::isError($info = $this->infoFromDescriptionFile($descfile))) { 230 return $info; 231 } 232 $dir = dirname($descfile); 233 $old_cwd = getcwd(); 234 if (!@chdir($dir)) { 235 return $this->raiseError("could not chdir to $dir"); 236 } 237 $vdir = "$info[package]-$info[version]"; 238 if (is_dir($vdir)) { 239 chdir($vdir); 240 } 241 $dir = getcwd(); 242 $this->log(2, "building in $dir"); 243 $this->current_callback = $callback; 244 putenv('PATH=' . $this->config->get('bin_dir') . ':' . getenv('PATH')); 245 $err = $this->_runCommand("phpize", array(&$this, 'phpizeCallback')); 246 if (PEAR::isError($err)) { 247 return $err; 248 } 249 if (!$err) { 250 return $this->raiseError("`phpize' failed"); 251 } 252 253 // {{{ start of interactive part 254 $configure_command = "$dir/configure"; 255 if (isset($info['configure_options'])) { 256 foreach ($info['configure_options'] as $o) { 257 list($r) = $this->ui->userDialog('build', 258 array($o['prompt']), 259 array('text'), 260 array(@$o['default'])); 261 if (substr($o['name'], 0, 5) == 'with-' && 262 ($r == 'yes' || $r == 'autodetect')) { 263 $configure_command .= " --$o[name]"; 264 } else { 265 $configure_command .= " --$o[name]=".trim($r); 266 } 267 } 268 } 269 // }}} end of interactive part 270 271 // FIXME make configurable 272 if(!$user=getenv('USER')){ 273 $user='defaultuser'; 274 } 275 $build_basedir = "/var/tmp/pear-build-$user"; 276 $build_dir = "$build_basedir/$info[package]-$info[version]"; 277 $inst_dir = "$build_basedir/install-$info[package]-$info[version]"; 278 $this->log(1, "building in $build_dir"); 279 if (is_dir($build_dir)) { 280 System::rm('-rf', $build_dir); 281 } 282 if (!System::mkDir(array('-p', $build_dir))) { 283 return $this->raiseError("could not create build dir: $build_dir"); 284 } 285 $this->addTempFile($build_dir); 286 if (!System::mkDir(array('-p', $inst_dir))) { 287 return $this->raiseError("could not create temporary install dir: $inst_dir"); 288 } 289 $this->addTempFile($inst_dir); 290 291 if (getenv('MAKE')) { 292 $make_command = getenv('MAKE'); 293 } else { 294 $make_command = 'make'; 295 } 296 $to_run = array( 297 $configure_command, 298 $make_command, 299 "$make_command INSTALL_ROOT=\"$inst_dir\" install", 300 "find \"$inst_dir\" -ls" 301 ); 302 if (!@chdir($build_dir)) { 303 return $this->raiseError("could not chdir to $build_dir"); 304 } 305 putenv('PHP_PEAR_VERSION=@PEAR-VER@'); 306 foreach ($to_run as $cmd) { 307 $err = $this->_runCommand($cmd, $callback); 308 if (PEAR::isError($err)) { 309 chdir($old_cwd); 310 return $err; 311 } 312 if (!$err) { 313 chdir($old_cwd); 314 return $this->raiseError("`$cmd' failed"); 315 } 316 } 317 if (!($dp = opendir("modules"))) { 318 chdir($old_cwd); 319 return $this->raiseError("no `modules' directory found"); 320 } 321 $built_files = array(); 322 $prefix = exec("php-config --prefix"); 323 $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files); 324 chdir($old_cwd); 325 return $built_files; 326 } 327 328 // }}} 329 // {{{ phpizeCallback() 330 331 /** 332 * Message callback function used when running the "phpize" 333 * program. Extracts the API numbers used. Ignores other message 334 * types than "cmdoutput". 335 * 336 * @param string $what the type of message 337 * @param mixed $data the message 338 * 339 * @return void 340 * 341 * @access public 342 */ 343 function phpizeCallback($what, $data) 344 { 345 if ($what != 'cmdoutput') { 346 return; 347 } 348 $this->log(1, rtrim($data)); 349 if (preg_match('/You should update your .aclocal.m4/', $data)) { 350 return; 351 } 352 $matches = array(); 353 if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) { 354 $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1])); 355 $apino = (int)$matches[2]; 356 if (isset($this->$member)) { 357 $this->$member = $apino; 358 //$msg = sprintf("%-22s : %d", $matches[1], $apino); 359 //$this->log(1, $msg); 360 } 361 } 362 } 363 364 // }}} 365 // {{{ _runCommand() 366 367 /** 368 * Run an external command, using a message callback to report 369 * output. The command will be run through popen and output is 370 * reported for every line with a "cmdoutput" message with the 371 * line string, including newlines, as payload. 372 * 373 * @param string $command the command to run 374 * 375 * @param mixed $callback (optional) function to use as message 376 * callback 377 * 378 * @return bool whether the command was successful (exit code 0 379 * means success, any other means failure) 380 * 381 * @access private 382 */ 383 function _runCommand($command, $callback = null) 384 { 385 $this->log(1, "running: $command"); 386 $pp = @popen("$command 2>&1", "r"); 387 if (!$pp) { 388 return $this->raiseError("failed to run `$command'"); 389 } 390 if ($callback && $callback[0]->debug == 1) { 391 $olddbg = $callback[0]->debug; 392 $callback[0]->debug = 2; 393 } 394 395 while ($line = fgets($pp, 1024)) { 396 if ($callback) { 397 call_user_func($callback, 'cmdoutput', $line); 398 } else { 399 $this->log(2, rtrim($line)); 400 } 401 } 402 if ($callback && isset($olddbg)) { 403 $callback[0]->debug = $olddbg; 404 } 405 $exitcode = @pclose($pp); 406 return ($exitcode == 0); 407 } 408 409 // }}} 410 // {{{ log() 411 412 function log($level, $msg) 413 { 414 if ($this->current_callback) { 415 if ($this->debug >= $level) { 416 call_user_func($this->current_callback, 'output', $msg); 417 } 418 return; 419 } 420 return PEAR_Common::log($level, $msg); 421 } 422 423 // }}} 424 } 425 426 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sat Feb 24 14:40:03 2007 | par Balluche grâce à PHPXref 0.7 |