|
View:
New views
3 Messages
—
Rating Filter:
Alert me
|
|
|
A new way for creating extensionsI recently had the need to create a php-gtk extension, and what i found
wasn't too pleasant. Most code (gen_*.c) is autogenerated from the defs file by generator/generator.php. Which itself is made by running h2def.py on the C header. Well, it turns out generator/h2def.py is outdated. And by outdated i mean that generator/generator.php *won't be able to process that file*. Oops. The solution is using the newer one maintained by the pygtk folks at http://svn.gnome.org/svn/pygobject/trunk/codegen It also has improvements such as no longer needing to edit the defs file in order to specify which is the constructor. Where to get the other files an extension needs? Well, there's a skeleton extension precisely for a basis for that, right? Wrong! It is also outdated. php_skeleton_register_constants() doesn't expect a module_number, but a const char* Using it you get a nice sigsegv on runtime. Finally, there's ext_skel, a shell script to copy the skeleton dir to the widget's and avoid you the trouble or replacing each skeleton occurrence by the new widget's name. It's also broken, although this may be just in my setup. So, you end up copying one of the working widgets and changing the name in lots of places, with different capitalizations. You invariably forget some, and have to try compiling several times until you get it right. As Bob said when i asked how to create php-gtk extensions, "it is just not very fun to do". That labour would better be achieved by a script, and so i went into making it. This new script resides in generator/ext_gen.php and hooks into the build process, based on ext_data.php on each extension folder. You can use it once to generate the files which you will then customize, or leave them autogenerate on each build. This point is specially interesting because most extensions haven't changed since they were created by copy & replace, and provides a single point of improvement into the system. Also, by keeping the generator in use by a number of extensions, it is guaranteed to be kept up-to-date. Each extension defines a few parameters into the file ext_data.php, and can have most its files autogenerated. The new generated scripts are (expected to be) equivalent to the old ones. In fact, much of it is the same code, to make a cvs diff as smaller as possible. However, there's a number of improvements: -grep | sed process replaced by just a sed -gen_*.h created a bit more independed from gen_*.c -Makefiles actions in one line broken on several. -gen_*.h will include the prototypes of the exported functions of gen_*.c, which would have warned the issue of the register_constants() parameter type at compile time. -php_*.h will include gen_*.h instead of placing the prototypes. -Minor differences on text presented to the user, usually just of capitalization (eg. 'Disable libglade support' vs 'Disable libGlade support'). Transitioned extensions: extra, html, libglade, libsexy Unchanged: gtk+ (lots of special stuff), mozembed (three different modules), scintilla (several customizations), spell (standalone) I have done my best to ensure it doesn't break anything, but any comments are welcome. You can also reach me at #php-gtk. The extensions still build fine on Linux with the patch. On windows, it still fails, as it did without it, so SNAFU. Added files: extra/ext_data.php html/ext_data.php libglade/ext_data.php libsexy/ext_data.php generator/ext_gen.php Modified: win32/buildconf.js build2/build.mk Removed: generator/h2def.py ext/ext_skel ext/skeleton/* [keep skeleton.overrides?] Deprecated: extra/config.m4,config.w32,Makefile.frag,php_gtkextra.c,php_gtkextra.h html/config.m4,config.w32,Makefile.frag,php_html.c,php_html.h libglade/config.m4,config.w32,Makefile.frag,php_libglade.c,php_libglade.h libsexy/config.m4,config.w32,Makefile.frag,php_libsexy.c,php_libsexy.h Renamed (apply manually): mv extra/gtkextra.defs extra/extra.defs mv extra/gtkextra.overrides extra/extra.overrides mv libsexy/sexy.overrides libsexy/libsexy.overrides mv libsexy/sexy.defs libsexy/libsexy.defs Opinions? Index: build2/build.mk =================================================================== RCS file: /repository/php-gtk/build2/build.mk,v retrieving revision 1.11 diff -u -r1.11 build.mk --- build2/build.mk 12 Sep 2005 17:01:08 -0000 1.11 +++ build2/build.mk 10 Aug 2008 17:52:54 -0000 @@ -12,6 +12,7 @@ @$(MAKE) -s -f build2/build2.mk build2/generated_lists: + @for i in `find . -name ext_data.php`; do php generator/ext_gen.php $$i; done @echo config_m4_files = ext/*/config*.m4 > $@ $(STAMP): Index: ext/ext_skel =================================================================== RCS file: ext/ext_skel diff -N ext/ext_skel --- ext/ext_skel 11 Apr 2002 02:19:45 -0000 1.4 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,82 +0,0 @@ -#!/bin/sh - -# $Id: ext_skel,v 1.4 2002/04/11 02:19:45 andrei Exp $ - -file_list=".cvsignore Makefile.in Makefile.frag config.m4 php_skeleton.c php_skeleton.h skeleton.overrides" - -giveup() { - echo $* - echo "" - exit 1 -} - -usage() { - echo "$0 --widget=name" - echo "" - echo " --widget=name the name of the widget." - echo " It's actually important to name the" - echo " widget properly, e.g. SQPaned and" - echo " not Sqpaned." - echo "" - exit 1 -} - -if test $# = 0; then - usage -fi - -while test $# -gt 0; do - case "$1" in - -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;; - *) optarg= ;; - esac - - case $1 in - --widget=?*) - Widget=$optarg - WIDGET=`echo $Widget | tr [a-z] [A-Z]` - widget=`echo $Widget | tr [A-Z] [a-z]` - ;; - *) - usage - ;; - esac - shift -done - -if test -d "$widget"; then - giveup "Directory $widget already exists." -fi - -test -f ext_skel || giveup "ext_skel must be in the current directory" -test -d skeleton || giveup "subdirectory skeleton does not exist or is not directory" - -echo "Creating directory $widget" -mkdir $widget || giveup "Cannot create directory $widget" - -echo "Creating skeleton files" -cd skeleton -cp -a $file_list ../$widget/ -cd ../$widget/ - -perl -p -i -e "s/skeleton/$widget/g" $file_list -perl -p -i -e "s/Skeleton/$Widget/g" $file_list -perl -p -i -e "s/SKELETON/$WIDGET/g" $file_list -perl -p -i -e "s/^dnl //" config.m4 - -mv php_skeleton.c php_$widget.c -mv php_skeleton.h php_$widget.h -mv skeleton.overrides $widget.overrides - -echo "Skeleton built." -echo "" -echo "Now you can create your $widget/$widget.defs file with:" -echo "" -echo -e "\t../generator/h2def.py <path>/$widget.h >$widget/$widget.defs" -echo "" -echo "and don't forget to add the constructor line to $widget.defs:" -echo "" -echo -e "\t(is-constructor-of Gtk$Widget)" -echo "" -echo "in the definition of gtk_${widget}_new" -echo "" Index: ext/extra/ext_data.php =================================================================== RCS file: ext/extra/ext_data.php diff -N ext/extra/ext_data.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ext/extra/ext_data.php 10 Aug 2008 17:52:54 -0000 @@ -0,0 +1,16 @@ +<?php + +$Widget_Name = "GtkExtra"; +$required_version = "2.1.1"; +$module_name = "gtkextra-2.0"; +$lib_name = "gtkextra-2.0.lib"; +$include_header = "gtkextra/gtkextra.h"; + +load_names(); +create_m4_config(); +create_makefile_frag(); +create_w32_config(); +create_php_ext_h(); +create_php_ext_c(); +create_cvsignore(); + Index: ext/html/ext_data.php =================================================================== RCS file: ext/html/ext_data.php diff -N ext/html/ext_data.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ext/html/ext_data.php 10 Aug 2008 17:52:54 -0000 @@ -0,0 +1,19 @@ +<?php + +$Widget_Name = "GtkHtml"; +$required_version = "3.10.0"; +$module_name = "libgtkhtml-3.8"; +$lib_name = "gtkhtml-3.0.lib"; +$include_header = "gtkhtml/gtkhtml.h"; + +load_names(); +create_m4_config(); +create_makefile_frag(); +create_w32_config(); +create_php_ext_h(); +create_php_ext_c(); +create_cvsignore(); + +/* Rename to +gtkhtml.overrides +gtkhtml.defs*/ Index: ext/libglade/ext_data.php =================================================================== RCS file: ext/libglade/ext_data.php diff -N ext/libglade/ext_data.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ext/libglade/ext_data.php 10 Aug 2008 17:52:54 -0000 @@ -0,0 +1,16 @@ +<?php + +$Widget_Name = "libGlade"; +$required_version = "2.4.0"; +$module_name = "libglade-2.0"; +$lib_name = "glade-2.0.lib"; +$enable_default = true; + +load_names(); +create_m4_config(); +create_makefile_frag(); +create_w32_config(); +create_php_ext_h(); +create_php_ext_c(); +create_cvsignore(); + Index: ext/libsexy/ext_data.php =================================================================== RCS file: ext/libsexy/ext_data.php diff -N ext/libsexy/ext_data.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ ext/libsexy/ext_data.php 10 Aug 2008 17:52:54 -0000 @@ -0,0 +1,16 @@ +<?php + +$Widget_Name = "libSexy"; +$required_version = "0.1.10"; +$module_name = "libsexy"; +$lib_name = "libsexy.lib"; +$include_header = "libsexy/sexy.h"; + +load_names(); +create_m4_config(); +create_makefile_frag(); +create_w32_config(); +create_php_ext_h(); +create_php_ext_c(); +create_cvsignore(); + Index: ext/skeleton/Makefile.frag =================================================================== RCS file: ext/skeleton/Makefile.frag diff -N ext/skeleton/Makefile.frag --- ext/skeleton/Makefile.frag 12 Oct 2005 20:05:37 -0000 1.3 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,11 +0,0 @@ - -$(builddir)/php_skeleton.lo: $(builddir)/gen_ce_skeleton.h - -$(builddir)/gen_skeleton.lo: $(builddir)/gen_skeleton.c - -$(builddir)/gen_skeleton.c: $(srcdir)/skeleton.defs $(srcdir)/skeleton.overrides - $(PHP) -f $(top_srcdir)/generator/generator.php -- -o $(srcdir)/skeleton.overrides -p Skeleton -r $(top_srcdir)/ext/gtk%2b/gtk.defs $(srcdir)/skeleton.defs > $@ - -$(builddir)/gen_ce_skeleton.h: $(builddir)/gen_skeleton.c - grep -h "^PHP_GTK_EXPORT_CE" $(srcdir)/gen_skeleton.c | sed -e "s!^!extern !" > $@ - Index: ext/skeleton/config.m4 =================================================================== RCS file: ext/skeleton/config.m4 diff -N ext/skeleton/config.m4 --- ext/skeleton/config.m4 28 Jun 2003 02:09:06 -0000 1.9 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,30 +0,0 @@ -dnl $Id: config.m4,v 1.9 2003/06/28 02:09:06 alan_k Exp $ -dnl config.m4 for skeleton module - -dnl PHP_GTK_ARG_ENABLE(skeleton,for GtkSkeleton support, -dnl [ --enable-skeleton Enable GtkSkeleton support]) - -dnl if test "$PHP_GTK_SKELETON" != "no"; then -dnl for x in /usr /usr/local; do -dnl if test -f $x/include/gtkskeleton.h; then -dnl SKELETON_DIR=$x -dnl SKELETON_INCDIR=$x/include -dnl fi -dnl done -dnl -dnl if test -z "$SKELETON_DIR"; then -dnl AC_MSG_ERROR(Cannot locate Skeleton) -dnl fi -dnl -dnl SKELETON_LIBDIR=$SKELETON_DIR/lib -dnl -dnl AC_DEFINE(HAVE_SKELETON,1,[skeleton support]) -dnl PHP_ADD_INCLUDE($SKELETON_INCDIR) -dnl if test "$php_gtk_ext_shared" = "yes"; then -dnl PHP_ADD_LIBRARY_WITH_PATH(gtkskeleton, $SKELETON_LIBDIR, SKELETON_SHARED_LIBADD) -dnl PHP_SUBST(SKELETON_SHARED_LIBADD) -dnl else -dnl PHP_ADD_LIBRARY_WITH_PATH(gtkskeleton, $SKELETON_LIBDIR, PHP_GTK_SHARED_LIBADD) -dnl fi -dnl PHP_GTK_EXTENSION(skeleton, $php_gtk_ext_shared) -dnl fi Index: ext/skeleton/php_skeleton.c =================================================================== RCS file: ext/skeleton/php_skeleton.c diff -N ext/skeleton/php_skeleton.c --- ext/skeleton/php_skeleton.c 29 Feb 2008 19:05:53 -0000 1.5 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,45 +0,0 @@ -/* - * PHP-GTK - The PHP language bindings for GTK+ - * - * Copyright (C) 2001-2008 Andrei Zmievski <andrei@...> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: php_skeleton.c,v 1.5 2008/02/29 19:05:53 andrei Exp $ */ - -#include "php_skeleton.h" - -#if HAVE_SKELETON - -#ifdef PHP_GTK_COMPILE_DL_SKELETON -PHP_GTK_GET_EXTENSION(skeleton) -#endif - -PHP_GTK_XINIT_FUNCTION(skeleton) -{ - php_skeleton_register_constants(module_number TSRMLS_CC); - php_skeleton_register_classes(); - - return SUCCESS; -} - -php_gtk_ext_entry skeleton_ext_entry = { - "skeleton", - PHP_GTK_XINIT(skeleton), - NULL, -}; - -#endif /* HAVE_SKELETON */ Index: ext/skeleton/php_skeleton.h =================================================================== RCS file: ext/skeleton/php_skeleton.h diff -N ext/skeleton/php_skeleton.h --- ext/skeleton/php_skeleton.h 29 Feb 2008 19:05:53 -0000 1.5 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,46 +0,0 @@ -/* - * PHP-GTK - The PHP language bindings for GTK+ - * - * Copyright (C) 2001-2008 Andrei Zmievski <andrei@...> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* $Id: php_skeleton.h,v 1.5 2008/02/29 19:05:53 andrei Exp $ */ - -#ifndef PHP_SKELETON_H -#define PHP_SKELETON_H - -#include "php_gtk.h" - -#if HAVE_SKELETON - -#include "gen_ce_skeleton.h" - -extern php_gtk_ext_entry skeleton_ext_entry; -#define skeleton_ext_ptr &skeleton_ext_entry - -void php_skeleton_register_constants(int module_number TSRMLS_DC); -void php_skeleton_register_classes(); - -#else - -#define skeleton_ext_ptr NULL - -#endif /* HAVE_SKELETON */ - -#define php_gtk_ext_skeleton_ptr skeleton_ext_ptr - -#endif /* PHP_SKELETON_H */ Index: ext/skeleton/skeleton.overrides =================================================================== RCS file: ext/skeleton/skeleton.overrides diff -N ext/skeleton/skeleton.overrides --- ext/skeleton/skeleton.overrides 14 Oct 2001 16:21:54 -0000 1.1 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,10 +0,0 @@ -/* vim: set ft=cpp: */ -%% -headers -#include <gtkskeleton.h> -#include "ext/gtk+/php_gtk+.h" -%% -constants -%% -ignore-glob - *_get_type Index: generator/ext_gen.php =================================================================== RCS file: generator/ext_gen.php diff -N generator/ext_gen.php --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ generator/ext_gen.php 10 Aug 2008 17:52:55 -0000 @@ -0,0 +1,246 @@ +<?php + + +/* Usage: Pass a ext_data.php as parameter + * This script can generate config.m4,config.w32,Makefile.frag, + * the extension .c and .h files and .cvsignore + * To regenerate the .defs file, checkout from svn + * http://svn.gnome.org/svn/pygobject/trunk/codegen + * and run h2def.py <C header> + * When crating a new extension, remember to add the enum names + * at generator/generator.php is_php_type() + */ + +/** Example of ext_data.php +$Widget_Name = "GtkSpell"; +$required_version = "2.0.0"; +$module_name = "gtkspell-2.0"; #Linux +$lib_name = "gtkspell-2.0.lib"; #Windows +$enable_default = false; +* +load_names(); +create_m4_config(); +create_makefile_frag(); +create_w32_config(); +create_php_ext_h(); +create_php_ext_c(); +create_cvsignore(); +*/ + +error_reporting (E_ALL | E_STRICT ); +function load_names() { + #Prepare different variations of the name we will use + global $Widget_Name, $Full_Widget_Name, $WIDGET_NAME, $widget_name, $FULL_WIDGET_NAME, $full_widget_name, $widget_name_nolib, $WIDGET_NAME_NOLIB, $full_widget_name_nolib, $FULL_WIDGET_NAME_NOLIB, $include_header; + + $Full_Widget_Name=$Widget_Name; + if (substr($Widget_Name, 0, 3) == "Gtk") $Widget_Name = substr($Widget_Name, 3); + + + $WIDGET_NAME=strtoupper($Widget_Name); + $widget_name=strtolower($Widget_Name); + $widget_name_nolib = (substr($widget_name, 0, 3) == "lib") ? substr($widget_name, 3) : $widget_name; + $FULL_WIDGET_NAME = strtoupper($Full_Widget_Name); + $full_widget_name = strtolower($Full_Widget_Name); + $full_widget_name_nolib = (substr($full_widget_name, 0, 3) == "lib") ? substr($full_widget_name, 3) : $full_widget_name; + $FULL_WIDGET_NAME_NOLIB = (substr($FULL_WIDGET_NAME, 0, 3) == "LIB") ? substr($FULL_WIDGET_NAME, 3) : $FULL_WIDGET_NAME; + + if (!isset($include_header)) { + $include_header = "{$widget_name_nolib}/{$widget_name_nolib}.h"; + } +} + +function create_m4_config() { +global $required_version, $module_name, $lib_name, $Widget_Name, $Full_Widget_Name, $WIDGET_NAME, $widget_name, $FULL_WIDGET_NAME, $full_widget_name, $widget_name_nolib; +global $enable_default, $extra_files; +$files = "php_{$widget_name}.c " . implode(" ", $extra_files) . ", gen_{$widget_name}.c gen_{$widget_name}.h"; + +$M4 = <<< EOF_CONFIG +dnl Autogenerated by ext_gen.php + +define({$widget_name}_required_version, $required_version) +PHP_GTK_ARG_WITH({$widget_name},for {$widget_name} support, + + +EOF_CONFIG; +if ($enable_default) + $M4 .= "[ --without-{$widget_name} Disable {$Full_Widget_Name} support],yes)"; +else + $M4 .= "[ --with-{$widget_name} Enable {$Full_Widget_Name} support],no)"; + +$M4 .= <<< EOF_CONFIG + +if test "\$PHP_GTK_{$WIDGET_NAME}" != "no"; then + PKG_CHECK_MODULES($WIDGET_NAME, [{$module_name} >= {$widget_name}_required_version], + have_{$widget_name}=yes, have_{$widget_name}=no) + if test "\$have_{$widget_name}" != "yes"; then + AC_MSG_RESULT([Unable to locate $Widget_Name version {$widget_name}_required_version or higher: not building]) + else + AC_DEFINE(HAVE_{$FULL_WIDGET_NAME}, 1, [$Widget_Name support]) + PHP_EVAL_INCLINE(\${$WIDGET_NAME}_CFLAGS) + if test "\$php_gtk_ext_shared" = "yes"; then + PHP_EVAL_LIBLINE(\${$WIDGET_NAME}_LIBS, {$WIDGET_NAME}_SHARED_LIBADD) + PHP_SUBST({$WIDGET_NAME}_SHARED_LIBADD) + else + PHP_EVAL_LIBLINE(\${$WIDGET_NAME}_LIBS, PHP_GTK2_SHARED_LIBADD) + fi + PHP_GTK_EXTENSION({$widget_name}, \$php_gtk_ext_shared, $files) + fi +fi +EOF_CONFIG; + +file_put_contents ("config.m4", $M4); +} + +function create_w32_config() { +global $required_version, $module_name, $lib_name, $Widget_Name, $Full_Widget_Name, $WIDGET_NAME, $widget_name, $FULL_WIDGET_NAME, $full_widget_name, $include_header, $extra_files; +$files = "php_{$widget_name}.c gen_{$widget_name}.c " . implode(" ", $extra_files); +$W32 = <<< EOF_CONFIG +// Autogenerated by ext_gen.php + +ARG_WITH("{$widget_name}", "{$Full_Widget_Name} support", "no"); + +if (PHP_GTK_{$WIDGET_NAME} != "no" || PHP_GTK_ALL != "no") { + if (CHECK_HEADER("$include_header") && CHECK_LIB("{$lib_name}", "{$widget_name}")) + { + if (FSO.FileExists("win32\\\\temp.bat")) { + + var temp = FSO.OpenTextFile("win32\\\\temp.bat", 8); + temp.WriteLine("php -q generator\\\\generator.php -l win32\\\\logs\\\\config_{$widget_name}.log -o ext\\\\{$widget_name}\\\\{$widget_name}.overrides -p {$full_widget_name} -r ext\\\\gtk+\\\\gtk.defs ext\\\\{$widget_name}\\\\{$widget_name}.defs > ext\\\\{$widget_name}\\\\gen_{$widget_name}.c"); + temp.WriteLine('sed -n "s/^PHP_GTK_EXPORT_CE/PHP_GTK_API extern \\\\0/p" ext\\\\{$widget_name}\\\\gen_{$widget_name}.c > ext\\\\{$widget_name}\\\\gen_{$widget_name}.h'); + temp.WriteLine('sed -n "s/^void.*/\\\\0;/p" ext\\\\{$widget_name}\\\\gen_{$widget_name}.c >> ext\\\\{$widget_name}\\\\gen_{$widget_name}.h'); + temp.Close(); + } + + /* The first parameter of ADD_FLAG must always match the first one of EXTENSION(), uppercased and with CFLAGS_ prepended. Otherwise, it's not passed to the compiler. */ + ADD_FLAG("CFLAGS_{$WIDGET_NAME}", "/I ext\\\\{$widget_name} /I ..\\\\ext\\\\{$widget_name} /D HAVE_{$FULL_WIDGET_NAME}=1"); + EXTENSION("{$widget_name}", "$files", true); // always shared + AC_DEFINE("HAVE_{$FULL_WIDGET_NAME}", 1, "{$Full_Widget_Name} enabled"); + + } else { + WARNING("{$Full_Widget_Name} not enabled; libraries and headers not found"); + } +} +EOF_CONFIG; + +file_put_contents ("config.w32", $W32); +} + +function create_php_ext_c() { +global $required_version, $module_name, $lib_name, $Widget_Name, $Full_Widget_Name, $WIDGET_NAME, $widget_name, $FULL_WIDGET_NAME, $full_widget_name, $FULL_WIDGET_NAME_NOLIB, $full_widget_name_nolib; + +$PHP_FILE = <<< EOF_FILE +// Autogenerated by ext_gen.php +#include "php_{$widget_name}.h" + +#if HAVE_{$FULL_WIDGET_NAME} + +#ifdef PHP_GTK_COMPILE_DL_$WIDGET_NAME +PHP_GTK_GET_EXTENSION($widget_name) +#endif + +PHP_GTK_XINIT_FUNCTION($widget_name) +{ + phpg_{$full_widget_name_nolib}_register_classes(); + phpg_{$full_widget_name_nolib}_register_constants("{$FULL_WIDGET_NAME_NOLIB}_"); + + return SUCCESS; +} + +php_gtk_ext_entry {$widget_name}_ext_entry = { + "$widget_name", + PHP_GTK_XINIT($widget_name), + NULL, +}; + +#endif /* HAVE_{$FULL_WIDGET_NAME} */ + +EOF_FILE; + +file_put_contents ("php_$widget_name.c", $PHP_FILE); +} + +function create_php_ext_h() { +global $required_version, $module_name, $lib_name, $Widget_Name, $Full_Widget_Name, $WIDGET_NAME, $widget_name, $FULL_WIDGET_NAME, $full_widget_name, $full_widget_name_nolib, $include_header; + +$PHP_FILE = <<< EOF_FILE +// Autogenerated by ext_gen.php +#ifndef PHP_{$FULL_WIDGET_NAME}_H +#define PHP_{$FULL_WIDGET_NAME}_H + +#include "php_gtk.h" + +#if HAVE_{$FULL_WIDGET_NAME} +#include "gen_{$widget_name}.h" + +#include <$include_header> + +extern php_gtk_ext_entry {$widget_name}_ext_entry; +#define php_gtk_ext_{$widget_name}_ptr &{$widget_name}_ext_entry + +/** defined at gen_{$widget_name}.h +void phpg_{$full_widget_name_nolib}_register_classes(void); +void phpg_{$full_widget_name_nolib}_register_constants(const char *strip_prefix); +**/ + +#else + +#define php_gtk_ext_{$widget_name}_ptr NULL + +#endif /* HAVE_{$FULL_WIDGET_NAME} */ + +#endif /* PHP_{$FULL_WIDGET_NAME}_H */ + +EOF_FILE; + +file_put_contents ("php_$widget_name.h", $PHP_FILE); +} + +function create_cvsignore() { + +$cvsignore = <<< EOF_CVSIGNORE +*.cache +*.lo +*.la +gen_* +.libs +libs.mk +EOF_CVSIGNORE; + +file_put_contents (".cvsignore", $cvsignore); +} + + +function create_makefile_frag() { +global $required_version, $module_name, $lib_name, $Widget_Name, $Full_Widget_Name, $WIDGET_NAME, $widget_name, $FULL_WIDGET_NAME, $full_widget_name; + +if (file_exists("{$widget_name}-types.defs")) + $extra_types = "\$(srcdir)/{$widget_name}-types.defs"; +else + $extra_types = ""; + +$makefile = <<< EOF_MAKEFILE +\$(builddir)/gen_{$widget_name}.c: \$(srcdir)/{$widget_name}.defs \$(srcdir)/{$widget_name}.overrides $extra_types + \$(PHP) \$(top_srcdir)/generator/generator.php \ + -l \$(@D)/\$(*F).log \ + -r ext/gtk+/atk-types.defs \ + -r ext/gtk+/pango-types.defs \ + -r ext/gtk+/gdk-types.defs \ + -r ext/gtk+/gtk-types.defs \ + -r $extra_types \ + -o \$(srcdir)/{$widget_name}.overrides \ + -p $Full_Widget_Name \ + -f \$@ \$(srcdir)/{$widget_name}.defs + +\$(builddir)/gen_{$widget_name}.h: \$(builddir)/gen_{$widget_name}.c + sed -n 's/^PHP_GTK_EXPORT_CE/PHP_GTK_API extern \\0/p' \$@ > \$(@D)/\$(*F).h + sed -n 's/^void.*/\\0;/p' \$@ >> \$(@D)/\$(*F).h + +EOF_MAKEFILE; + +file_put_contents ("Makefile.frag", $makefile); +} + +$enable_default = false; +$extra_files = array(); +chdir(dirname($argv[1])); +require (basename($argv[1])); Index: generator/h2def.py =================================================================== RCS file: generator/h2def.py diff -N generator/h2def.py --- generator/h2def.py 9 Jun 2006 15:50:45 -0000 1.2 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,345 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python; py-indent-offset: 4 -*- -# Search through a header file looking for function prototypes. -# For each prototype, generate a scheme style definition. -# GPL'ed -# Toby D. Reeves <toby@...> - -# Modified by James Henstridge <james@...> to output stuff in -# Havoc's new defs format. Info on this format can be seen at: -# http://www.gnome.org/mailing-lists/archives/gtk-devel-list/2000-January/0085.shtml - - -import string, sys, re, types - -# ------------------ Find object definitions ----------------- - -obj_name_pat = "[A-Z][a-z]+[A-Z][A-Za-z0-9]*" - -def find_obj_defs(buf, objdefs=[]): - """ - Try to find object definitions in header files. - """ - - # filter out comments from buffer. - pat = re.compile(r"""/[*](.|\n)*?[*]/""", re.MULTILINE) - buf=pat.sub('',buf) - - # first find all structures that look like they may represent a GtkObject - pat = re.compile("struct _(" + obj_name_pat + ")\s*{\s*" + - "(" + obj_name_pat + ")\s+", re.MULTILINE) - maybeobjdefs = [] # contains all possible objects from file - pos = 0 - while pos < len(buf): - m = pat.search(buf, pos) - if not m: break - maybeobjdefs.append((m.group(1), m.group(2))) - pos = m.end() - - # now find all structures that look like they might represent a class: - pat = re.compile("struct _(" + obj_name_pat + ")Class\s*{\s*" + - "(" + obj_name_pat + ")Class\s+", re.MULTILINE) - pos = 0 - while pos < len(buf): - m = pat.search(buf, pos) - if not m: break - t = (m.group(1), m.group(2)) - # if we find an object structure together with a corresponding - # class structure, then we have probably found a GtkObject subclass. - if t in maybeobjdefs: - objdefs.append(t) - pos = m.end() - -def sort_obj_defs(objdefs): - objdefs.sort() # not strictly needed, but looks nice - pos = 0 - while pos < len(objdefs): - klass,parent = objdefs[pos] - for i in range(pos+1, len(objdefs)): - # parent below subclass ... reorder - if objdefs[i][0] == parent: - objdefs.insert(i+1, objdefs[pos]) - del objdefs[pos] - break - else: - pos = pos + 1 - return objdefs - -def write_obj_defs(objdefs, output): - if type(output)==types.StringType: - fp=open(output,'w') - elif type(output)==types.FileType: - fp=output - else: - fp=sys.stdout - - fp.write(';; -*- scheme -*-\n') - fp.write('; object definitions ...\n') - - pat = re.compile('([A-Z][a-z]+)([A-Za-z0-9]+)') - for klass, parent in objdefs: - m = pat.match(klass) - cmodule = None - cname = klass - if m: - cmodule = m.group(1) - cname = m.group(2) - if parent: - m = pat.match(parent) - pmodule = None - pname = parent - if m: - pmodule = m.group(1) - pname = m.group(2) - - fp.write('(object ' + cname + '\n') - if cmodule: - fp.write(' (in-module ' + cmodule + ')\n') - if parent: - fp.write(' (parent ' + pname) - if pmodule: fp.write(' (' + pmodule + ')') - fp.write(')\n') - fp.write(' (c-name ' + klass + ')\n') - # should do something about accessible fields - fp.write(')\n\n') - -# ------------------ Find enum definitions ----------------- - -def find_enum_defs(buf, enums=[]): - # strip comments - # bulk comments - pat = re.compile(r"""/[*](.|\n)*?[*]/""", re.MULTILINE) - buf=pat.sub('',buf) - - buf = re.sub('\n', ' ', buf) - - enum_pat = re.compile(r'enum\s*{([^}]*)}\s*([A-Z][A-Za-z]*)(\s|;)') - splitter = re.compile(r'\s*,\s', re.MULTILINE) - pos = 0 - while pos < len(buf): - m = enum_pat.search(buf, pos) - if not m: break - - name = m.group(2) - vals = m.group(1) - isflags = string.find(vals, '<<') >= 0 - entries = [] - for val in splitter.split(vals): - entries.append(string.split(val)[0]) - enums.append((name, isflags, entries)) - - pos = m.end() - -def write_enum_defs(enums, output=None): - if type(output)==types.StringType: - fp=open(output,'w') - elif type(output)==types.FileType: - fp=output - else: - fp=sys.stdout - - fp.write(';; Enumerations and flags ...\n\n') - pat = re.compile('([A-Z][a-z]+)([A-Za-z0-9]+)') - trans = string.maketrans(string.uppercase + '_', string.lowercase + '-') - for cname, isflags, entries in enums: - name = cname - module = None - m = pat.match(cname) - if m: - module = m.group(1) - name = m.group(2) - if isflags: - fp.write('(flags ' + name + '\n') - else: - fp.write('(enum ' + name + '\n') - if module: - fp.write(' (in-module ' + module + ')\n') - fp.write(' (c-name ' + cname + ')\n') - prefix = entries[0] - for ent in entries: - # shorten prefix til we get a match ... - while ent[:len(prefix)] != prefix: - prefix = prefix[:-1] - for ent in entries: - fp.write(' (value (name ' + - string.translate(ent[len(prefix):], trans) + - ') (c-name ' + ent + '))\n') - fp.write(')\n\n') - -# ------------------ Find function definitions ----------------- - -#comment_pat = re.compile(r"""(/[*](.|\n)*?[*]/)|(^;.*$)""", re.MULTILINE) - -def clean_func(buf): - """ - Ideally would make buf have a single prototype on each line. - Actually just cuts out a good deal of junk, but leaves lines - where a regex can figure prototypes out. - """ - # bulk comments - pat = re.compile(r"""/[*](.|\n)*?[*]/""", re.MULTILINE) - buf=pat.sub('',buf) - - # Preprocess directives - pat = re.compile(r"""^[#].*?$""", re.MULTILINE) - buf=pat.sub('',buf) - - #typedefs, stucts, and enums - pat = re.compile(r"""^(typedef|struct|enum)(\s|.|\n)*?;\s*""", re.MULTILINE) - buf=pat.sub('',buf) - - #multiple whitespace - pat = re.compile(r"""\s+""", re.MULTILINE) - buf=pat.sub(' ',buf) - - #clean up line ends - pat = re.compile(r""";\s*""", re.MULTILINE) - buf=pat.sub('\n',buf) - - #associate *, &, and [] with type instead of variable - #pat=re.compile(r'\s+([*|&]+)\s*(\w+)') - pat=re.compile(r' \s+ ([*|&]+) \s* (\w+)',re.VERBOSE) - buf=pat.sub(r'\1 \2', buf) - pat=re.compile(r'\s+ (\w+) \[ \s* \]',re.VERBOSE) - buf=pat.sub(r'[] \1', buf) - - return buf - -proto_pat=re.compile(r""" -(?P<ret>(\w|\&|\*)+\s*) # return type -\s+ # skip whitespace -(?P<func>\w+)\s*[(] # match the function name until the opening ( -(?P<args>.*?)[)] # group the function arguments -""", re.IGNORECASE|re.VERBOSE) -#""" -arg_split_pat = re.compile("\s*,\s*") - -def define_func(buf,fp): - buf=clean_func(buf) - buf=string.split(buf,'\n') - for p in buf: - if len(p)==0: continue - m=proto_pat.match(p) - if m==None: - if verbose: - sys.stderr.write('No match:|%s|\n'%p) - continue - func = m.group('func') - ret = m.group('ret') - ret = string.replace(ret, 'const ', 'const-') - args=m.group('args') - args=arg_split_pat.split(args) - - for i in range(len(args)): - args[i] = string.replace(args[i], 'const ', 'const-') - - write_func(fp, func, ret, args) - -get_type_pat = re.compile(r'(const-)?([A-Za-z0-9]+)\*?\s+') -get_mod_pat = re.compile('([A-Z][a-z]+)([A-Za-z0-9]+)') - -def write_func(fp, name, ret, args): - if len(args) >= 1: - # methods must have at least one argument - munged_name = string.replace(name, '_', '') - m = get_type_pat.match(args[0]) - if m: - obj = m.group(2) - if munged_name[:len(obj)] == string.lower(obj): - regex = string.join(map(lambda x: x+'_?',string.lower(obj)),'') - mname = re.sub(regex, '', name) - fp.write('(method ' + mname + '\n') - m = get_mod_pat.match(obj) - if m: - fp.write(' (of-object ' + m.group(2) + - ' (' + m.group(1) + '))\n') - fp.write(' (c-name ' + name + ')\n') - if ret != 'void': - fp.write(' (return-type ' + ret + ')\n') - else: - fp.write(' (return-type none)\n') - for arg in args[1:]: - if arg == '...': - fp.write(' (varargs t)\n') - elif arg in ('void', 'void '): - pass - else: - fp.write(' (parameter (type-and-name ' + arg + '))\n') - fp.write(')\n\n') - return - # it is either a constructor or normal function - # FIXME: put in constructor check - fp.write('(function ' + name + '\n') - # do in-module thingee - fp.write(' (c-name ' + name + ')\n') - if ret != 'void': - fp.write(' (return-type ' + ret + ')\n') - else: - fp.write(' (return-type none)\n') - for arg in args: - if arg == '...': - fp.write(' (varargs t)\n') - elif arg == 'void' or arg == '': - pass - else: - fp.write(' (parameter (type-and-name ' + arg + '))\n') - fp.write(')\n\n') - -def write_def(input,output=None): - fp = open(input) - buf = fp.read() - fp.close() - - if type(output) == types.StringType: - fp = open(output,'w') - elif type(output) == types.FileType: - fp = output - else: - fp = sys.stdout - - fp.write('\n;; From %s\n\n' % input) - buf = define_func(buf, fp) - fp.write('\n') - -# ------------------ Glue code ----------------- - -def make_gdk_defs(): - """ This is intended to be run only by the package maintainer!!! """ - p='/usr/local/src/gtk+-1.2.6/gdk/' - gdk= [ - 'gdk.h', - 'gdkrgb.h', - #'gdktypes.h' - ] - fp=open('_gdk_func.defs','w') - for h in gdk: - write_def(p+h,fp) - fp.close() - -verbose=0 -if __name__ == '__main__': - import getopt - - opts, args = getopt.getopt(sys.argv[1:], 'v') - for o, v in opts: - if o=='-v': verbose=1 - - if not args[0:1]: - print 'Must specify at least one input file name' - sys.exit(-1) - - # read all the object definitions in - objdefs = [] - enums = [] - for filename in args: - buf = open(filename).read() - find_obj_defs(buf, objdefs) - if len(filename) > 11 and filename[-11:] == 'gtkobject.h': - objdefs.append(('GtkObject', None)) - find_enum_defs(buf, enums) - objdefs = sort_obj_defs(objdefs) - write_obj_defs(objdefs,None) - write_enum_defs(enums,None) - - for filename in args: - write_def(filename,None) Index: win32/buildconf.js =================================================================== RCS file: /repository/php-gtk/win32/buildconf.js,v retrieving revision 1.9 diff -u -r1.9 buildconf.js --- win32/buildconf.js 29 May 2007 12:40:22 -0000 1.9 +++ win32/buildconf.js 10 Aug 2008 17:52:58 -0000 @@ -112,6 +112,17 @@ continue; } + /* We may need to generate the extensions files here */ + c = FSO.BuildPath(fc.item(), "ext_data.php"); + if (FSO.FileExists(c)) { + var WshShell = WScript.CreateObject("WScript.Shell"); + if ( WshShell.Run("php generator/ext_gen.php " + c, 10, true) ) { + WScript.StdOut.WriteLine("\tError generating files"); + WScript.Quit(1); + } + } + + /* Now check if there's a config.w32, possibly created by */ c = FSO.BuildPath(fc.item(), "config.w32"); if (!FSO.FileExists(c)) { @@ -120,7 +131,7 @@ } else { - WScript.StdOut.WriteLine(" Available"); + WScript.StdOut.WriteLine(" Available on Windows"); var dir_line = "configure_module_dirname = condense_path(FSO.GetParentFolderName('" + c.replace(new RegExp('(["\\\\])', "g"), '\\$1') + "'));\r\n"; -- PHP-GTK Development Mailing List (http://gtk.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php |
|
|
Re: A new way for creating extensionsHey, this looks interesting!
I'm catching up on older mail, so I just now saw this. Looks like this could be a great replacement for ext_skel and more. I'll take a closer look in a bit. -Andrei Keisial wrote: > I recently had the need to create a php-gtk extension, and what i found > wasn't too pleasant. > Most code (gen_*.c) is autogenerated from the defs file by > generator/generator.php. Which itself is made by running h2def.py on the > C header. Well, it turns out generator/h2def.py is outdated. And by > outdated i mean that generator/generator.php *won't be able to process > that file*. Oops. > The solution is using the newer one maintained by the pygtk folks at > http://svn.gnome.org/svn/pygobject/trunk/codegen > It also has improvements such as no longer needing to edit the defs file > in order to specify which is the constructor. > > > Where to get the other files an extension needs? Well, there's a > skeleton extension precisely for a basis for that, right? Wrong! It is > also outdated. php_skeleton_register_constants() doesn't expect a > module_number, but a const char* Using it you get a nice sigsegv on > runtime. > > Finally, there's ext_skel, a shell script to copy the skeleton dir to > the widget's and avoid you the trouble or replacing each skeleton > occurrence by the new widget's name. It's also broken, although this may > be just in my setup. > > > So, you end up copying one of the working widgets and changing the name > in lots of places, with different capitalizations. You invariably forget > some, and have to try compiling several times until you get it right. As > Bob said when i asked how to create php-gtk extensions, "it is just not > very fun to do". > That labour would better be achieved by a script, and so i went into > making it. > > This new script resides in generator/ext_gen.php and hooks into the > build process, based on ext_data.php on each extension folder. You can > use it once to generate the files which you will then customize, or > leave them autogenerate on each build. This point is specially > interesting because most extensions haven't changed since they were > created by copy & replace, and provides a single point of improvement > into the system. Also, by keeping the generator in use by a number of > extensions, it is guaranteed to be kept up-to-date. > > Each extension defines a few parameters into the file ext_data.php, and > can have most its files autogenerated. The new generated scripts are > (expected to be) equivalent to the old ones. In fact, much of it is the > same code, to make a cvs diff as smaller as possible. However, there's a > number of improvements: > -grep | sed process replaced by just a sed > -gen_*.h created a bit more independed from gen_*.c > -Makefiles actions in one line broken on several. > -gen_*.h will include the prototypes of the exported functions of > gen_*.c, which would have warned the issue of the register_constants() > parameter type at compile time. > -php_*.h will include gen_*.h instead of placing the prototypes. > -Minor differences on text presented to the user, usually just of > capitalization (eg. 'Disable libglade support' vs 'Disable libGlade > support'). > > > Transitioned extensions: extra, html, libglade, libsexy > Unchanged: gtk+ (lots of special stuff), mozembed (three different > modules), scintilla (several customizations), spell (standalone) > I have done my best to ensure it doesn't break anything, but any > comments are welcome. You can also reach me at #php-gtk. The extensions > still build fine on Linux with the patch. On windows, it still fails, as > it did without it, so SNAFU. > > Added files: > extra/ext_data.php > html/ext_data.php > libglade/ext_data.php > libsexy/ext_data.php > generator/ext_gen.php > > Modified: > win32/buildconf.js > build2/build.mk > > Removed: > generator/h2def.py > ext/ext_skel > ext/skeleton/* [keep skeleton.overrides?] > > Deprecated: > extra/config.m4,config.w32,Makefile.frag,php_gtkextra.c,php_gtkextra.h > html/config.m4,config.w32,Makefile.frag,php_html.c,php_html.h > libglade/config.m4,config.w32,Makefile.frag,php_libglade.c,php_libglade.h > libsexy/config.m4,config.w32,Makefile.frag,php_libsexy.c,php_libsexy.h > > Renamed (apply manually): > mv extra/gtkextra.defs extra/extra.defs > mv extra/gtkextra.overrides extra/extra.overrides > mv libsexy/sexy.overrides libsexy/libsexy.overrides > mv libsexy/sexy.defs libsexy/libsexy.defs > > Opinions? > -- PHP-GTK Development Mailing List (http://gtk.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php |
|
|
Re: A new way for creating extensionsAndrei Zmievski wrote:
> Hey, this looks interesting! > > I'm catching up on older mail, so I just now saw this. Looks like this > could be a great replacement for ext_skel and more. I'll take a closer > look in a bit. > > -Andrei Please note that, as I noticed after sending the email to this list, it won't work on a completely clean Linux (a clean left some files behind). You may need to uncomment the 'defined at gen_{$widget_name}.h' and maybe remove its include. Check the exact error. The generated makefile missed a dependency and the bits that would need to be changed weren't provided by php-gtk but on the php config.m4, then used by phpize. It's still an improvement, but not as complete as I originally intended. I look forward to your comments. -- PHP-GTK Development Mailing List (http://gtk.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php |
| Free embeddable forum powered by Nabble | Forum Help |