Ethereal-dev: [Ethereal-dev] Building plugins with mingw works

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Scott Renfro <scott@xxxxxxxxxx>
Date: Thu, 18 Apr 2002 09:03:07 -0700
Summary: You can indeed use mingw (gcc for win32) to build a plugin that
works with the win32 Ethereal binary from www.ethereal.com (which is
compiled with MS Visual C++).  Although I was building a proprietary
dissector that can't be released, I wanted to document the required
tricks so others can do this without MS Dev Studio and without building
the entire Ethereal win32 binary.

There are bits of this that would be worth committing (e.g., the
config.h.mingw, config.mingw, plugins/plugin.def.mingw, and patch to
plugin_api.h).  The others (plugins/Makefile.mingw and
plugins/FOO/Makefile.mingw, changes to plugin_api.c) are more
questionable.  It may be worth adding this to doc/README.plugins.  Some
of this may lay the groundwork for building Ethereal from scratch using
mingw.

What You Need

  - The win32 binary release of Ethereal (0.9.2 in this case)

  - The corresponding source code tarball (0.9.2 also; note that using a
    different source tarball will likely result in problems).

  - The gtk development tarball (gtk+-dev-20001226.zip) from
    www.ethereal.com/distribution/win32/development.  This includes both
    the glib and gtk header files you need.  For convenience, I
    extracted the tarball in the same parent directory as the ethereal
    source.  We assume you extract these into c:/ethereal-win32-libs/.

  - The mingw and make distributions from http://mingw.sf.net

  - A few UNIX-sh tools. Install UnxUtils from http://unxutils.sf.net

Preparing to build

  - First, get a plugin working under Unix, if at all possible.
    Otherwise, follow the directions in doc/README.plugins.  We assume
    this is in place as a starting point.

  - Ethereal source modifications.  Several modifications to the
    existing code base are required to appease mingw.

    - Add global function pointers to plugins/plugin_api.c.

      Copy the field list contained in the typedef struct
      plugin_address_table_t (but not the surrounding structure
      definition) from plugins/plugin_table.h and paste them at the end
      of plugins/plugin_api.c.  This creates a set of global variables
      that mirror those contained within that structure.  I'm not
      providing a diff for this since it changes from release to release
      and is a 10 second operation to copy and paste.

      Here's why: the plugin needs to call methods in the parent
      executable.  While this works fine on some OSes (e.g., UNIX), it
      doesn't work on Win32.  In such cases, plugins/plugin_api.{c,h}
      and plugins/plugin_table.h provide a table of pointers that is
      passed to the plugin and used to initialize a set of global
      function pointers in the plugin.  This trick allows the same
      source to be used with and without function pointers depending on
      whether or not the address table is required.

      Unfortunately, gcc doesn't see the global pointers (actually, it's
      not clear to me how Dev Studio does see them or where they exist,
      but that's another discussion, perhaps).  Copying the fields out
      of the struct and pasting them into plugin_api.c, which is linked
      with the plugin, creates the global variables inside the dll that
      are initialized in the plugin_init() call.

    - Disable the gcc __attribute__(x) extensions for the function
      pointers.

      Although there's surely a more surgical, elegant, and proper way
      to accomplish this, here's one that works: in
      plugins/plugin_api.h, just before the includes, within the #ifdef
      PLUGINS_NEED_ADDRESS_TABLE, add the following lines (the attached
      patchfile will also do this):

          #if defined(WIN32) && defined(__GNUC__)
          #define __attribute__(x)
          #endif

      This will cause the later includes within this compilation unit to
      erase the gcc __attribute__ extensions.  Here's why: apparently
      gcc doesn't support the use of this extension with function
      pointers.  The code in plugins/plugin_api.h translates several
      Ethereal functions into function pointer declarations, so we need
      to disable the extension for those functions.

  - Add the build framework.  The following files need to be added,
    which will allow your plugin to build.  The attached patch will
    create generic copies of these.

    - config.h.mingw.  Copy this file over config.h, epan/config.h,
      wiretap/config.h.  It contains the proper #defines to control
      inclusion/exclusion of various header files.  (Note that the
      VERSION string is hard coded in this file; I didn't do the same
      @VERSION@ sed trick that config.h.nmake used since I didn't have a
      global Makefile.mingw.  You'll have to update the version string
      before use.)

    - config.mingw.  This file contains the make variables, including
      compiler name, locations of libraries, header files, etc.

    - plugins/Makefile.mingw.  This builds plugin_api.o and then builds
      the specified plugins by calling their makefiles.  Replace FOO in
      PROTO=FOO with the name of your plugin's directory.  You could
      retrofit this with the SUBDIR approach more common in other
      Makefiles.

    - plugins/plugin.def.mingw.  This file specifies which symbols
      should be exported and the order in which they should be exported.
      It's completely boilerplate and can be shared by all plugins, so
      no modifications should be required.

    - plugins/FOO/Makefile.mingw.  This builds your plugin from
      packet-proto.c.  Replace FOO in PROTO=FOO PROTO with the name of
      your protocol.  This assumes that your source files and dll name
      are based on your short protocol name -- which is the case for
      nearly all Ethereal development.

  - Modifying your plugin source code.  If you followed
    doc/README.plugins closely, then nothing special needs to be done.
    You do want to be sure you wrap your includes in appropriate guards
    (e.g., for <netinet/in.h> guard with HAVE_NETINET_IN_H).

Building the plugin

  The hard work is all finished.  Here's how to build it:

      cd plugins
      make -f Makefile.mingw
      copy FOO/FOO.dll c:\program files\ethereal\plugins\VERSION\
   
  Start Ethereal and it should all ``just work.''

Caveat: these are my sketchy notes and reflect one (successful) attempt
with one version of Ethereal. This is intended for experienced
developers and may or may not work for you or your plugins.  If it
doesn't, I probably don't have time to help you debug the problem.

Best of luck,
--Scott

-- 
Scott Renfro <scott@xxxxxxxxxx>
diff -ruN ethereal-0.9.2.orig\config.h.mingw ethereal-0.9.2\config.h.mingw
--- ethereal-0.9.2.orig\config.h.mingw	Wed Dec 31 16:00:00 1969
+++ ethereal-0.9.2\config.h.mingw	Wed Apr 17 11:14:19 2002
@@ -0,0 +1,114 @@
+/* config.h.  Generated automatically by configure.  */
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+/* #undef WORDS_BIGENDIAN */
+
+/* Define if lex declares yytext as a char * by default, not a char[].  */
+/* #undef YYTEXT_POINTER */
+
+#define HAVE_PLUGINS		1
+#define PLUGINS_NEED_ADDRESS_TABLE 1
+
+/* #undef HAVE_SA_LEN */
+
+/* #undef NEED_SNPRINTF_H */
+
+/* #undef NEED_STRERROR_H */
+
+#define NEED_MKSTEMP 1
+
+#define HAVE_LIBPCAP 1
+
+/* Define if you have the gethostbyname2 function.  */
+/* #undef HAVE_GETHOSTBYNAME2 */
+
+/* Define if you have the getprotobynumber function.  */
+/* #undef HAVE_GETPROTOBYNUMBER */
+
+/* Define if you have the <arpa/inet.h> header file.  */
+/* #undef HAVE_ARPA_INET_H */
+
+/* Define if you have the <fcntl.h> header file.  */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <iconv.h> header file.  */
+/* #undef HAVE_ICONV_H */
+
+/* Define if you have the <netdb.h> header file.  */
+/* #undef HAVE_NETDB_H */
+
+/* Define if you have the <netinet/in.h> header file.  */
+/* #define HAVE_NETINET_IN_H 1 */
+
+/* Define if you have the <snmp/snmp.h> header file.  */
+/* #undef HAVE_SNMP_SNMP_H */
+
+/* Define if you have the <snmp/version.h> header file.  */
+/* #undef HAVE_SNMP_VERSION_H */
+
+/* Define if you have the <stdarg.h> header file.  */
+#define HAVE_STDARG_H 1
+
+/* Define if you have the <stddef.h> header file.  */
+#define HAVE_STDDEF_H
+
+/* Define if you have the <sys/ioctl.h> header file.  */
+/* #undef HAVE_SYS_IOCTL_H */
+
+/* Define if you have the <sys/socket.h> header file.  */
+/* #undef HAVE_SYS_SOCKET_H */
+
+/* Define if you have the <sys/sockio.h> header file.  */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define if you have the <sys/stat.h> header file.  */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/time.h> header file.  */
+#define HAVE_SYS_TIME_H 1
+
+/* Define if you have the <sys/types.h> header file.  */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have the <sys/wait.h> header file.  */
+/* #undef HAVE_SYS_WAIT_H */
+
+/* Define if you have the <ucd-snmp/snmp.h> header file.  */
+/* #undef HAVE_UCD_SNMP_SNMP_H */
+
+/* Define if you have the <ucd-snmp/version.h> header file.  */
+/* #undef HAVE_UCD_SNMP_VERSION_H */
+
+/* Define if you have the <unistd.h> header file.  */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the z library (-lz).  */
+/*#define HAVE_LIBZ 1*/
+
+#ifndef WIN32
+#define WIN32			1
+#endif
+
+#define HAVE_WINDOWS_H		1
+#define HAVE_WINSOCK_H		1
+#define HAVE_DIRECT_H		1
+#define HAVE_IO_H		1
+#define NEED_INET_ATON_H	1
+#define NEED_INET_V6DEFS_H	1
+#define NEED_STRPTIME_H		1
+#define snprintf 		_snprintf
+#define vsnprintf 		_vsnprintf
+
+/* Name of package */
+#define PACKAGE "ethereal"
+
+/* Version number of package */
+#define VERSION "0.9.2"
+
+/* Plugin installation directory */
+#define PLUGIN_DIR NULL
diff -ruN ethereal-0.9.2.orig\config.mingw ethereal-0.9.2\config.mingw
--- ethereal-0.9.2.orig\config.mingw	Wed Dec 31 16:00:00 1969
+++ ethereal-0.9.2\config.mingw	Wed Apr 17 11:36:23 2002
@@ -0,0 +1,32 @@
+# $Id: $
+
+CC=gcc
+MAKE=make
+
+VERSION=0.9.2
+RC_VERSION=0.9.2
+WTAP_VERSION=0.0
+
+GTK_VERSION=1.3
+GLIB_VERSION=1.3
+
+GLIB_DIR=C:/ethereal-win32-libs/glib
+GTK_DIR=C:/ethereal-win32-libs/gtk+
+ZLIB_DIR=C:/ethereal-win32-libs/zlib-1.1.3
+PCAP_DIR=C:/ethereal-win32-libs/WPdpack
+
+LOCAL_CFLAGS=
+LOCAL_LDFLAGS=
+
+PERL=perl
+POD2MAN=pod2man
+POD2HTML=pod2html
+PYTHON="C:/python22/python.exe"
+LEX=flex
+YACC=bison
+
+# Set YACC_OPTS if cygnus bison can't find template file.
+#YACC_OPTS=-S t:/w32-ix86/cygnus/cygwin-b20/share/bison.simple 
+
+# To build the installer
+MAKENSIS="C:/program files/nsis/makensis.exe"
diff -ruN ethereal-0.9.2.orig\plugins\Makefile.mingw ethereal-0.9.2\plugins\Makefile.mingw
--- ethereal-0.9.2.orig\plugins\Makefile.mingw	Wed Dec 31 16:00:00 1969
+++ ethereal-0.9.2\plugins\Makefile.mingw	Wed Apr 17 11:52:09 2002
@@ -0,0 +1,30 @@
+#
+# $Id: Makefile.nmake,v 1.13 2002/02/27 09:42:44 guy Exp $
+#
+
+include ../config.mingw
+
+PROTO=FOO
+
+CC=gcc
+
+CFLAGS=-DHAVE_CONFIG_H -I.. -I.. -I../wiretap -I. \
+	-I$(GLIB_DIR) -I$(GTK_DIR) -I$(GLIB_DIR)/gmodule \
+	-I$(GTK_DIR)/gdk -I$(GTK_DIR)/gdk/win32 \
+	-I$(PCAP_DIR)/include -D_U_="" $(LOCAL_CFLAGS)
+
+OBJECTS=plugin_api.o
+
+all: plugin_api.o $(PROTO)-dir
+
+$(PROTO)-dir:
+	cd $(PROTO); \
+	$(MAKE) -f Makefile.mingw; \
+	cd ..
+
+clean:
+	rm -f $(OBJECTS); \
+	cd $(PROTO); \
+	$(MAKE) -f Makefile.mingw clean; \
+	cd ..
+
diff -ruN ethereal-0.9.2.orig\plugins\plugin.def.mingw ethereal-0.9.2\plugins\plugin.def.mingw
--- ethereal-0.9.2.orig\plugins\plugin.def.mingw	Wed Dec 31 16:00:00 1969
+++ ethereal-0.9.2\plugins\plugin.def.mingw	Wed Apr 17 10:35:08 2002
@@ -0,0 +1,4 @@
+EXPORTS
+	plugin_init @ 0 ; 
+	plugin_reg_handoff @ 1 ; 
+	version @ 2 DATA ; 
diff -ruN ethereal-0.9.2.orig\plugins\plugin_api.h ethereal-0.9.2\plugins\plugin_api.h
--- ethereal-0.9.2.orig\plugins\plugin_api.h	Sat Feb 23 11:12:30 2002
+++ ethereal-0.9.2\plugins\plugin_api.h	Wed Apr 17 11:46:14 2002
@@ -202,6 +202,12 @@
 #define dissect_tpkt_encap		(*p_dissect_tpkt_encap)
 
 /* TPKT entries End */
+
+/* disable gcc attributes when using mingw and plugin address table macros */
+#if defined(WIN32) && defined(__GNUC__)
+#define __attribute__(x)
+#endif
+
 #endif
 
 #include <epan/packet.h>
diff -ruN ethereal-0.9.2.orig\plugins\FOO\Makefile.mingw ethereal-0.9.2\plugins\FOO\Makefile.mingw
--- ethereal-0.9.2.orig\plugins\FOO\Makefile.mingw	Wed Dec 31 16:00:00 1969
+++ ethereal-0.9.2\plugins\FOO\Makefile.mingw	Wed Apr 17 12:37:40 2002
@@ -0,0 +1,26 @@
+#
+# $Id: Makefile.nmake,v 1.8 2002/02/27 09:42:47 guy Exp $
+#
+
+include ../../config.mingw
+
+PROTO=FOO
+
+############### no need to modify below this line #########
+
+CFLAGS=-DHAVE_CONFIG_H -I.. -I../.. -I../../wiretap -I. \
+	-I$(GLIB_DIR) -I$(GTK_DIR) -I$(GLIB_DIR)/gmodule \
+	-I$(GTK_DIR)\gdk -I$(GTK_DIR)\gdk\win32 \
+	-I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS)
+
+OBJECTS=packet-$(PROTO).o ../plugin_api.o
+
+$(PROTO).dll: $(OBJECTS)
+	dllwrap --def ../plugin.def.mingw -dllname=$(PROTO).dll --driver-name=gcc $(OBJECTS)
+
+packet-$(PROTO).o: packet-$(PROTO).c
+	gcc $(CFLAGS) -c packet-$(PROTO).c
+
+clean:
+	rm -f $(OBJECTS) $(PROTO).dll 
+