Back to index

php5  5.3.10
mkdist.php
Go to the documentation of this file.
00001 <?php # $Id: mkdist.php 321952 2012-01-09 13:56:46Z pajoye $
00002 /* piece together a windows binary distro */
00003 
00004 $build_dir = $argv[1];
00005 $php_build_dir = $argv[2];
00006 $phpdll = $argv[3];
00007 $sapi_targets = explode(" ", $argv[4]);
00008 $ext_targets = explode(" ", $argv[5]);
00009 $pecl_targets = explode(" ", $argv[6]);
00010 $snapshot_template = $argv[7];
00011 
00012 $is_debug = preg_match("/^debug/i", $build_dir);
00013 
00014 echo "Making dist for $build_dir\n";
00015 
00016 $dist_dir = $build_dir . "/php-" . phpversion();
00017 $test_dir = $build_dir . "/php-test-pack-" . phpversion();
00018 $pecl_dir = $build_dir . "/pecl-" . phpversion();
00019 
00020 @mkdir($dist_dir);
00021 @mkdir("$dist_dir/ext");
00022 @mkdir("$dist_dir/dev");
00023 @mkdir("$dist_dir/extras");
00024 @mkdir($pecl_dir);
00025 
00026 /* figure out additional DLL's that are required */
00027 $extra_dll_deps = array();
00028 $per_module_deps = array();
00029 $pecl_dll_deps = array();
00030 
00031 function get_depends($module)
00032 {
00033        static $no_dist = array(
00034               /* windows system dlls that should not be bundled */
00035               'advapi32.dll', 'comdlg32.dll', 'crypt32.dll', 'gdi32.dll', 'kernel32.dll', 'ntdll.dll',
00036               'odbc32.dll', 'ole32.dll', 'oleaut32.dll', 'rpcrt4.dll',
00037               'shell32.dll', 'shlwapi.dll', 'user32.dll', 'ws2_32.dll', 'ws2help.dll',
00038               'comctl32.dll', 'winmm.dll', 'wsock32.dll', 'winspool.drv', 'msasn1.dll',
00039               'secur32.dll', 'netapi32.dll',
00040 
00041               /* apache */
00042               'apachecore.dll',
00043 
00044               /* apache 2 */
00045               'libhttpd.dll', 'libapr.dll', 'libaprutil.dll','libapr-1.dll', 'libaprutil-1.dll',
00046 
00047               /* pi3web */
00048               'piapi.dll', 'pi3api.dll',
00049 
00050               /* nsapi */
00051               'ns-httpd30.dll', 'ns-httpd35.dll', 'ns-httpd36.dll', 'ns-httpd40.dll',
00052 
00053               /* oracle */
00054               'oci.dll', 'ociw32.dll',
00055 
00056               /* sybase */
00057               'libcs.dll', 'libct.dll',
00058 
00059               /* firebird */
00060               'fbclient.dll',
00061 
00062               /* visual C++; mscvrt.dll is present on everyones system,
00063                * but the debug version (msvcrtd.dll) and those from visual studio.net
00064                * (msvcrt7x.dll) are not */
00065               'msvcrt.dll',
00066               'msvcr90.dll',
00067               'wldap32.dll'
00068               );
00069        global $build_dir, $extra_dll_deps, $ext_targets, $sapi_targets, $pecl_targets, $phpdll, $per_module_deps, $pecl_dll_deps;
00070        
00071        $bd = strtolower(realpath($build_dir));
00072 
00073        $is_pecl = in_array($module, $pecl_targets);
00074        
00075        $cmd = "$GLOBALS[build_dir]\\deplister.exe \"$module\" \"$GLOBALS[build_dir]\"";
00076        $proc = proc_open($cmd, 
00077                      array(1 => array("pipe", "w")),
00078                      $pipes);
00079 
00080        $n = 0;
00081        while (($line = fgetcsv($pipes[1]))) {
00082               $n++;
00083 
00084               $dep = strtolower($line[0]);
00085               $depbase = basename($dep);
00086               /* ignore stuff in our build dir, but only if it is
00087             * one of our targets */
00088               if (((in_array($depbase, $sapi_targets) ||
00089                             in_array($depbase, $ext_targets) || in_array($depbase, $pecl_targets)) ||
00090                             $depbase == $phpdll) && file_exists($GLOBALS['build_dir'] . "/$depbase")) {
00091                      continue;
00092               }
00093               /* ignore some well-known system dlls */
00094               if (in_array(basename($dep), $no_dist)) {
00095                      continue;
00096               }
00097               
00098               if ($is_pecl) {
00099                      if (!in_array($dep, $pecl_dll_deps)) {
00100                             $pecl_dll_deps[] = $dep;
00101                      }
00102               } else {
00103                      if (!in_array($dep, $extra_dll_deps)) {
00104                             $extra_dll_deps[] = $dep;
00105                      }
00106               }
00107 
00108               $per_module_deps[basename($module)][] = $dep;
00109        }
00110        fclose($pipes[1]);
00111        proc_close($proc);
00112 //echo "Module $module [$n lines]\n";
00113 }
00114 
00115 function copy_file_list($source_dir, $dest_dir, $list)
00116 {
00117        global $is_debug, $dist_dir;
00118 
00119        foreach ($list as $item) {
00120               if (empty($item)) {
00121                      continue;
00122               } elseif (!is_file($source_dir . DIRECTORY_SEPARATOR . $item)) {
00123                      echo "WARNING: $item not found\n";
00124                      continue;
00125               }
00126 
00127               echo "Copying $item from $source_dir to $dest_dir\n";
00128               copy($source_dir . DIRECTORY_SEPARATOR . $item, $dest_dir . DIRECTORY_SEPARATOR . $item);
00129               if ($is_debug) {
00130                      $itemdb = preg_replace("/\.(exe|dll|lib)$/i", ".pdb", $item);
00131                      if (file_exists("$source_dir/$itemdb")) {
00132                             copy("$source_dir/$itemdb", "$dist_dir/dev/$itemdb");
00133                      }
00134               }
00135               if (preg_match("/\.(exe|dll)$/i", $item)) {
00136                      get_depends($source_dir . '/' . $item);
00137               }
00138        }
00139 }
00140 
00141 function copy_text_file($source, $dest)
00142 {
00143        $text = file_get_contents($source);
00144        $text = preg_replace("/(\r\n?)|\n/", "\r\n", $text);
00145        $fp = fopen($dest, "w");
00146        fwrite($fp, $text);
00147        fclose($fp);
00148 }
00149 
00150 /* very light-weight function to extract a single named file from
00151  * a gzipped tarball.  This makes assumptions about the files
00152  * based on the PEAR info set in $packages. */
00153 function extract_file_from_tarball($pkg, $filename, $dest_dir) /* {{{ */
00154 {
00155        global $packages;
00156 
00157        $name = $pkg . '-' . $packages[$pkg];
00158        $tarball = $dest_dir . "/" . $name . '.tgz';
00159        $filename = $name . '/' . $filename;
00160        $destfilename = $dest_dir . "/" . basename($filename);
00161 
00162        $fp = gzopen($tarball, 'rb');
00163 
00164        $done = false;
00165        do {
00166               /* read the header */
00167               $hdr_data = gzread($fp, 512);
00168               if (strlen($hdr_data) == 0)
00169                      break;
00170               $checksum = 0;
00171               for ($i = 0; $i < 148; $i++)
00172                      $checksum += ord($hdr_data{$i});
00173               for ($i = 148; $i < 156; $i++)
00174                      $checksum += 32;
00175               for ($i = 156; $i < 512; $i++)
00176                      $checksum += ord($hdr_data{$i});
00177 
00178               $hdr = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $hdr_data);
00179 
00180               $hdr['checksum'] = octdec(trim($hdr['checksum']));
00181 
00182               if ($hdr['checksum'] != $checksum) {
00183                      echo "Checksum for $tarball $hdr[filename] is invalid\n";
00184                      print_r($hdr);
00185                      return;
00186               }
00187 
00188               $hdr['size'] = octdec(trim($hdr['size']));
00189               echo "File: $hdr[filename] $hdr[size]\n";
00190               
00191               if ($filename == $hdr['filename']) {
00192                      echo "Found the file we want\n";
00193                      $dest = fopen($destfilename, 'wb');
00194                      $x = stream_copy_to_stream($fp, $dest, $hdr['size']);
00195                      fclose($dest);
00196                      echo "Wrote $x bytes into $destfilename\n";
00197                      break;
00198               }
00199               
00200               /* skip body of the file */
00201               $size = 512 * ceil((int)$hdr['size'] / 512);
00202               echo "Skipping $size bytes\n";
00203               gzseek($fp, gztell($fp) + $size);
00204               
00205        } while (!$done);
00206        
00207 } /* }}} */
00208 
00209 
00210 /* the core dll */
00211 copy("$build_dir/php.exe", "$dist_dir/php.exe");
00212 copy("$build_dir/$phpdll", "$dist_dir/$phpdll");
00213 
00214 /* and the .lib goes into dev */
00215 $phplib = str_replace(".dll", ".lib", $phpdll);
00216 copy("$build_dir/$phplib", "$dist_dir/dev/$phplib");
00217 /* debug builds; copy the symbols too */
00218 if ($is_debug) {
00219        $phppdb = str_replace(".dll", ".pdb", $phpdll);
00220        copy("$build_dir/$phppdb", "$dist_dir/dev/$phppdb");
00221 }
00222 /* copy the sapi */
00223 copy_file_list($build_dir, "$dist_dir", $sapi_targets);
00224 
00225 /* copy the extensions */
00226 copy_file_list($build_dir, "$dist_dir/ext", $ext_targets);
00227 
00228 /* pecl sapi and extensions */
00229 if(sizeof($pecl_targets)) {
00230        copy_file_list($build_dir, $pecl_dir, $pecl_targets);
00231 }
00232 
00233 /* populate reading material */
00234 $text_files = array(
00235        "LICENSE" => "license.txt",
00236        "NEWS" => "news.txt",
00237        "README.REDIST.BINS" => "readme-redist-bins.txt",
00238        "php.ini-development" => "php.ini-development",
00239        "php.ini-production" => "php.ini-production",
00240        "win32/install.txt" => "install.txt",
00241        "win32/pws-php5cgi.reg" => "pws-php5cgi.reg",
00242        "win32/pws-php5isapi.reg" => "pws-php5isapi.reg",
00243 );
00244 
00245 foreach ($text_files as $src => $dest) {
00246        copy_text_file($src, $dist_dir . '/' . $dest);
00247 }
00248 
00249 /* general other files */
00250 $general_files = array(
00251        "php.gif"                   =>     "php.gif",
00252 );
00253 
00254 foreach ($general_files as $src => $dest) {
00255        copy($src, $dist_dir . '/' . $dest);
00256 }
00257 
00258 /* include a snapshot identifier */
00259 $branch = "HEAD"; // TODO - determine this from SVN branche name
00260 $fp = fopen("$dist_dir/snapshot.txt", "w");
00261 $now = date("r");
00262 $version = phpversion();
00263 fwrite($fp, <<<EOT
00264 This snapshot was automatically generated on
00265 $now
00266 
00267 Version: $version
00268 Branch: $branch
00269 Build: $build_dir
00270 
00271 EOT
00272 );
00273 /* list build-in extensions */
00274 $exts = get_loaded_extensions();
00275 fprintf($fp, "\r\nBuilt-in Extensions\r\n");
00276 fwrite($fp, "===========================\r\n");
00277 foreach ($exts as $ext) {
00278        fprintf($fp, "%s\r\n", $ext);
00279 }
00280 fwrite($fp, "\r\n\r\n");
00281 
00282 /* list dependencies */
00283 fprintf($fp, "Dependency information:\r\n");
00284 foreach ($per_module_deps as $modulename => $deps) {
00285        if (in_array($modulename, $pecl_targets))
00286               continue;
00287 
00288        fprintf($fp, "Module: %s\r\n", $modulename);
00289        fwrite($fp, "===========================\r\n");
00290        foreach ($deps as $dll) {
00291               fprintf($fp, "\t%s\r\n", basename($dll));
00292        }
00293        fwrite($fp, "\r\n");
00294 }
00295 fclose($fp);
00296 
00297 /* Now add those dependencies */
00298 foreach ($extra_dll_deps as $dll) {
00299        if (!file_exists($dll)) {
00300               /* try template dir */
00301               $tdll = $snapshot_template . "/dlls/" . basename($dll);
00302               if (!file_exists($tdll)) {
00303                      $tdll = $php_build_dir . '/bin/' . basename($dll);
00304                      if (!file_exists($tdll)) {
00305                             echo "WARNING: distro depends on $dll, but could not find it on your system\n";
00306                             continue;
00307                      }
00308               }
00309               $dll = $tdll;
00310        }
00311        copy($dll, "$dist_dir/" . basename($dll));
00312 }
00313 
00314 /* TODO:
00315 add sanity check and test if all required DLLs are present, per version 
00316 This version works at least for 3.6, 3.8 and 4.0 (5.3-vc6, 5.3-vc9 and HEAD).
00317 Add ADD_DLLS to add extra DLLs like dynamic dependencies for standard 
00318 deps. For example, libenchant.dll loads libenchant_myspell.dll or
00319 libenchant_ispell.dll
00320 */
00321 $ICU_DLLS = $php_build_dir . '/bin/icu*.dll';
00322 foreach (glob($ICU_DLLS) as $filename) {
00323        copy($filename, "$dist_dir/" . basename($filename));
00324 }
00325 $ENCHANT_DLLS = array(
00326        'glib-2.dll',
00327        'gmodule-2.dll',
00328        'libenchant_myspell.dll',
00329        'libenchant_ispell.dll',
00330 );
00331 foreach ($ENCHANT_DLLS as $filename) {
00332        copy($php_build_dir . '/bin/' . $filename, "$dist_dir/" . basename($filename));
00333 }
00334 
00335 /* and those for pecl */
00336 foreach ($pecl_dll_deps as $dll) {
00337        if (in_array($dll, $extra_dll_deps)) {
00338               /* already in main distro */
00339               continue;
00340        }
00341        if (!file_exists($dll)) {
00342               /* try template dir */
00343               $tdll = $snapshot_template . "/dlls/" . basename($dll);
00344               if (!file_exists($tdll)) {
00345                      echo "WARNING: distro depends on $dll, but could not find it on your system\n";
00346                      continue;
00347               }
00348               $dll = $tdll;
00349        }
00350        copy($dll, "$pecl_dir/" . basename($dll));
00351 }
00352 
00353 function copy_dir($source, $dest)
00354 {
00355        if (!is_dir($dest)) {
00356               if (!mkdir($dest)) {
00357                      return false;
00358               }
00359        }
00360 
00361        $d = opendir($source);
00362        while (($f = readdir($d)) !== false) {
00363               if ($f == '.' || $f == '..' || $f == '.svn') {
00364                      continue;
00365               }
00366               $fs = $source . '/' . $f;
00367               $fd = $dest . '/' . $f;
00368               if (is_dir($fs)) {
00369                      copy_dir($fs, $fd);
00370               } else {
00371                      copy($fs, $fd);
00372               }
00373        }
00374        closedir($d);
00375 }
00376 
00377 
00378 
00379 function copy_test_dir($directory, $dest)
00380 {
00381        if(substr($directory,-1) == '/') {
00382               $directory = substr($directory,0,-1);
00383        }
00384 
00385        if ($directory == 'tests' || $directory == 'examples') {
00386               if (!is_dir($dest . '/tests')) {
00387                      mkdir($dest . '/tests', 0775, true);
00388               }
00389               copy_dir($directory, $dest . '/tests/');
00390 
00391               return false;
00392        }
00393 
00394        if(!file_exists($directory) || !is_dir($directory)) {
00395               echo "failed... $directory\n";
00396               return FALSE;
00397        }
00398 
00399        $directory_list = opendir($directory);
00400 
00401        while (FALSE !== ($file = readdir($directory_list))) {
00402               $full_path = $directory . '/' . $file;
00403               if($file != '.' && $file != '..' && $file != '.svn' && is_dir($full_path)) {
00404                      if ($file == 'tests') {
00405                             if (!is_dir($dest . '/' . $full_path)) {
00406                                    mkdir($dest . '/' . $full_path , 0775, true);
00407                             }
00408                             copy_dir($full_path, $dest . '/' . $full_path . '/');
00409                             continue;
00410                      } else {
00411                             copy_test_dir($full_path, $dest);
00412                      }
00413               }
00414        }
00415 
00416        closedir($directory_list); 
00417 }
00418 
00419 function make_phar_dot_phar($dist_dir)
00420 {
00421        if (!extension_loaded('phar')) {
00422               return;
00423        }
00424 
00425        $path_to_phar = realpath(__DIR__ . '/../../ext/phar');
00426 
00427        echo "Generating pharcommand.phar\n";
00428        $phar = new Phar($dist_dir . '/pharcommand.phar', 0, 'pharcommand');
00429 
00430        foreach (new DirectoryIterator($path_to_phar . '/phar') as $file) {
00431               if ($file->isDir() || $file == 'phar.php') {
00432                      continue;
00433               }
00434 
00435               echo 'adding ', $file, "\n";
00436               $phar[(string) $file] = file_get_contents($path_to_phar.  '/phar/' . $file);
00437        }
00438 
00439        $phar->setSignatureAlgorithm(Phar::SHA1);
00440        $stub = file($path_to_phar . '/phar/phar.php');
00441 
00442        unset($stub[0]); // remove hashbang
00443        $phar->setStub(implode('', $stub));
00444 
00445        echo "Creating phar.phar.bat\n";
00446        file_put_contents($dist_dir . '/phar.phar.bat', "%~dp0php.exe %~dp0pharcommand.phar %*\r\n");
00447 }
00448 
00449 if (!is_dir($test_dir)) {
00450        mkdir($test_dir);
00451 }
00452 
00453 $dirs = array(
00454        'ext',
00455        'Sapi',
00456        'Zend',
00457        'tests'
00458 );
00459 foreach ($dirs as $dir) {
00460        copy_test_dir($dir, $test_dir);
00461 }
00462 copy('run-tests.php', $test_dir . '/run-test.php');
00463 
00464 /* change this next line to true to use good-old
00465  * hand-assembled go-pear-bundle from the snapshot template */
00466 $use_pear_template = true;
00467 
00468 if (!$use_pear_template) {
00469        /* Let's do a PEAR-less pear setup */
00470        mkdir("$dist_dir/PEAR");
00471        mkdir("$dist_dir/PEAR/go-pear-bundle");
00472 
00473        /* grab the bootstrap script */
00474        echo "Downloading go-pear\n";
00475        copy("http://pear.php.net/go-pear", "$dist_dir/PEAR/go-pear.php");
00476 
00477        /* import the package list -- sets $packages variable */
00478        include "pear/go-pear-list.php";
00479 
00480        /* download the packages into the destination */
00481        echo "Fetching packages\n";
00482 
00483        foreach ($packages as $name => $version) {
00484               $filename = "$name-$version.tgz";
00485               $destfilename = "$dist_dir/PEAR/go-pear-bundle/$filename";
00486               if (file_exists($destfilename))
00487                      continue;
00488               $url = "http://pear.php.net/get/$filename";
00489               echo "Downloading $name from $url\n";
00490               flush();
00491               copy($url, $destfilename);
00492        }
00493 
00494        echo "Download complete.  Extracting bootstrap files\n";
00495 
00496        /* Now, we want PEAR.php, Getopt.php (Console_Getopt) and Tar.php (Archive_Tar)
00497         * broken out of the tarballs */
00498        extract_file_from_tarball('PEAR', 'PEAR.php', "$dist_dir/PEAR/go-pear-bundle");
00499        extract_file_from_tarball('Archive_Tar', 'Archive/Tar.php', "$dist_dir/PEAR/go-pear-bundle");
00500        extract_file_from_tarball('Console_Getopt', 'Console/Getopt.php', "$dist_dir/PEAR/go-pear-bundle");
00501 }
00502        
00503 /* add extras from the template dir */
00504 if (file_exists($snapshot_template)) {
00505        $items = glob("$snapshot_template/*");
00506        print_r($items);
00507 
00508        foreach ($items as $item) {
00509               $bi = basename($item);
00510               if (is_dir($item)) {
00511                      if ($bi == 'dlls' || $bi == 'symbols') {
00512                             continue;
00513                      } else if ($bi == 'PEAR') {
00514                             if ($use_pear_template) {
00515                                    /* copy to top level */
00516                                    copy_dir($item, "$dist_dir/$bi");
00517                             }
00518                      } else {
00519                             /* copy that dir into extras */
00520                             copy_dir($item, "$dist_dir/extras/$bi");
00521                      }
00522               } else {
00523                      if ($bi == 'go-pear.bat') {
00524                             /* copy to top level */
00525                             copy($item, "$dist_dir/$bi");
00526                      } else {
00527                             /* copy to extras */
00528                             copy($item, "$dist_dir/extras/$bi");
00529                      }
00530               }
00531        }
00532        
00533        /* copy c++ runtime */
00534        $items = glob("$snapshot_template/dlls/*.CRT");
00535 
00536        foreach ($items as $item) {
00537               $bi = basename($item);
00538               if (is_dir($item)) {
00539                      copy_dir($item, "$dist_dir/$bi");
00540                      copy_dir($item, "$dist_dir/ext/$bi");
00541               }
00542        }
00543 } else {
00544        echo "WARNING: you don't have a snapshot template, your dist will not be complete\n";
00545 }
00546 
00547 make_phar_dot_phar($dist_dir);
00548 ?>