PageRenderTime 58ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/win32/build/mkdist.php

http://github.com/php/php-src
PHP | 589 lines | 421 code | 86 blank | 82 comment | 96 complexity | f43cfad45b89cfcab74c7dfd85e41277 MD5 | raw file
Possible License(s): BSD-2-Clause, BSD-3-Clause, MPL-2.0-no-copyleft-exception, LGPL-2.1
  1. <?php
  2. /* piece together a windows binary distro */
  3. $php_version = $argv[1];
  4. $build_dir = $argv[2];
  5. $php_build_dir = $argv[3];
  6. $phpdll = $argv[4];
  7. $sapi_targets = explode(" ", $argv[5]);
  8. $ext_targets = explode(" ", $argv[6]);
  9. $pecl_targets = explode(" ", $argv[7]);
  10. $snapshot_template = $argv[8];
  11. $is_debug = preg_match("/^debug/i", $build_dir);
  12. echo "Making dist for $build_dir\n";
  13. $dist_dir = $build_dir . "/php-" . $php_version;
  14. $test_dir = $build_dir . "/php-test-pack-" . $php_version;
  15. $pecl_dir = $build_dir . "/pecl-" . $php_version;
  16. @mkdir($dist_dir);
  17. @mkdir("$dist_dir/ext");
  18. @mkdir("$dist_dir/dev");
  19. @mkdir("$dist_dir/extras");
  20. @mkdir($pecl_dir);
  21. /* figure out additional DLL's that are required */
  22. $extra_dll_deps = array();
  23. $per_module_deps = array();
  24. $pecl_dll_deps = array();
  25. function get_depends($module)
  26. {
  27. static $no_dist = array(
  28. /* windows system dlls that should not be bundled */
  29. 'advapi32.dll', 'comdlg32.dll', 'crypt32.dll', 'gdi32.dll', 'kernel32.dll', 'ntdll.dll',
  30. 'odbc32.dll', 'ole32.dll', 'oleaut32.dll', 'rpcrt4.dll',
  31. 'shell32.dll', 'shlwapi.dll', 'user32.dll', 'ws2_32.dll', 'ws2help.dll',
  32. 'comctl32.dll', 'winmm.dll', 'wsock32.dll', 'winspool.drv', 'msasn1.dll',
  33. 'secur32.dll', 'netapi32.dll', 'dnsapi.dll', 'psapi.dll', 'normaliz.dll',
  34. 'iphlpapi.dll', 'bcrypt.dll',
  35. /* apache */
  36. 'apachecore.dll',
  37. /* apache 2 */
  38. 'libhttpd.dll', 'libapr.dll', 'libaprutil.dll','libapr-1.dll', 'libaprutil-1.dll',
  39. /* oracle */
  40. 'oci.dll', 'ociw32.dll',
  41. /* sybase */
  42. 'libcs.dll', 'libct.dll',
  43. /* firebird */
  44. 'fbclient.dll',
  45. /* visual C++; mscvrt.dll is present on everyones system,
  46. * but the debug version (msvcrtd.dll) and those from visual studio.net
  47. * (msvcrt7x.dll) are not */
  48. 'msvcrt.dll',
  49. 'msvcr90.dll',
  50. 'wldap32.dll',
  51. 'vcruntime140.dll',
  52. 'msvcp140.dll',
  53. );
  54. static $no_dist_re = array(
  55. "api-ms-win-crt-.+\.dll",
  56. );
  57. global $build_dir, $extra_dll_deps, $ext_targets, $sapi_targets, $pecl_targets, $phpdll, $per_module_deps, $pecl_dll_deps;
  58. $bd = strtolower(realpath($build_dir));
  59. $is_pecl = in_array($module, $pecl_targets);
  60. $cmd = "$GLOBALS[build_dir]\\deplister.exe \"$module\" \"$GLOBALS[build_dir]\"";
  61. $proc = proc_open($cmd,
  62. array(1 => array("pipe", "w")),
  63. $pipes);
  64. $n = 0;
  65. while (($line = fgetcsv($pipes[1]))) {
  66. $n++;
  67. $dep = strtolower($line[0]);
  68. $depbase = basename($dep);
  69. /* ignore stuff in our build dir, but only if it is
  70. * one of our targets */
  71. if (((in_array($depbase, $sapi_targets) ||
  72. in_array($depbase, $ext_targets) || in_array($depbase, $pecl_targets)) ||
  73. $depbase == $phpdll) && file_exists($GLOBALS['build_dir'] . "/$depbase")) {
  74. continue;
  75. }
  76. /* ignore some well-known system dlls */
  77. if (in_array(basename($dep), $no_dist)) {
  78. continue;
  79. } else {
  80. $skip = false;
  81. foreach ($no_dist_re as $re) {
  82. if (preg_match(",$re,", basename($dep)) > 0) {
  83. $skip = true;
  84. break;
  85. }
  86. }
  87. if ($skip) {
  88. continue;
  89. }
  90. }
  91. if ($is_pecl) {
  92. if (!in_array($dep, $pecl_dll_deps)) {
  93. $pecl_dll_deps[] = $dep;
  94. }
  95. } else {
  96. if (!in_array($dep, $extra_dll_deps)) {
  97. $extra_dll_deps[] = $dep;
  98. }
  99. }
  100. if (!isset($per_module_deps[basename($module)]) || !in_array($dep, $per_module_deps[basename($module)])) {
  101. $per_module_deps[basename($module)][] = $dep;
  102. //recursively check dll dependencies
  103. get_depends($dep);
  104. }
  105. }
  106. fclose($pipes[1]);
  107. proc_close($proc);
  108. //echo "Module $module [$n lines]\n";
  109. }
  110. function copy_file_list($source_dir, $dest_dir, $list)
  111. {
  112. global $is_debug, $dist_dir;
  113. foreach ($list as $item) {
  114. if (empty($item)) {
  115. continue;
  116. } elseif (!is_file($source_dir . DIRECTORY_SEPARATOR . $item)) {
  117. echo "WARNING: $item not found\n";
  118. continue;
  119. }
  120. echo "Copying $item from $source_dir to $dest_dir\n";
  121. copy($source_dir . DIRECTORY_SEPARATOR . $item, $dest_dir . DIRECTORY_SEPARATOR . $item);
  122. if ($is_debug) {
  123. $itemdb = preg_replace("/\.(exe|dll|lib)$/i", ".pdb", $item);
  124. if (file_exists("$source_dir/$itemdb")) {
  125. copy("$source_dir/$itemdb", "$dist_dir/dev/$itemdb");
  126. }
  127. }
  128. if (preg_match("/\.(exe|dll)$/i", $item)) {
  129. get_depends($source_dir . '/' . $item);
  130. }
  131. }
  132. }
  133. function copy_text_file($source, $dest)
  134. {
  135. $text = file_get_contents($source);
  136. $text = preg_replace("/(\r\n?)|\n/", "\r\n", $text);
  137. $fp = fopen($dest, "w");
  138. fwrite($fp, $text);
  139. fclose($fp);
  140. }
  141. /* very light-weight function to extract a single named file from
  142. * a gzipped tarball. This makes assumptions about the files
  143. * based on the PEAR info set in $packages. */
  144. function extract_file_from_tarball($pkg, $filename, $dest_dir) /* {{{ */
  145. {
  146. global $packages;
  147. $name = $pkg . '-' . $packages[$pkg];
  148. $tarball = $dest_dir . "/" . $name . '.tgz';
  149. $filename = $name . '/' . $filename;
  150. $destfilename = $dest_dir . "/" . basename($filename);
  151. $fp = gzopen($tarball, 'rb');
  152. $done = false;
  153. do {
  154. /* read the header */
  155. $hdr_data = gzread($fp, 512);
  156. if (strlen($hdr_data) == 0)
  157. break;
  158. $checksum = 0;
  159. for ($i = 0; $i < 148; $i++)
  160. $checksum += ord($hdr_data{$i});
  161. for ($i = 148; $i < 156; $i++)
  162. $checksum += 32;
  163. for ($i = 156; $i < 512; $i++)
  164. $checksum += ord($hdr_data{$i});
  165. $hdr = unpack("a100filename/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor", $hdr_data);
  166. $hdr['checksum'] = octdec(trim($hdr['checksum']));
  167. if ($hdr['checksum'] != $checksum) {
  168. echo "Checksum for $tarball $hdr[filename] is invalid\n";
  169. print_r($hdr);
  170. return;
  171. }
  172. $hdr['size'] = octdec(trim($hdr['size']));
  173. echo "File: $hdr[filename] $hdr[size]\n";
  174. if ($filename == $hdr['filename']) {
  175. echo "Found the file we want\n";
  176. $dest = fopen($destfilename, 'wb');
  177. $x = stream_copy_to_stream($fp, $dest, $hdr['size']);
  178. fclose($dest);
  179. echo "Wrote $x bytes into $destfilename\n";
  180. break;
  181. }
  182. /* skip body of the file */
  183. $size = 512 * ceil((int)$hdr['size'] / 512);
  184. echo "Skipping $size bytes\n";
  185. gzseek($fp, gztell($fp) + $size);
  186. } while (!$done);
  187. } /* }}} */
  188. /* the core dll */
  189. copy("$build_dir/php.exe", "$dist_dir/php.exe");
  190. /* copy dll and its dependencies */
  191. copy_file_list($build_dir, "$dist_dir", [$phpdll]);
  192. /* and the .lib goes into dev */
  193. $phplib = str_replace(".dll", ".lib", $phpdll);
  194. copy("$build_dir/$phplib", "$dist_dir/dev/$phplib");
  195. /* debug builds; copy the symbols too */
  196. if ($is_debug) {
  197. $phppdb = str_replace(".dll", ".pdb", $phpdll);
  198. copy("$build_dir/$phppdb", "$dist_dir/dev/$phppdb");
  199. }
  200. /* copy the sapi */
  201. copy_file_list($build_dir, "$dist_dir", $sapi_targets);
  202. /* copy the extensions */
  203. copy_file_list($build_dir, "$dist_dir/ext", $ext_targets);
  204. /* pecl sapi and extensions */
  205. if(sizeof($pecl_targets)) {
  206. copy_file_list($build_dir, $pecl_dir, $pecl_targets);
  207. }
  208. /* populate reading material */
  209. $text_files = array(
  210. "LICENSE" => "license.txt",
  211. "NEWS" => "news.txt",
  212. "README.md" => "README.md",
  213. "README.REDIST.BINS" => "readme-redist-bins.txt",
  214. "php.ini-development" => "php.ini-development",
  215. "php.ini-production" => "php.ini-production"
  216. );
  217. foreach ($text_files as $src => $dest) {
  218. copy_text_file($src, $dist_dir . '/' . $dest);
  219. }
  220. /* general other files */
  221. $general_files = array(
  222. "$GLOBALS[build_dir]\\deplister.exe" => "deplister.exe",
  223. );
  224. foreach ($general_files as $src => $dest) {
  225. copy($src, $dist_dir . '/' . $dest);
  226. }
  227. /* include a snapshot identifier */
  228. $branch = "HEAD"; // TODO - determine this from SVN branche name
  229. $fp = fopen("$dist_dir/snapshot.txt", "w");
  230. $now = date("r");
  231. fwrite($fp, <<<EOT
  232. This snapshot was automatically generated on
  233. $now
  234. Version: $php_version
  235. Branch: $branch
  236. Build: $build_dir
  237. EOT
  238. );
  239. /* list built-in extensions */
  240. $exts = get_loaded_extensions();
  241. fprintf($fp, "\r\nBuilt-in Extensions\r\n");
  242. fwrite($fp, "===========================\r\n");
  243. foreach ($exts as $ext) {
  244. fprintf($fp, "%s\r\n", $ext);
  245. }
  246. fwrite($fp, "\r\n\r\n");
  247. /* list dependencies */
  248. fprintf($fp, "Dependency information:\r\n");
  249. foreach ($per_module_deps as $modulename => $deps) {
  250. if (in_array($modulename, $pecl_targets))
  251. continue;
  252. fprintf($fp, "Module: %s\r\n", $modulename);
  253. fwrite($fp, "===========================\r\n");
  254. foreach ($deps as $dll) {
  255. fprintf($fp, "\t%s\r\n", basename($dll));
  256. }
  257. fwrite($fp, "\r\n");
  258. }
  259. fclose($fp);
  260. /* Now add those dependencies */
  261. foreach ($extra_dll_deps as $dll) {
  262. if (!file_exists($dll)) {
  263. /* try template dir */
  264. $tdll = $snapshot_template . "/dlls/" . basename($dll);
  265. if (!file_exists($tdll)) {
  266. $tdll = $php_build_dir . '/bin/' . basename($dll);
  267. if (!file_exists($tdll)) {
  268. echo "WARNING: distro depends on $dll, but could not find it on your system\n";
  269. continue;
  270. }
  271. }
  272. $dll = $tdll;
  273. }
  274. copy($dll, "$dist_dir/" . basename($dll));
  275. }
  276. /* TODO:
  277. add sanity check and test if all required DLLs are present, per version
  278. This version works at least for 3.6, 3.8 and 4.0 (5.3-vc6, 5.3-vc9 and HEAD).
  279. Add ADD_DLLS to add extra DLLs like dynamic dependencies for standard
  280. deps. For example, libenchant.dll loads libenchant_myspell.dll or
  281. libenchant_ispell.dll
  282. */
  283. $ENCHANT_DLLS = array(
  284. array('', 'glib-2.dll'),
  285. array('', 'gmodule-2.dll'),
  286. );
  287. if (file_exists("$php_build_dir/bin/libenchant2.dll")) {
  288. $ENCHANT_DLLS[] = array('lib/enchant', 'libenchant2_hunspell.dll');
  289. } else {
  290. $ENCHANT_DLLS[] = array('lib/enchant', 'libenchant_myspell.dll');
  291. $ENCHANT_DLLS[] = array('lib/enchant', 'libenchant_ispell.dll');
  292. }
  293. foreach ($ENCHANT_DLLS as $dll) {
  294. $dest = "$dist_dir/$dll[0]";
  295. $filename = $dll[1];
  296. if (!file_exists("$dest") || !is_dir("$dest")) {
  297. if (!mkdir("$dest", 0777, true)) {
  298. echo "WARNING: couldn't create '$dest' for enchant plugins ";
  299. }
  300. }
  301. if (!copy($php_build_dir . '/bin/' . $filename, "$dest/" . basename($filename))) {
  302. echo "WARNING: couldn't copy $filename into the dist dir";
  303. }
  304. }
  305. $SASL_DLLS = $php_build_dir . "/bin/sasl2/sasl*.dll";
  306. $fls = glob($SASL_DLLS);
  307. if (!empty($fls)) {
  308. $sasl_dest_dir = "$dist_dir/sasl2";
  309. if (!file_exists($sasl_dest_dir) || !is_dir($sasl_dest_dir)) {
  310. if (!mkdir("$sasl_dest_dir", 0777, true)) {
  311. echo "WARNING: couldn't create '$sasl_dest_dir' for SASL2 auth plugins ";
  312. }
  313. }
  314. foreach ($fls as $fl) {
  315. if (!copy($fl, "$sasl_dest_dir/" . basename($fl))) {
  316. echo "WARNING: couldn't copy $fl into the $sasl_dest_dir";
  317. }
  318. }
  319. }
  320. /* and those for pecl */
  321. foreach ($pecl_dll_deps as $dll) {
  322. if (in_array($dll, $extra_dll_deps)) {
  323. /* already in main distro */
  324. continue;
  325. }
  326. if (!file_exists($dll)) {
  327. /* try template dir */
  328. $tdll = $snapshot_template . "/dlls/" . basename($dll);
  329. if (!file_exists($tdll)) {
  330. echo "WARNING: distro depends on $dll, but could not find it on your system\n";
  331. continue;
  332. }
  333. $dll = $tdll;
  334. }
  335. copy($dll, "$pecl_dir/" . basename($dll));
  336. }
  337. function copy_dir($source, $dest)
  338. {
  339. if (!is_dir($dest)) {
  340. if (!mkdir($dest)) {
  341. return false;
  342. }
  343. }
  344. $d = opendir($source);
  345. while (($f = readdir($d)) !== false) {
  346. if ($f == '.' || $f == '..' || $f == '.svn') {
  347. continue;
  348. }
  349. $fs = $source . '/' . $f;
  350. $fd = $dest . '/' . $f;
  351. if (is_dir($fs)) {
  352. copy_dir($fs, $fd);
  353. } else {
  354. copy($fs, $fd);
  355. }
  356. }
  357. closedir($d);
  358. }
  359. function copy_test_dir($directory, $dest)
  360. {
  361. if(substr($directory,-1) == '/') {
  362. $directory = substr($directory,0,-1);
  363. }
  364. if ($directory == 'tests' || $directory == 'examples') {
  365. if (!is_dir($dest . '/tests')) {
  366. mkdir($dest . '/tests', 0775, true);
  367. }
  368. copy_dir($directory, $dest . '/tests/');
  369. return false;
  370. }
  371. if(!file_exists($directory) || !is_dir($directory)) {
  372. echo "failed... $directory\n";
  373. return FALSE;
  374. }
  375. $directory_list = opendir($directory);
  376. while (FALSE !== ($file = readdir($directory_list))) {
  377. $full_path = $directory . '/' . $file;
  378. if($file != '.' && $file != '..' && $file != '.svn' && is_dir($full_path)) {
  379. if ($file == 'tests' || $file == 'examples') {
  380. if (!is_dir($dest . '/' . $full_path)) {
  381. mkdir($dest . '/' . $full_path , 0775, true);
  382. }
  383. copy_dir($full_path, $dest . '/' . $full_path . '/');
  384. continue;
  385. } else {
  386. copy_test_dir($full_path, $dest);
  387. }
  388. }
  389. }
  390. closedir($directory_list);
  391. }
  392. function make_phar_dot_phar($dist_dir)
  393. {
  394. if (!extension_loaded('phar')) {
  395. return;
  396. }
  397. $path_to_phar = realpath(__DIR__ . '/../../ext/phar');
  398. echo "Generating pharcommand.phar\n";
  399. $phar = new Phar($dist_dir . '/pharcommand.phar', 0, 'pharcommand');
  400. foreach (new DirectoryIterator($path_to_phar . '/phar') as $file) {
  401. if ($file->isDir() || $file == 'phar.php') {
  402. continue;
  403. }
  404. echo 'adding ', $file, "\n";
  405. $phar[(string) $file] = file_get_contents($path_to_phar. '/phar/' . $file);
  406. }
  407. $phar->setSignatureAlgorithm(Phar::SHA1);
  408. $stub = file($path_to_phar . '/phar/phar.php');
  409. unset($stub[0]); // remove hashbang
  410. $phar->setStub(implode('', $stub));
  411. echo "Creating phar.phar.bat\n";
  412. file_put_contents($dist_dir . '/phar.phar.bat', "\"%~dp0php.exe\" \"%~dp0pharcommand.phar\" %*\r\n");
  413. }
  414. if (!is_dir($test_dir)) {
  415. mkdir($test_dir);
  416. }
  417. $dirs = array(
  418. 'ext',
  419. 'Sapi',
  420. 'Zend',
  421. 'tests'
  422. );
  423. foreach ($dirs as $dir) {
  424. copy_test_dir($dir, $test_dir);
  425. }
  426. copy('run-tests.php', $test_dir . '/run-tests.php');
  427. /* change this next line to true to use good-old
  428. * hand-assembled go-pear-bundle from the snapshot template */
  429. $use_pear_template = true;
  430. if (!$use_pear_template) {
  431. /* Let's do a PEAR-less pear setup */
  432. mkdir("$dist_dir/PEAR");
  433. mkdir("$dist_dir/PEAR/go-pear-bundle");
  434. /* grab the bootstrap script */
  435. echo "Downloading go-pear\n";
  436. copy("https://pear.php.net/go-pear.phar", "$dist_dir/PEAR/go-pear.php");
  437. /* import the package list -- sets $packages variable */
  438. include "pear/go-pear-list.php";
  439. /* download the packages into the destination */
  440. echo "Fetching packages\n";
  441. foreach ($packages as $name => $version) {
  442. $filename = "$name-$version.tgz";
  443. $destfilename = "$dist_dir/PEAR/go-pear-bundle/$filename";
  444. if (file_exists($destfilename))
  445. continue;
  446. $url = "http://pear.php.net/get/$filename";
  447. echo "Downloading $name from $url\n";
  448. flush();
  449. copy($url, $destfilename);
  450. }
  451. echo "Download complete. Extracting bootstrap files\n";
  452. /* Now, we want PEAR.php, Getopt.php (Console_Getopt) and Tar.php (Archive_Tar)
  453. * broken out of the tarballs */
  454. extract_file_from_tarball('PEAR', 'PEAR.php', "$dist_dir/PEAR/go-pear-bundle");
  455. extract_file_from_tarball('Archive_Tar', 'Archive/Tar.php', "$dist_dir/PEAR/go-pear-bundle");
  456. extract_file_from_tarball('Console_Getopt', 'Console/Getopt.php', "$dist_dir/PEAR/go-pear-bundle");
  457. }
  458. /* add extras from the template dir */
  459. if (file_exists($snapshot_template)) {
  460. $items = glob("$snapshot_template/*");
  461. print_r($items);
  462. foreach ($items as $item) {
  463. $bi = basename($item);
  464. if (is_dir($item)) {
  465. if ($bi == 'dlls' || $bi == 'symbols') {
  466. continue;
  467. } else if ($bi == 'PEAR') {
  468. if ($use_pear_template) {
  469. /* copy to top level */
  470. copy_dir($item, "$dist_dir/$bi");
  471. }
  472. } else {
  473. /* copy that dir into extras */
  474. copy_dir($item, "$dist_dir/extras/$bi");
  475. }
  476. } else {
  477. if ($bi == 'go-pear.bat') {
  478. /* copy to top level */
  479. copy($item, "$dist_dir/$bi");
  480. } else {
  481. /* copy to extras */
  482. copy($item, "$dist_dir/extras/$bi");
  483. }
  484. }
  485. }
  486. /* copy c++ runtime */
  487. $items = glob("$snapshot_template/dlls/*.CRT");
  488. foreach ($items as $item) {
  489. $bi = basename($item);
  490. if (is_dir($item)) {
  491. copy_dir($item, "$dist_dir/$bi");
  492. copy_dir($item, "$dist_dir/ext/$bi");
  493. }
  494. }
  495. } else {
  496. echo "WARNING: you don't have a snapshot template, your dist will not be complete\n";
  497. }
  498. make_phar_dot_phar($dist_dir);
  499. ?>