Viewing file: Extension.php (61.42 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php /** * A class that generates PECL extension soure and documenation files * * PHP versions 5 * * LICENSE: This source file is subject to version 3.0 of the PHP license * that is available through the world-wide-web at the following URI: * http://www.php.net/license/3_0.txt. If you did not receive a copy of * the PHP License and are unable to obtain it through the web, please * send a note to license@php.net so we can mail you a copy immediately. * * @category Tools and Utilities * @package CodeGen_PECL * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version CVS: $Id: Extension.php,v 1.53 2006/08/16 10:40:51 hholzgra Exp $ * @link http://pear.php.net/package/CodeGen_PECL */
/** * includes */ require_once "System.php";
require_once "CodeGen/Extension.php";
require_once "CodeGen/PECL/Release.php";
require_once "CodeGen/PECL/Element.php"; require_once "CodeGen/PECL/Element/Constant.php"; require_once "CodeGen/PECL/Element/Function.php"; require_once "CodeGen/PECL/Element/Resource.php"; require_once "CodeGen/PECL/Element/Ini.php"; require_once "CodeGen/PECL/Element/Global.php"; require_once "CodeGen/PECL/Element/Logo.php"; require_once "CodeGen/PECL/Element/Test.php"; require_once "CodeGen/PECL/Element/Class.php"; require_once "CodeGen/PECL/Element/Interface.php"; require_once "CodeGen/PECL/Element/Stream.php";
require_once "CodeGen/PECL/Dependency/With.php"; require_once "CodeGen/PECL/Dependency/Lib.php"; require_once "CodeGen/PECL/Dependency/Header.php"; require_once "CodeGen/PECL/Dependency/Extension.php"; require_once "CodeGen/PECL/Dependency/Platform.php";
/** * A class that generates PECL extension soure and documenation files * * @category Tools and Utilities * @package CodeGen_PECL * @author Hartmut Holzgraefe <hartmut@php.net> * @copyright 2005 Hartmut Holzgraefe * @license http://www.php.net/license/3_0.txt PHP License 3.0 * @version Release: 1.0.3 * @link http://pear.php.net/package/CodeGen_PECL */ class CodeGen_PECL_Extension extends CodeGen_Extension { /** * Current CodeGen_PECL version number * * @return string */ function version() { return "1.0.3"; }
/** * CodeGen_PECL Copyright message * * @return string */ function copyright() { return "Copyright (c) 2003-2005 Hartmut Holzgraefe"; }
// {{{ member variables
/** * The public PHP functions defined by this extension * * @var array */ protected $functions = array(); /** * The extensions internal functions like MINIT * * @var array */ protected $internalFunctions = array(); /** * The constants defined by this extension * * @var array */ protected $constants = array(); /** * The PHP classes defined by this extension * * @var array */ protected $classes = array(); /** * The PHP interfaces defined by this extension * * @var array */ protected $interfaces = array(); /** * The extensions php.ini parameters * * @var array */ protected $phpini = array(); /** * The extensions internal global variables * * @var array */ protected $globals = array();
/** * The PHP resources defined by this extension * * @var array */ protected $resources = array();
/** * Custom test cases * * @var array */ protected $testcases = array();
/** * phpinfo logos * * @var string * @access private */ protected $logos = array();
/** * cross extension dependencies * * @var array */ protected $otherExtensions = array();
/** * Makefile fragments * * @var array * @access private */ protected $makefragments = array();
/** * config.m4 fragments * * @var array * @access private */ protected $configfragments = array("top"=>array(), "bottom"=>array());
/** * generate #line specs? * * @var bool * @access private */ protected $linespecs = false;
/** * PHP Streams * * @var array * @access private */ protected $streams = array();
/** * --with configure options * * @var array * @access private */ protected $with = array();
/** * pear installer channel name * * @var string * @access private */ protected $channel = "pecl.php.net";
// }}}
// {{{ constructor /** * The constructor * * @access public */ function __construct() { $this->release = new CodeGen_PECL_Release; $this->platform = new CodeGen_PECL_Dependency_Platform("all");
parent::__construct(); } // }}}
// {{{ member adding functions
/** * Add a function to the extension * * @access public * @param object a function object */ function addFunction(CodeGen_PECL_Element_Function $function) { $name = $function->getName(); $role = $function->getRole(); switch ($role) { case "public": if (isset($this->functions[$name])) { return PEAR::raiseError("public function '$name' has been defined before"); } $this->functions[$name] = $function; return true; case "private": return PEAR::raiseError("private functions are no longer supported, use <code> sections instead"); case "internal": if (isset($this->internalFunctions[$name])) { return PEAR::raiseError("internal '$name' has been defined before"); } $this->internalFunctions[$name] = $function; return true; default: return PEAR::raiseError("unnokwn function role '$role'"); } }
/** * Set target platform for generated code * * @access public * @param string platform name */ function setPlatform($type) { $this->platform = new CodeGen_PECL_Dependency_Platform($type); if (PEAR::isError($this->platform)) { return $this->platform; } return true; }
/** * Add a PHP constant to the extension * * @access public * @param object a constant object */ function addConstant(CodeGen_PECL_Element_Constant $constant) { $name = $constant->getName();
if (isset($this->constants[$name])) { return PEAR::raiseError("constant '$name' has been defined before"); } $this->constants[$name] = $constant; return true; }
/** * Add a PHP ini directive * * @access public * @param object a phpini object */ function addPhpIni(CodeGen_PECL_Element_Ini $phpini) { $name = $phpini->getName();
if (isset($this->phpini[$name])) { return PEAR::raiseError("php.ini directive '$name' has been defined before"); } $this->phpini[$name] = $phpini; return true; }
/** * Add a internal global variable * * @access public * @param object a global object */ function addGlobal(CodeGen_PECL_Element_Global $global) { $name = $global->getName(); if (isset($this->globals[$name])) { return PEAR::raiseError("global '{$name}' has been defined before"); } $this->globals[$name] = $global; return true; }
/** * Add a PHP resource type * * @access public * @param object a resource object */ function addResource(CodeGen_PECL_Element_Resource $resource) { $name = $resource->getName(); if (isset($this->resources[$name])) { return PEAR::raiseError("resource type '{$name}' has been defined before"); } $this->resources[$name] = $resource; return true; } /** * Get PHP resource types * * @access public * @return array */ function getResources() { return $this->resources; }
/** * Get PHP constants * * @access public * @return array */ function getConstants() { return $this->constants; }
/** * Add a PHP class to the extension * * @access public * @param object a class object */ function addClass(CodeGen_PECL_Element_Class $class) { if (isset($this->classes[$class->getName()])) { return PEAR::raiseError("class '".$class->getName()."' has been defined before"); } $this->classes[$class->getName()] = $class; return true; } /** * Add a PHP interface to the extension * * @access public * @param object an interface object */ function addInterface(CodeGen_PECL_Element_Interface $interface) { if (isset($this->interfaces[$interface->getName()])) { return PEAR::raiseError("interface '".$interface->getName()."' has been defined before"); } $this->interfaces[$interface->getName()] = $interface; return true; } /** * Add a PHP stream wrapper to the extension * * @access public * @param object a stream wrapper object */ function addStream(CodeGen_PECL_Element_Stream $stream) { if (isset($this->streams[$stream->getName()])) { return PEAR::raiseError("stream '".$stream->getName()."' has been defined before"); } $this->streams[$stream->getName()] = $stream; return true; } /** * Add a --with configure option * * @access public * @param object 'With' object * @returns bool */ function addWith(CodeGen_PECL_Dependency_With $with) { $name = $with->getName();
if (isset($this->with[$name])) { return PEAR::raiseError("--with-{$name} declared twice"); }
$this->with[$name] = $with;
return true; }
/** * Add phpinfo logo * * @access public * @param object the logo */ function addLogo(CodeGen_PECL_Element_Logo $logo) { $name = $logo->getName();
if (isset($this->logos[$name])) { return PEAR::raiseError("logo '{$name}' already defined"); }
$this->logos[$name] = $logo; return true; }
/** * Add cross-module dependency * * @param object extension dependency object */ function addOtherExtension(CodeGen_PECL_Dependency_Extension $ext) { $name = $ext->getName();
if (isset($this->otherExtensions[$name])) { return PEAR::raiseError("dependency to extension '{$name}' already defined"); }
$this->otherExtensions[$name] = $ext; return true; } /** * Generate #line specs? * * @access public * @param bool */ function setLinespecs($state) { $this->linespecs = $state; }
/** * linespec getter * * @access public * @return bool */ function getLinespecs() { return $this->linespecs; }
// }}}
// {{{ output generation
/** * Create the extensions including * * @access public * @param string Directory to create (default is ./$this->name) */ function createExtension($dirpath = false, $force = false) { // default: create dir in current working directory, // dirname is the extensions base name if (!is_string($dirpath) || $dirpath == "") { $dirpath = "./" . $this->name; } // purge and create extension directory if ($dirpath !== ".") { if (!$force && file_exists($dirpath)) { return PEAR::raiseError("'$dirpath' already exists, can't create that directory (use '--force' to override)"); } else if (!@System::mkdir("-p $dirpath")) { return PEAR::raiseError("can't create '$dirpath'"); } } // make path absolute to be independant of working directory changes $this->dirpath = realpath($dirpath); echo "Creating '{$this->name}' extension in '$dirpath'\n";
// generate complete source code $this->generateSource();
// copy additional source files if (isset($this->packageFiles['copy'])) { foreach ($this->packageFiles['copy'] as $targetpath => $sourcepath) { $targetpath = $this->dirpath."/".$targetpath; if (!is_dir(dirname($targetpath))) { mkdir(dirname($targetpath), 0777, true); } copy($sourcepath, $targetpath); } } // generate README file $this->writeReadme(); // generate DocBook XML documantation for PHP manual $manpath = $this->dirpath . "/manual/" . str_replace('_', '-', $this->name); if (!@System::mkdir("-p $manpath")) { return PEAR::raiseError("can't create '$manpath'", E_USER_ERROR); } $this->generateDocumentation($manpath); } /** * Create the extensions code soure and project files * * @access public */ function generateSource() { // generate source and header files $this->writeHeaderFile(); $this->writeCodeFile();
foreach($this->logos as $logo) { $fp = new CodeGen_Tools_FileReplacer("{$this->dirpath}/".$logo->getName()."_logos.h"); $fp->puts($logo->hCode()); $fp->close(); } // generate project files for configure (unices and similar platforms like cygwin) if ($this->platform->test("unix")) { $this->writeConfigM4(); } // generate project files for Windows platform (VisualStudio/C++ V6) if ($this->platform->test("windows")) { $this->writeMsDevStudioDsp(); $this->writeConfigW32(); } // generate .cvsignore file entries $this->writeDotCvsignore();
// generate EXPERIMENTAL file for unstable release states $this->writeExperimental(); // generate CREDITS file $this->writeCredits(); // generate LICENSE file if license given if ($this->license) { $this->license->writeToFile($this->dirpath."/LICENSE"); $this->files['doc'][] = "LICENSE"; } // generate test case templates $this->writeTestFiles();
// generate PEAR/PECL package.xml file $this->writePackageXml(); $this->writePackageXml2(); } // {{{ docbook documentation
/** * Create the extension documentation DocBook XML files * * @access public * @param string Directory to write to */ function generateDocumentation($docdir) { $idName = str_replace('_', '-', $this->name); $fp = new CodeGen_Tools_FileReplacer("$docdir/reference.xml"); $fp->puts( "<?xml version='1.0' encoding='iso-8859-1'?> <!-- ".'$'."Revision: 1.1 $ --> <reference id='ref.$idName'> <title>{$this->summary}</title> <titleabbrev>$idName</titleabbrev>
<partintro> <section id='$idName.intro'> &reftitle.intro; <para> {$this->description} </para> </section> &reference.$idName.configure;
<section id='$idName.resources'> &reftitle.resources; ");
if (empty($this->resources)) { $fp->puts(" &no.resource;\n"); } else { foreach ($this->resources as $resource) { $fp->puts($resource->docEntry($idName)); } }
$fp->puts( " </section>
<section id='$idName.constants'> &reftitle.constants; ");
if (empty($this->constants)) { $fp->puts(" &no.constants;\n"); } else { $fp->puts(CodeGen_PECL_Element_Constant::docHeader($idName));
foreach ($this->constants as $constant) { $fp->puts($constant->docEntry($idName)); }
$fp->puts(CodeGen_PECL_Element_Constant::docFooter()); }
$fp->puts( " </section> </partintro>
&reference.$idName.functions;
</reference> ");
$fp->puts($this->docEditorSettings());
$fp->close(); // configure options and dependencies have their own file $fp = new CodeGen_Tools_FileReplacer("$docdir/configure.xml");
$fp->puts("\n <section id='$idName.requirements'>\n &reftitle.required;\n"); if (empty($this->libs) && empty($this->headers)) { $fp->puts(" &no.requirement;\n"); } else { // TODO allow custom text if (isset($this->libs)) { $libs = array(); foreach ($this->libs as $lib) { $libs[] = $lib->getName(); } $ies = count($libs)>1 ? "ies" :"y"; $fp->puts("<para>This extension requires the following librar$ies: ".join(",", $libs)."</para>\n"); } if (isset($this->headers)) { $headers = array(); foreach ($this->headers as $header) { $headers[] = $header->getName(); } $s = count($headers)>1 ? "s" : ""; $fp->puts("<para>This extension requires the following header$s: ".join(",", $headers)."</para>\n"); } } $fp->puts("\n </section>\n\n");
$fp->puts("\n <section id='$idName.install'>\n &reftitle.install;\n"); if (empty($this->with)) { $fp->puts(" &no.install;\n"); } else { foreach ($this->with as $with) { if (isset($with->summary)) { if (strstr($with->summary, "<para>")) { $fp->puts($with->summary); } else { $fp->puts(" <para>\n".rtrim($with->summary)."\n </para>\n"); } } else { // TODO default text } } } $fp->puts("\n </section>\n\n");
$fp->puts("\n <section id='$idName.configuration'>\n &reftitle.runtime;\n"); if (empty($this->phpini)) { $fp->puts(" &no.config;\n"); } else { $fp->puts(CodeGen_PECL_Element_Ini::docHeader($this->name)); foreach ($this->phpini as $phpini) { $fp->puts($phpini->docEntry($idName)); } $fp->puts(CodeGen_PECL_Element_Ini::docFooter()); } $fp->puts("\n </section>\n\n"); $fp->puts($this->docEditorSettings()); $fp->close();
@mkdir("$docdir/functions"); foreach ($this->functions as $name => $function) { $filename = $docdir . "/functions/" . strtolower(str_replace("_", "-", $name)) . ".xml"; $funcfile = new CodeGen_Tools_FileReplacer($filename); $funcfile->puts($function->docEntry($idName)); $funcfile->puts($this->docEditorSettings(4)); $funcfile->close(); } }
// }}}
// {{{ extension entry /** * Create the module entry code for this extension * * @access private * @return string zend_module_entry code fragment */ function generateExtensionEntry() { $name = $this->name; $upname = strtoupper($this->name);
$code = "";
if (empty($this->otherExtensions)) { $moduleHeader = " STANDARD_MODULE_HEADER,"; } else { $code.= CodeGen_PECL_Dependency_Extension::cCodeHeader($this); foreach ($this->otherExtensions as $ext) { $code.= $ext->cCode($this); } $code.= CodeGen_PECL_Dependency_Extension::cCodeFooter($this);
$moduleHeader = "#if ZEND_EXTENSION_API_NO >= 220050617 STANDARD_MODULE_HEADER_EX, NULL, {$this->name}_deps, #else STANDARD_MODULE_HEADER, #endif "; }
$code.= " /* {{{ {$name}_module_entry */ zend_module_entry {$name}_module_entry = { $moduleHeader \"$name\", {$name}_functions, PHP_MINIT($name), /* Replace with NULL if there is nothing to do at php startup */ PHP_MSHUTDOWN($name), /* Replace with NULL if there is nothing to do at php shutdown */ PHP_RINIT($name), /* Replace with NULL if there is nothing to do at request start */ PHP_RSHUTDOWN($name), /* Replace with NULL if there is nothing to do at request end */ PHP_MINFO($name), \"".$this->release->getVersion()."\", STANDARD_MODULE_PROPERTIES }; /* }}} */
";
$code .= "#ifdef COMPILE_DL_$upname\n"; if ($this->language == "cpp") { $code .= "extern \"C\" {\n"; } $code .= "ZEND_GET_MODULE($name)\n"; if ($this->language == "cpp") { $code .= "} // extern \"C\"\n"; } $code .= "#endif\n\n";
return $code; }
// }}}
// {{{ globals and ini /** * Create the module globals c code fragment * * @access private * @return string module globals code fragment */
function generateGlobalsC() { if (empty($this->globals)) return ""; $code = "\n/* {{{ globals and ini entries */\n"; $code .= "ZEND_DECLARE_MODULE_GLOBALS({$this->name})\n\n"; if (!empty($this->phpini)) { $code .= CodeGen_PECL_Element_Ini::cCodeHeader($this->name); foreach ($this->phpini as $phpini) { $code .= $phpini->cCode($this->name); } $code .= CodeGen_PECL_Element_Ini::cCodeFooter($this->name); } if (!empty($this->globals)) { $code .= CodeGen_PECL_Element_Global::cCodeHeader($this->name); foreach ($this->globals as $global) { $code .= $global->cCode($this->name); } $code .= CodeGen_PECL_Element_Global::cCodeFooter($this->name); } $code .= "/* }}} */\n\n"; return $code; } /** * Create the module globals c header file fragment * * @access private * @return string module globals code fragment */ function generateGlobalsH() { if (empty($this->globals)) return ""; $code = CodeGen_PECL_Element_Global::hCodeHeader($this->name); foreach ($this->globals as $global) { $code .= $global->hCode($this->name); } $code .= CodeGen_PECL_Element_Global::hCodeFooter($this->name); return $code; } // }}}
// {{{ /** * Create global function registration * * @access private * @return string function registration code fragments */ function generateFunctionRegistrations() { $code = "/* {{{ {$this->name}_functions[] */\n"; $code .= "function_entry {$this->name}_functions[] = {\n"; foreach ($this->functions as $function) { $code.= $function->functionEntry(); } foreach ($this->classes as $class) { $code.= $class->functionAliasEntries(); } $code .= " { NULL, NULL, NULL }\n"; $code .= "};\n/* }}} */\n\n";
return $code; } // }}} // {{{ /** * Create global class registration code and functions * * @access private * @return string class registration code fragments */ function generateClassRegistrations() { if (empty($this->classes)) return "";
$code = "/* {{{ Class definitions */\n\n";
foreach ($this->classes as $class) { $code .= $class->globalCode($this); }
$code .= "/* }}} Class definitions*/\n\n";
return $code; } // }}}
// {{{ /** * Create global interface registration code * * @access private * @return string interface registration code fragments */ function generateInterfaceRegistrations() { if (empty($this->interfaces)) return "";
$code = "/* {{{ Interface definitions */\n\n";
foreach ($this->interfaces as $interface) { $code .= $interface->globalCode($this); }
$code .= "/* }}} Interface definitions*/\n\n";
return $code; } // }}}
// {{{ license and authoers /** * Set license * * @access public * @param object */ function setLicense($license) { if ($license->getShortName() == "GPL") { return PEAR::raiseError("The GPL is no valid choice for PHP extensions due to license incompatibilities"); } $this->license = $license; return true; }
/** * Create the license part of the source file header comment * * @access private * @return string code fragment */ function getLicense() { $code = "/*\n"; $code.= " +----------------------------------------------------------------------+\n"; if (is_object($this->license)) { $code.= $this->license->getComment(); } else { $code.= sprintf(" | unknown license: %-52s |\n", $this->license); } $code.= " +----------------------------------------------------------------------+\n"; foreach ($this->authors as $author) { $code.= $author->comment(); } $code.= " +----------------------------------------------------------------------+\n"; $code.= "*/\n\n"; $code.= "/* $ Id: $ */ \n\n"; return $code; } // }}}
/** * Set pear installer channel * * @access public * @param string */ function setChannel($channel) { if (! preg_match('/^[a-z\-_\.]+$/i', $channel)) { return PEAR::raiseError("'$channel' is not a valid pear installer channel name"); }
$this->channel = $channel; }
// {{{ header file
/** * Write the complete C header file * * @access private * @param string directory to write to */ function writeHeaderFile() { $this->addPackageFile('header', "php_{$this->name}.h");
$file = new CodeGen_Tools_Outbuf($this->dirpath."/php_{$this->name}.h"); $upname = strtoupper($this->name); echo $this->getLicense(); echo "#ifndef PHP_{$upname}_H\n"; echo "#define PHP_{$upname}_H\n\n"; foreach ($this->headers as $header) { echo $header->hCode(true); } echo "#ifdef __cplusplus\n"; echo "extern \"C\" {\n"; echo "#endif\n";
echo ' #ifdef HAVE_CONFIG_H #include "config.h" #endif
#include <php.h>
#ifdef HAVE_'.$upname.'
#include <php_ini.h> #include <SAPI.h> #include <ext/standard/info.h> #include <Zend/zend_extensions.h> ';
echo "#ifdef __cplusplus\n"; echo "} // extern \"C\" \n"; echo "#endif\n";
foreach ($this->headers as $header) { echo $header->hCode(false); }
foreach ($this->with as $with) { foreach ($with->getHeaders() as $header) { echo $header->hCode(false); } }
if (isset($this->code["header"]["top"])) { foreach ($this->code["header"]["top"] as $code) { echo $this->codegen->block($code, 0); } }
echo "#ifdef __cplusplus\n"; echo "extern \"C\" {\n"; echo "#endif\n";
echo " extern zend_module_entry {$this->name}_module_entry; #define phpext_{$this->name}_ptr &{$this->name}_module_entry
#ifdef PHP_WIN32 #define PHP_{$upname}_API __declspec(dllexport) #else #define PHP_{$upname}_API #endif
PHP_MINIT_FUNCTION({$this->name}); PHP_MSHUTDOWN_FUNCTION({$this->name}); PHP_RINIT_FUNCTION({$this->name}); PHP_RSHUTDOWN_FUNCTION({$this->name}); PHP_MINFO_FUNCTION({$this->name});
#ifdef ZTS #include \"TSRM.h\" #endif
#define FREE_RESOURCE(resource) zend_list_delete(Z_LVAL_P(resource))
#define PROP_GET_LONG(name) Z_LVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC)) #define PROP_SET_LONG(name, l) zend_update_property_long(_this_ce, _this_zval, #name, strlen(#name), l TSRMLS_CC)
#define PROP_GET_DOUBLE(name) Z_DVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC)) #define PROP_SET_DOUBLE(name, d) zend_update_property_double(_this_ce, _this_zval, #name, strlen(#name), d TSRMLS_CC)
#define PROP_GET_STRING(name) Z_STRVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC)) #define PROP_GET_STRLEN(name) Z_STRLEN_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC)) #define PROP_SET_STRING(name, s) zend_update_property_string(_this_ce, _this_zval, #name, strlen(#name), s TSRMLS_CC) #define PROP_SET_STRINGL(name, s, l) zend_update_property_string(_this_ce, _this_zval, #name, strlen(#name), s, l TSRMLS_CC)
";
echo $this->generateGlobalsH();
echo "\n";
foreach ($this->functions as $name => $function) { echo $function->hCode($this); }
foreach ($this->classes as $name => $class) { echo $class->hCode($this); }
foreach ($this->interfaces as $name => $interface) { echo $interface->hCode($this); }
foreach ($this->streams as $name => $stream) { echo $this->codegen->block($stream->hCode()); }
echo "#ifdef __cplusplus\n"; echo "} // extern \"C\" \n"; echo "#endif\n"; echo "\n";
// write #defines for <constant>s $defines = ""; foreach ($this->constants as $constant) { $defines.= $constant->hCode($this); } if ($defines !== "") { echo "/* mirrored PHP Constants */\n"; echo $defines; echo "\n"; } // add bottom header snippets if (isset($this->code["header"]["bottom"])) { echo "/* 'bottom' header snippets*/\n"; foreach ($this->code["header"]["bottom"] as $code) { echo $this->codegen->block($code, 0); } echo "\n"; }
echo "#endif /* PHP_HAVE_{$upname} */\n\n"; echo "#endif /* PHP_{$upname}_H */\n\n";
echo $this->cCodeEditorSettings();
return $file->write(); }
// }}}
// {{{ internal functions
/** * Create code for the internal functions like MINIT etc ... * * @access private * @return string code snippet */ function internalFunctionsC() { $need_block = false; $code = " /* {{{ PHP_MINIT_FUNCTION */ PHP_MINIT_FUNCTION({$this->name}) { ";
if (count($this->globals)) { $code .= " ZEND_INIT_MODULE_GLOBALS({$this->name}, php_{$this->name}_init_globals, php_{$this->name}_shutdown_globals)\n"; $need_block = true; }
if (count($this->phpini)) { $code .= " REGISTER_INI_ENTRIES();\n"; $need_block = true; } foreach ($this->logos as $logo) { $code .= $this->codegen->block($logo->minitCode()); $need_block = true; } if (count($this->constants)) { foreach ($this->constants as $constant) { $code .= $this->codegen->block($constant->cCode($this->name)); } $need_block = true; } if (count($this->resources)) { foreach ($this->resources as $resource) { $code .= $this->codegen->block($resource->minitCode()); } $need_block = true; }
if (count($this->classes)) { foreach ($this->classes as $class) { $code .= $this->codegen->block($class->minitCode($this)); } $need_block = true; }
if (count($this->interfaces)) { foreach ($this->interfaces as $interface) { $code .= $this->codegen->block($interface->minitCode($this)); } $need_block = true; } if (count($this->streams)) { foreach ($this->streams as $stream) { $code .= $this->codegen->block($stream->minitCode($this)); } $need_block = true; } if (isset($this->internalFunctions['MINIT'])) { $code .= $this->codegen->varblock($this->internalFunctions['MINIT']->getCode()); } else { $code .="\n /* add your stuff here */\n"; } $code .= " return SUCCESS; } /* }}} */
"; $code .= " /* {{{ PHP_MSHUTDOWN_FUNCTION */ PHP_MSHUTDOWN_FUNCTION({$this->name}) { "; if (count($this->phpini)) { $code .= " UNREGISTER_INI_ENTRIES();\n"; $need_block = true; }
if (count($this->logos)) { foreach ($this->logos as $logo) { $code .= $this->codegen->block($logo->mshutdownCode()); } $need_block = true; } if (isset($this->internalFunctions['MSHUTDOWN'])) { $code .= $this->codegen->varblock($this->internalFunctions['MSHUTDOWN']->getCode()); } else { $code .="\n /* add your stuff here */\n"; }
$code .= " return SUCCESS; } /* }}} */
"; $code .= " /* {{{ PHP_RINIT_FUNCTION */ PHP_RINIT_FUNCTION({$this->name}) { ";
if (isset($this->internalFunctions['RINIT'])) { $code .= $this->codegen->block($this->internalFunctions['RINIT']->getCode()); } else { $code .= " /* add your stuff here */\n"; }
$code .= " return SUCCESS; } /* }}} */
";
$code .= " /* {{{ PHP_RSHUTDOWN_FUNCTION */ PHP_RSHUTDOWN_FUNCTION({$this->name}) { ";
if (isset($this->internalFunctions['RSHUTDOWN'])) { $code .= $this->codegen->block($this->internalFunctions['RSHUTDOWN']->getCode()); } else { $code .= " /* add your stuff here */\n"; }
$code .= " return SUCCESS; } /* }}} */
"; $code .= " /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION({$this->name}) { php_info_print_box_start(0); ";
foreach ($this->logos as $logo) { $code.= $logo->phpinfoCode($this->name); }
if (!empty($this->summary)) { $summary = strtr(trim($this->summary), array('"'=>'\\"', "\n"=>"<br />")); $code .= " php_printf(\"<p>$summary</p>\\n\");\n"; } if (!empty($this->release)) { $code .= $this->release->phpinfoCode($this->name); }
if (count($this->authors)) { $code .= " php_printf(\"<p><b>Authors:</b></p>\\n\");\n"; foreach ($this->authors as $author) { $code.= $this->codegen->block($author->phpinfoCode($this->name)); } }
$code.= " php_info_print_box_end(); ";
// TODO move this decision up? if (isset($this->internalFunctions['MINFO'])) { $code .= $this->codegen->varblock($this->internalFunctions['MINFO']->getCode()); } else { $code .= " /* add your stuff here */\n"; }
if (count($this->phpini)) { $code .= "\n DISPLAY_INI_ENTRIES();"; } $code .= " } /* }}} */
";
return $code; }
// }}}
// {{{ public functions /** * Create code for the exported PHP functions * * @access private * @return string code snippet */ function publicFunctionsC() { $code = "";
foreach ($this->functions as $function) { $code .= $function->cCode($this); } return $code; }
// }}}
// {{{ code file
/** * Write the complete C code file * * @access private * @param string directory to write to */ function writeCodeFile() { $filename = "{$this->name}.{$this->language}"; // todo extension logic
$upname = strtoupper($this->name);
$this->addPackageFile('code', $filename);
$file = new CodeGen_Tools_Outbuf($this->dirpath.'/'.$filename, CodeGen_Tools_Outbuf::OB_TABIFY); echo $this->getLicense();
echo "#include \"php_{$this->name}.h\"\n\n"; echo "#if HAVE_$upname\n\n"; if (isset($this->code["code"]["top"])) { foreach ($this->code["code"]["top"] as $code) { echo $this->codegen->block($code, 0); } }
if (!empty($this->logos)) { echo CodeGen_PECL_Element_Logo::cCodeHeader($this->name); foreach ($this->logos as $logo) { echo $logo->cCode($this->name); } echo CodeGen_PECL_Element_Logo::cCodeFooter($this->name); }
if (!empty($this->resources)) { echo CodeGen_PECL_Element_Resource::cCodeHeader($this->name); foreach ($this->resources as $resource) { echo $resource->cCode($this); } echo CodeGen_PECL_Element_Resource::cCodeFooter($this->name); }
echo $this->generateInterfaceRegistrations();
echo $this->generateClassRegistrations();
echo $this->generateFunctionRegistrations(); echo $this->generateExtensionEntry(); echo $this->generateGlobalsC();
echo $this->internalFunctionsC(); echo $this->publicFunctionsC();
if (isset($this->code["code"]["bottom"])) { foreach ($this->code["code"]["bottom"] as $code) { echo $this->codegen->block($code, 0); } }
echo "#endif /* HAVE_$upname */\n\n"; echo $this->cCodeEditorSettings();
return $file->write(); }
// }}}
// {{{ config.m4 file
/** * Write config.m4 file for autoconf * * @access private * @param string directory to write to */ function writeConfigM4() { $upname = strtoupper($this->name);
$this->addPackageFile("conf", "config.m4");
$file = new CodeGen_Tools_Outbuf($this->dirpath."/config.m4", CodeGen_Tools_Outbuf::OB_TABIFY);
echo 'dnl dnl $ Id: $ dnl ';
if (isset($this->with[$this->name])) { $with = $this->with[$this->name]; echo "\n".$with->m4Line()."\n"; } else { echo " PHP_ARG_ENABLE({$this->name}, whether to enable {$this->name} functions, [ --enable-{$this->name} Enable {$this->name} support]) "; }
echo "\n";
echo "if test \"\$PHP_$upname\" != \"no\"; then\n";
foreach ($this->configfragments['top'] as $fragment) { echo "$fragment\n"; }
foreach ($this->with as $with) { echo $with->configm4($this); }
$pathes = array(); foreach($this->headers as $header) { $pathes[$header->getPath()] = true; // TODO WTF??? } foreach (array_keys($pathes) as $path) { echo " PHP_ADD_INCLUDE(\$PHP_{$upname}_DIR/$path)\n"; }
if ($this->language === "cpp") { echo " PHP_REQUIRE_CXX\n"; echo " AC_LANG_CPLUSPLUS\n"; echo " PHP_ADD_LIBRARY(stdc++,,{$upname}_SHARED_LIBADD)\n"; }
echo " export OLD_CPPFLAGS=\"\$CPPFLAGS\"\n"; echo " export CPPFLAGS=\"\$CPPFLAGS \$INCLUDES -DHAVE_".strtoupper($this->name)."\"\n";
if (count($this->headers)) { if (!isset($this->with[$this->name])) { $this->terminate("global headers not bound to a --with option found and no --with option by the default name"); }
foreach($this->headers as $header) { echo $header->configm4($this->name, $this->name); } }
foreach ($this->resources as $resource) { echo $resource->configm4($this->name); }
echo " export CPPFLAGS=\"\$OLD_CPPFLAGS\"\n";
if (count($this->libs)) { if (!isset($this->with[$this->name])) { $this->terminate("global libs not bound to a --with option found and no --with option by the default name"); } foreach ($this->libs as $lib) { echo $lib->configm4($this->name, $this->name); } }
echo "\n";
echo " PHP_SUBST({$upname}_SHARED_LIBADD) AC_DEFINE(HAVE_$upname, 1, [ ]) PHP_NEW_EXTENSION({$this->name}, ".join(" ", array_keys($this->packageFiles['code']))." , \$ext_shared) ";
if (count($this->makefragments)) { echo " PHP_ADD_MAKEFILE_FRAGMENT\n";
$frag = new CodeGen_Tools_FileReplacer($this->dirpath."/Makefile.frag"); foreach($this->makefragments as $block) { $frag->puts(CodeGen_Tools_IndentC::tabify("\n$block\n")); } $frag->close(); }
foreach ($this->configfragments['bottom'] as $fragment) { echo "$fragment\n"; }
echo " fi
";
return $file->write(); }
// }}}
// {{{ config.w32 file
/** * Write config.w32 file for new windows build system * * @access private * @param string directory to write to */ function writeConfigW32() { // TODO fragments $upname = strtoupper($this->name);
$this->addPackageFile("conf", "config.w32");
$file = new CodeGen_Tools_Outbuf($this->dirpath."/config.w32", CodeGen_Tools_Outbuf::OB_UNTABIFY | CodeGen_Tools_Outbuf::OB_DOSIFY);
echo '// $ Id: $ // vim:ft=javascript ';
if (isset($this->with[$this->name])) { echo " ARG_WITH('{$this->name}', '{$this->summary}', 'no');
"; } else { echo " ARG_ENABLE('{$this->name}' , '{$this->summary}', 'no'); "; }
echo "if (PHP_$upname == \"yes\") {\n";
// add libraries from <deps> section foreach ($this->libs as $lib) { echo $lib->configw32($this->name, $this->name); }
foreach($this->headers as $header) { echo $header->configw32($this->name, $this->name); }
echo " EXTENSION(\"{$this->name}\", \"".join(" ", array_keys($this->packageFiles['code']))."\");\n";
echo " AC_DEFINE(\"HAVE_$upname\", 1, \"{$this->name} support\");\n";
echo "}\n";
$file->write(); }
// }}}
// {{{ M$ dev studio project file
/** * Write project file for VisualStudio V6 * * @access private * @param string directory to write to */ function writeMsDevStudioDsp() { $filename = $this->name.".dsp"; $this->addPackageFile("conf", $filename); $file = new CodeGen_Tools_Outbuf($this->dirpath.'/'.$filename, CodeGen_Tools_Outbuf::OB_UNTABIFY | CodeGen_Tools_Outbuf::OB_DOSIFY);
// these system libraries are always needed? // (list taken from sample *.dsp files in php ext tree...) $winlibs = "kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib "; $winlibs.= "shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib";
// add libraries from <deps> section if (count($this->libs)) { foreach ($this->libs as $lib) { if (!$lib->testPlatform("windows")) { continue; } $winlibs .= " ".$lib->getName().".lib"; } }
echo '# Microsoft Developer Studio Project File - Name="'.$this->name.'" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG='.$this->name.' - Win32 Debug_TS !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "'.$this->name.'.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "'.$this->name.'.mak" CFG="'.$this->name.' - Win32 Debug_TS" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "'.$this->name.' - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "'.$this->name.' - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE
# Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe
!IF "$(CFG)" == "'.$this->name.' - Win32 Release_TS"
# PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release_TS" # PROP BASE Intermediate_Dir "Release_TS" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release_TS" # PROP Intermediate_Dir "Release_TS" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "'.strtoupper($this->name).'_EXPORTS" /YX /FD /c # ADD CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\main" /D "WIN32" /D "PHP_EXPORTS" /D "COMPILE_DL_'.strtoupper($this->name).'" /D ZTS=1 /D HAVE_'.strtoupper($this->name).'=1 /D ZEND_DEBUG=0 /D "NDEBUG" /D "_WINDOWS" /D "ZEND_WIN32" /D "PHP_WIN32" /YX /FD /c # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x407 /d "NDEBUG" # ADD RSC /l 0x407 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 '.$winlibs.' /nologo /dll /machine:I386 # ADD LINK32 php4ts.lib '.$winlibs.' /nologo /dll /machine:I386 /out:"..\..\Release_TS\php_'.$this->name.'.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline"
!ELSEIF "$(CFG)" == "'.$this->name.' - Win32 Debug_TS"
# PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug_TS" # PROP BASE Intermediate_Dir "Debug_TS" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug_TS" # PROP Intermediate_Dir "Debug_TS" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "'.strtoupper($this->name).'_EXPORTS" /YX /FD /GZ /c # ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\main" /D ZEND_DEBUG=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "PHP_EXPORTS" /D "COMPILE_DL_'.strtoupper($this->name).'" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_'.strtoupper($this->name).'=1 /YX /FD /GZ /c # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x407 /d "_DEBUG" # ADD RSC /l 0x407 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 '.$winlibs.' /nologo /dll /debug /machine:I386 /pdbtype:sept # ADD LINK32 php4ts_debug.lib '.$winlibs.' /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS\php_'.$this->name.'.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
!ENDIF
# Begin Target
# Name "'.$this->name.' - Win32 Release_TS" # Name "'.$this->name.' - Win32 Debug_TS" ';
echo ' # Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" ';
foreach ($this->packageFiles['code'] as $basename => $filepath) { $filename = "./$basename";
echo " # Begin Source File
SOURCE=$filename # End Source File "; }
echo ' # End Group ';
echo ' # Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl" ';
foreach ($this->packageFiles['header'] as $filename) { if ($filename{0}!='/' && $filename{0}!='.') { $filename = "./$filename"; } $filename = str_replace("/","\\",$filename);
echo " # Begin Source File
SOURCE=$filename # End Source File "; }
echo '# End Group # End Target # End Project ';
return $file->write(); }
// }}}
/** * Write authors to the CREDITS file * * @access private * @param string directory to write to */ function writeCredits() { if (count($this->authors)) { $this->addPackageFile("doc", "CREDITS"); $fp = new CodeGen_Tools_FileReplacer($this->dirpath."/CREDITS"); $fp->puts("{$this->name}\n"); $names = array(); foreach($this->authors as $author) { $names[] = $author->getName(); } $fp->puts(join(", ", $names) . "\n"); $fp->close(); } }
/** * Write EXPERIMENTAL file for non-stable extensions * * @access private * @param string directory to write to */ function writeExperimental() { if (($this->release) && $this->release->getState() === 'stable') { return; }
$this->addPackageFile("doc", "EXPERIMENTAL"); $fp = new CodeGen_Tools_FileReplacer($this->dirpath."/EXPERIMENTAL"); $fp->puts( "this extension is experimental, its functions may change their names or move to extension all together so do not rely to much on them you have been warned! "); $fp->close(); }
/** * Write file list for package.xml (both version 1.0 and 2.0) * * @return string */ protected function packageXmlFileList() { $code = "";
$code.= " <dir name=\"/\">\n"; if (@is_array($this->packageFiles['doc'])) { foreach ($this->packageFiles['doc'] as $file) { $code.= " <file role='doc' name='$file'/>\n"; } }
foreach (array("conf", "code", "header") as $type) { foreach ($this->packageFiles[$type] as $basename => $filepath) { $code.= " <file role='src' name='$basename'/>\n"; } }
if (!empty($this->packageFiles['test'])) { $code.= " <dir name=\"tests\">\n"; foreach ($this->packageFiles['test'] as $basename => $filepath) { $code.= " <file role='test' name='$basename'/>\n"; } $code.= " </dir>\n"; }
$code.= " </dir>\n";
return $code; }
/** * Write PEAR/PECL package.xml file * * @access private * @param string directory to write to */ function writePackageXml() { $outfile = new CodeGen_Tools_Outbuf($this->dirpath."/package.xml");
echo "<?xml version=\"1.0\"?> <!DOCTYPE package SYSTEM \"http://pear.php.net/dtd/package-1.0\"> <package>
<name>{$this->name}</name> ";
if (isset($this->summary)) { echo " <summary>{$this->summary}</summary>\n"; }
if (isset($this->description)) { echo " <description>\n".rtrim($this->description)."\n </description>\n"; } if ($this->license) { echo "\n <license>".$this->license->getShortName()."</license>\n"; }
if (count($this->with)) { echo "\n <configureoptions>\n"; foreach ($this->with as $with) { $configOption = "with-".$with->getName(); echo " <configureoption name=\"{$configOption}\" default=\"autodetect\" prompt=\"".$with->getName()." installation directory?\" />\n"; } echo " </configureoptions>\n"; }
if (count($this->authors)) { echo "\n <maintainers>\n"; foreach ($this->authors as $author) { echo $author->packageXml(); } echo " </maintainers>\n"; } if (isset($this->release)) { echo $this->release->packageXml(); }
echo " <changelog>\n"; echo $this->changelog."\n"; // TODO indent echo " </changelog>\n";
echo " <deps>\n"; echo " <dep type=\"php\" rel=\"ge\" version=\"".$this->minPhpVersion()."\"/>\n"; echo $this->platform->packageXML(); foreach ($this->otherExtensions as $ext) { echo $ext->packageXML(); } echo " </deps>\n";
echo "\n <filelist>\n"; echo $this->packageXmlFileList(); echo " </filelist>\n";
echo "</package>\n"; return $outfile->write(); }
// }}}
/** * Write PEAR/PECL package2.xml file * * @access private * @param string directory to write to */ function writePackageXml2() { $outfile = new CodeGen_Tools_Outbuf($this->dirpath."/package2.xml");
echo '<?xml version="1.0"?> <package version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd">
';
echo " <name>{$this->name}</name>\n"; echo " <channel>{$this->channel}</channel>\n\n";
if (isset($this->summary)) { echo " <summary>{$this->summary}</summary>\n\n"; }
if (isset($this->description)) { echo " <description>\n".rtrim($this->description)."\n </description>\n\n"; }
uasort($this->authors, array("CodeGen_PECL_Maintainer", "comp")); foreach ($this->authors as $maintainer) { echo $maintainer->packageXml2(); } echo "\n";
echo $this->release->packageXml2($this->license);
echo " <contents>\n"; echo $this->packageXmlFileList(); echo " </contents>\n\n";
echo " <dependencies>\n"; echo " <required>\n"; echo " <php>\n"; echo " <min>".$this->minPhpVersion()."</min>\n"; echo " </php>\n"; echo " <pearinstaller>\n"; echo " <min>1.4.0a1</min>\n"; echo " </pearinstaller>\n"; foreach ($this->otherExtensions as $ext) { echo $ext->packageXML2(array("REQUIRED", "CONFLICTS")); } echo $this->platform->packageXML2(); echo " </required>\n";
$optional = ""; foreach ($this->otherExtensions as $ext) { $optional.= $ext->packageXML2(array("OPTIONAL")); } if (!empty($optional)) { echo " <optional>\n"; echo $optional; echo " </optional>\n"; }
echo " </dependencies>\n\n";
echo " <providesextension>{$this->name}</providesextension>\n\n";
if (count($this->with)) { echo " <extsrcrelease>\n"; foreach ($this->with as $with) { $configOption = "with-".$with->getName(); echo " <configureoption name=\"{$configOption}\" default=\"autodetect\" prompt=\"".$with->getName()." installation directory?\" />\n"; } echo " </extsrcrelease>\n\n"; } else { echo " <extsrcrelease/>\n\n"; }
echo "</package>\n"; return $outfile->write(); }
// }}}
/** * add a custom test case * * @access public * @param object a Test object */ function addTest(CodeGen_PECL_Element_Test $test) { $name = $test->getName(); if (isset($this->testcases[$name])) { return PEAR::raiseError("testcase '{$name}' added twice"); }
$this->testcases[$name] = $test; return true; }
/** * Write test case files * * @access private */ function writeTestFiles() { $testCount=0; @mkdir($this->dirpath."/tests"); // function related tests foreach ($this->functions as $function) { $function->writeTest($this); }
// class method related tests foreach ($this->classes as $class) { $class->writeTests($this); }
// custom test cases (may overwrite custom function test cases) foreach ($this->testcases as $test) { $test->writeTest($this); }
if (0 == count(glob($this->dirpath."/tests/*.phpt"))) { rmdir($this->dirpath."/tests"); } }
/** * Generate README file (custom or default) * * @access private * @param string directory to write to */ function writeReadme() { $file = new CodeGen_Tools_Outbuf($this->dirpath."/README");
$configOption = isset($this->with[$this->name]) ? "--with-" : "--enable-"; $configOption.= $this->name;
?> This is a standalone PHP extension created using CodeGen_PECL <?php echo self::version(); ?>
HACKING =======
There are two ways to modify an extension created using CodeGen_PECL:
1) you can modify the generated code as with any other PHP extension 2) you can add custom code to the CodeGen_PECL XML source and re-run pecl-gen
The 2nd approach may look a bit complicated but you have be aware that any manual changes to the generated code will be lost if you ever change the XML specs and re-run PECL-Gen. All changes done before have to be applied to the newly generated code again. Adding code snippets to the XML source itself on the other hand may be a bit more complicated but this way your custom code will always be in the generated code no matter how often you rerun CodeGen_PECL.
<?php if ($this->platform->test("unix")): ?>
BUILDING ON UNIX etc. =====================
To compile your new extension, you will have to execute the following steps:
1. $ ./phpize 2. $ ./configure [<?php echo $configOption; ?>] 3. $ make [4. $ make test ] # NOTE: this doesn't work right now *) 5. $ [sudo] make install
*) this is a general problem with "make test" and standalone extensions (that is being worked on) so please don't blame CodeGen_PECL for this <?php endif; ?>
<?php if ($this->platform->test("windows")): ?>
BUILDING ON WINDOWS ===================
The extension provides the VisualStudio V6 project file
<?php echo $this->name.".dsp" ?>
To compile the extension you open this file using VisualStudio, select the apropriate configuration for your installation (either "Release_TS" or "Debug_TS") and create "php_<?php echo $this->name; ?>.dll"
After successfull compilation you have to copy the newly created "php_<?php echo $this->name; ?>.dll" to the PHP extension directory (default: C:\PHP\extensions).
<?php endif; ?>
TESTING =======
You can now load the extension using a php.ini directive
extension="php_<?php echo $this->name; ?>.[so|dll]"
or load it at runtime using the dl() function
dl("php_<?php echo $this->name; ?>.[so|dll]");
The extension should now be available, you can test this using the extension_loaded() function:
if (extension_loaded(<?php echo $this->name; ?>)) echo "<?php echo $this->name; ?> loaded :)"; else echo "something is wrong :(";
The extension will also add its own block to the output of phpinfo();
<?php
$file->write(); }
/** * Return minimal PHP version required to support the requested features * * @return string version string */ function minPhpVersion() { if (!empty($this->otherExtensions)) { return "5.1.0rc1"; }
if (!empty($this->classes) || !empty($this->interfaces)) { return "5.0.0"; }
return "4.0.0"; // TODO test for real lower bound }
/** * Generate Editor settings block for documentation files * * @access public * @param int Directory nesting depth of target file (default: 3) * @return string Editor settings comment block */ static function docEditorSettings($level=3) { return ' <!-- Keep this comment at the end of the file Local'.' variables: mode: sgml sgml-omittag:t sgml-shorttag:t sgml-minimize-attributes:nil sgml-always-quote-attributes:t sgml-indent-step:1 sgml-indent-data:t indent-tabs-mode:nil sgml-parent-document:nil sgml-default-dtd-file:"'.str_repeat("../",$level).'manual.ced" sgml-exposed-tags:nil sgml-local-catalogs:nil sgml-local-ecat-files:nil End: vim600: syn=xml fen fdm=syntax fdl=2 si vim: et tw=78 syn=sgml vi: ts=1 sw=1 --> '; }
/** * Show error message and bailout * * @param string error message */ function terminate($msg) { while (@ob_end_clean()); // purge output buffers
$stderr = fopen("php://stderr", "w"); if ($stderr) { fprintf($stderr, "%s\n", $msg); fclose($stderr); } else { echo "$msg\n"; } exit(3); } }
/* * Local variables: * tab-width: 4 * c-basic-offset: 4 * indent-tabs-mode:nil * End: */ ?>
|