Bearsampp 2026.9.23
Loading...
Searching...
No Matches
Builder.php
Go to the documentation of this file.
1<?php
19
23require_once 'PEAR/Common.php';
24require_once 'PEAR/PackageFile.php';
25require_once 'System.php';
26
42{
46
47 var $extensions_built = array();
48
54
55 // used for msdev builds
56 var $_lastline = null;
57 var $_firstline = null;
58
65
74 function __construct($configureoptions, &$ui)
75 {
76 parent::__construct();
77 $this->setFrontendObject($ui);
78 $this->_parseConfigureOptions($configureoptions);
79 }
80
87 {
88 $data = '<XML><PROPERTIES ' . $options . ' /></XML>';
89 $parser = xml_parser_create('ISO-8859-1');
90 xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
91 xml_set_element_handler(
92 $parser, array($this, '_parseConfigureOptionsStartElement'),
93 array($this, '_parseConfigureOptionsEndElement'));
94 xml_parse($parser, $data, true);
95 xml_parser_free($parser);
96 }
97
107 function _parseConfigureOptionsStartElement($parser, $tagName, $attribs)
108 {
109 if ($tagName !== 'PROPERTIES') {
110 return;
111 }
112 $this->_parsed_configure_options = $attribs;
113 }
114
123 function _parseConfigureOptionsEndElement($parser, $element)
124 {
125 }
126
131 function _build_win32($descfile, $callback = null)
132 {
133 if (is_object($descfile)) {
134 $pkg = $descfile;
135 $descfile = $pkg->getPackageFile();
136 } else {
137 $pf = new PEAR_PackageFile($this->config, $this->debug);
138 $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
139 if (PEAR::isError($pkg)) {
140 return $pkg;
141 }
142 }
143 $dir = dirname($descfile);
144 $old_cwd = getcwd();
145
146 if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) {
147 return $this->raiseError("could not chdir to $dir");
148 }
149
150 // packages that were in a .tar have the packagefile in this directory
151 $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
152 if (file_exists($dir) && is_dir($vdir)) {
153 if (!chdir($vdir)) {
154 return $this->raiseError("could not chdir to " . realpath($vdir));
155 }
156
157 $dir = getcwd();
158 }
159
160 $this->log(2, "building in $dir");
161
162 $dsp = $pkg->getPackage().'.dsp';
163 if (!file_exists("$dir/$dsp")) {
164 return $this->raiseError("The DSP $dsp does not exist.");
165 }
166 // XXX TODO: make release build type configurable
167 $command = 'msdev '.$dsp.' /MAKE "'.$pkg->getPackage(). ' - Release"';
168
169 $err = $this->_runCommand($command, array(&$this, 'msdevCallback'));
170 if (PEAR::isError($err)) {
171 return $err;
172 }
173
174 // figure out the build platform and type
175 $platform = 'Win32';
176 $buildtype = 'Release';
177 if (preg_match('/.*?'.$pkg->getPackage().'\s-\s(\w+)\s(.*?)-+/i',$this->_firstline,$matches)) {
178 $platform = $matches[1];
179 $buildtype = $matches[2];
180 }
181
182 if (preg_match('/(.*)?\s-\s(\d+).*?(\d+)/', $this->_lastline, $matches)) {
183 if ($matches[2]) {
184 // there were errors in the build
185 return $this->raiseError("There were errors during compilation.");
186 }
187 $out = $matches[1];
188 } else {
189 return $this->raiseError("Did not understand the completion status returned from msdev.exe.");
190 }
191
192 // msdev doesn't tell us the output directory :/
193 // open the dsp, find /out and use that directory
194 $dsptext = join('', file($dsp));
195
196 // this regex depends on the build platform and type having been
197 // correctly identified above.
198 $regex ='/.*?!IF\s+"\$\‍(CFG\‍)"\s+==\s+("'.
199 $pkg->getPackage().'\s-\s'.
200 $platform.'\s'.
201 $buildtype.'").*?'.
202 '\/out:"(.*?)"/is';
203
204 if ($dsptext && preg_match($regex, $dsptext, $matches)) {
205 // what we get back is a relative path to the output file itself.
206 $outfile = realpath($matches[2]);
207 } else {
208 return $this->raiseError("Could not retrieve output information from $dsp.");
209 }
210 // realpath returns false if the file doesn't exist
211 if ($outfile && copy($outfile, "$dir/$out")) {
212 $outfile = "$dir/$out";
213 }
214
215 $built_files[] = array(
216 'file' => "$outfile",
217 'php_api' => $this->php_api_version,
218 'zend_mod_api' => $this->zend_module_api_no,
219 'zend_ext_api' => $this->zend_extension_api_no,
220 );
221
222 return $built_files;
223 }
224 // }}}
225
226 // {{{ msdevCallback()
227 function msdevCallback($what, $data)
228 {
229 if (!$this->_firstline)
230 $this->_firstline = $data;
231 $this->_lastline = $data;
232 call_user_func($this->current_callback, $what, $data);
233 }
234
241 function _harvestInstDir($dest_prefix, $dirname, &$built_files)
242 {
243 $d = opendir($dirname);
244 if (!$d)
245 return false;
246
247 $ret = true;
248 while (($ent = readdir($d)) !== false) {
249 if ($ent[0] == '.')
250 continue;
251
252 $full = $dirname . DIRECTORY_SEPARATOR . $ent;
253 if (is_dir($full)) {
254 if (!$this->_harvestInstDir(
255 $dest_prefix . DIRECTORY_SEPARATOR . $ent,
256 $full, $built_files)) {
257 $ret = false;
258 break;
259 }
260 } else {
261 $dest = $dest_prefix . DIRECTORY_SEPARATOR . $ent;
262 $built_files[] = array(
263 'file' => $full,
264 'dest' => $dest,
265 'php_api' => $this->php_api_version,
266 'zend_mod_api' => $this->zend_module_api_no,
267 'zend_ext_api' => $this->zend_extension_api_no,
268 );
269 }
270 }
271 closedir($d);
272 return $ret;
273 }
274
298 function build($descfile, $callback = null)
299 {
300 if (preg_match('/(\\/|\\\\|^)([^\\/\\\\]+)?php([^\\/\\\\]+)?$/',
301 $this->config->get('php_bin'), $matches)) {
302 if (isset($matches[2]) && strlen($matches[2]) &&
303 trim($matches[2]) != trim($this->config->get('php_prefix'))) {
304 $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') .
305 ' appears to have a prefix ' . $matches[2] . ', but' .
306 ' config variable php_prefix does not match');
307 }
308
309 if (isset($matches[3]) && strlen($matches[3]) &&
310 trim($matches[3]) != trim($this->config->get('php_suffix'))) {
311 $this->log(0, 'WARNING: php_bin ' . $this->config->get('php_bin') .
312 ' appears to have a suffix ' . $matches[3] . ', but' .
313 ' config variable php_suffix does not match');
314 }
315 }
316
317 $this->current_callback = $callback;
318 if (PEAR_OS == "Windows") {
319 return $this->_build_win32($descfile, $callback);
320 }
321
322 if (PEAR_OS != 'Unix') {
323 return $this->raiseError("building extensions not supported on this platform");
324 }
325
326 if (is_object($descfile)) {
327 $pkg = $descfile;
328 $descfile = $pkg->getPackageFile();
329 if (is_a($pkg, 'PEAR_PackageFile_v1')) {
330 $dir = dirname($descfile);
331 } else {
332 $dir = $pkg->_config->get('temp_dir') . '/' . $pkg->getName();
333 // automatically delete at session end
334 self::addTempFile($dir);
335 }
336 } else {
337 $pf = new PEAR_PackageFile($this->config);
338 $pkg = &$pf->fromPackageFile($descfile, PEAR_VALIDATE_NORMAL);
339 if (PEAR::isError($pkg)) {
340 return $pkg;
341 }
342 $dir = dirname($descfile);
343 }
344
345 // Find config. outside of normal path - e.g. config.m4
346 foreach (array_keys($pkg->getInstallationFileList()) as $item) {
347 if (stristr(basename($item), 'config.m4') && dirname($item) != '.') {
348 $dir .= DIRECTORY_SEPARATOR . dirname($item);
349 break;
350 }
351 }
352
353 $old_cwd = getcwd();
354 if (!file_exists($dir) || !is_dir($dir) || !chdir($dir)) {
355 return $this->raiseError("could not chdir to $dir");
356 }
357
358 $vdir = $pkg->getPackage() . '-' . $pkg->getVersion();
359 if (is_dir($vdir)) {
360 chdir($vdir);
361 }
362
363 $dir = getcwd();
364 $this->log(2, "building in $dir");
365 $binDir = $this->config->get('bin_dir');
366 if (!preg_match('@(^|:)' . preg_quote($binDir, '@') . '(:|$)@', getenv('PATH'))) {
367 putenv('PATH=' . $binDir . ':' . getenv('PATH'));
368 }
369 $err = $this->_runCommand($this->config->get('php_prefix')
370 . "phpize" .
371 $this->config->get('php_suffix'),
372 array(&$this, 'phpizeCallback'));
373 if (PEAR::isError($err)) {
374 return $err;
375 }
376
377 if (!$err) {
378 return $this->raiseError("`phpize' failed");
379 }
380
381 // {{{ start of interactive part
382 $configure_command = "$dir/configure";
383
384 $phpConfigName = $this->config->get('php_prefix')
385 . 'php-config'
386 . $this->config->get('php_suffix');
387 $phpConfigPath = System::which($phpConfigName);
388 if ($phpConfigPath !== false) {
389 $configure_command .= ' --with-php-config='
390 . $phpConfigPath;
391 }
392
393 $configure_options = $pkg->getConfigureOptions();
394 if ($configure_options) {
395 foreach ($configure_options as $option) {
396 $default = array_key_exists('default', $option) ? $option['default'] : null;
397 if (array_key_exists($option['name'], $this->_parsed_configure_options)) {
398 $response = $this->_parsed_configure_options[$option['name']];
399 } else {
400 list($response) = $this->ui->userDialog(
401 'build', [$option['prompt']], ['text'], [$default]);
402 }
403 if (substr($option['name'], 0, 5) === 'with-' &&
404 ($response === 'yes' || $response === 'autodetect')) {
405 $configure_command .= " --{$option['name']}";
406 } else {
407 $configure_command .= " --{$option['name']}=".trim($response);
408 }
409 }
410 }
411 // }}} end of interactive part
412
413 // FIXME make configurable
414 if (!$user=getenv('USER')) {
415 $user='defaultuser';
416 }
417
418 $tmpdir = $this->config->get('temp_dir');
419 $build_basedir = System::mktemp(' -t "' . $tmpdir . '" -d "pear-build-' . $user . '"');
420 $build_dir = "$build_basedir/$vdir";
421 $inst_dir = "$build_basedir/install-$vdir";
422 $this->log(1, "building in $build_dir");
423 if (is_dir($build_dir)) {
424 System::rm(array('-rf', $build_dir));
425 }
426
427 if (!System::mkDir(array('-p', $build_dir))) {
428 return $this->raiseError("could not create build dir: $build_dir");
429 }
430
431 self::addTempFile($build_dir);
432 if (!System::mkDir(array('-p', $inst_dir))) {
433 return $this->raiseError("could not create temporary install dir: $inst_dir");
434 }
435 self::addTempFile($inst_dir);
436
437 $make_command = getenv('MAKE') ? getenv('MAKE') : 'make';
438
439 $to_run = array(
440 $configure_command,
441 $make_command,
442 "$make_command INSTALL_ROOT=\"$inst_dir\" install",
443 "find \"$inst_dir\" | xargs ls -dils"
444 );
445 if (!file_exists($build_dir) || !is_dir($build_dir) || !chdir($build_dir)) {
446 return $this->raiseError("could not chdir to $build_dir");
447 }
448 putenv('PHP_PEAR_VERSION=1.10.18');
449 foreach ($to_run as $cmd) {
450 $err = $this->_runCommand($cmd, $callback);
451 if (PEAR::isError($err)) {
452 chdir($old_cwd);
453 return $err;
454 }
455 if (!$err) {
456 chdir($old_cwd);
457 return $this->raiseError("`$cmd' failed");
458 }
459 }
460 if (!($dp = opendir("modules"))) {
461 chdir($old_cwd);
462 return $this->raiseError("no `modules' directory found");
463 }
464 $built_files = array();
465 $prefix = exec($this->config->get('php_prefix')
466 . "php-config" .
467 $this->config->get('php_suffix') . " --prefix");
468 $this->_harvestInstDir($prefix, $inst_dir . DIRECTORY_SEPARATOR . $prefix, $built_files);
469 chdir($old_cwd);
470 return $built_files;
471 }
472
485 function phpizeCallback($what, $data)
486 {
487 if ($what != 'cmdoutput') {
488 return;
489 }
490 $this->log(1, rtrim($data));
491 if (preg_match('/You should update your .aclocal.m4/', $data)) {
492 return;
493 }
494 $matches = array();
495 if (preg_match('/^\s+(\S[^:]+):\s+(\d{8})/', $data, $matches)) {
496 $member = preg_replace('/[^a-z]/', '_', strtolower($matches[1]));
497 $apino = (int)$matches[2];
498 if (isset($this->$member)) {
499 $this->$member = $apino;
500 //$msg = sprintf("%-22s : %d", $matches[1], $apino);
501 //$this->log(1, $msg);
502 }
503 }
504 }
505
522 function _runCommand($command, $callback = null)
523 {
524 $this->log(1, "running: $command");
525 $pp = popen("$command 2>&1", "r");
526 if (!$pp) {
527 return $this->raiseError("failed to run `$command'");
528 }
529 if ($callback && $callback[0]->debug == 1) {
530 $olddbg = $callback[0]->debug;
531 $callback[0]->debug = 2;
532 }
533
534 while ($line = fgets($pp, 1024)) {
535 if ($callback) {
536 call_user_func($callback, 'cmdoutput', $line);
537 } else {
538 $this->log(2, rtrim($line));
539 }
540 }
541 if ($callback && isset($olddbg)) {
542 $callback[0]->debug = $olddbg;
543 }
544
545 $exitcode = is_resource($pp) ? pclose($pp) : -1;
546 return ($exitcode == 0);
547 }
548
549 function log($level, $msg, $append_crlf = true)
550 {
551 if ($this->current_callback) {
552 if ($this->debug >= $level) {
553 call_user_func($this->current_callback, 'output', $msg);
554 }
555 return;
556 }
557 return parent::log($level, $msg, $append_crlf);
558 }
559}
const PEAR_OS
Definition PEAR.php:43
const PEAR_VALIDATE_NORMAL
Definition Validate.php:20
_parseConfigureOptions($options)
Definition Builder.php:86
_harvestInstDir($dest_prefix, $dirname, &$built_files)
Definition Builder.php:241
log($level, $msg, $append_crlf=true)
Definition Builder.php:549
_runCommand($command, $callback=null)
Definition Builder.php:522
build($descfile, $callback=null)
Definition Builder.php:298
$zend_extension_api_no
Definition Builder.php:45
$_parsed_configure_options
Definition Builder.php:64
_parseConfigureOptionsEndElement($parser, $element)
Definition Builder.php:123
phpizeCallback($what, $data)
Definition Builder.php:485
_build_win32($descfile, $callback=null)
Definition Builder.php:131
__construct($configureoptions, &$ui)
Definition Builder.php:74
_parseConfigureOptionsStartElement($parser, $tagName, $attribs)
Definition Builder.php:107
msdevCallback($what, $data)
Definition Builder.php:227
static addTempFile($file)
Definition Common.php:208
setFrontendObject(&$ui)
Definition Common.php:294
static isError($data, $code=null)
Definition PEAR.php:306
$options
Definition pearcmd.php:145
if( $raw) foreach($opts as $opt) if( $store_system_config) if($store_user_config) $command
Definition pearcmd.php:322