| View previous topic :: View next topic |
| Author |
Message |
Kappa007 Voice
Joined: 26 Jul 2005 Posts: 38
|
Posted: Fri Jan 20, 2006 10:14 pm Post subject: Example: Module in C++ |
|
|
Oke, since some people (including myself ) thought it might be useful to be able to write modules C++ rather than in plain C here we go
The problem when trying to use C++ code with eggdrop is that eggdrop uses some global function table for imports which does not mix very with C++.
A simple "extern C" is not enough to be able to include the "module.h".
So my approach is to use a wrapper.
We start building normal module which wraps all stuff we need and compile that one with C.
Then we take the header file of that and just include it in our C++ files.
At the end we link all together.
Only thing we need are some structs from eggdrop to be able to bind/unbind commands from C++.
The whole thing ofcourse only works well when we don't need A LOT of eggdrop core functions cause then it might be a lot work to wrap them all
My example module is called "cpphello.mod" and it just outputs a message to channel when triggered via "!hello".
| Code: |
/*
* hello.h -- part of cpphello.mod
*
* Example how to write an eggdrop module in C++
*
* Originally written by Kappa007 2006-01-21
*
*
* Copyright (c) by Kappa007. All rights reserved.
*/
#ifndef __HELLO_H__
#define __HELLO_H__
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
/*** Common typedefs and structs from eggdrop ***/
typedef void (*Function) ();
struct flag_record {
int match;
int global;
int udef_global;
int bot;
int chan;
int udef_chan;
};
typedef unsigned short int u_16bit_t;
typedef unsigned char u_8bit_t;
typedef struct tcl_cmd_b {
struct tcl_cmd_b *next;
struct flag_record flags;
char *func_name; /* Proc name. */
int hits; /* Number of times this proc was triggered. */
u_8bit_t attributes; /* Flags for this entry. TC_* */
} tcl_cmd_t;
typedef struct tcl_bind_mask_b {
struct tcl_bind_mask_b *next;
tcl_cmd_t *first; /* List of commands registered for this bind. */
char *mask;
u_8bit_t flags; /* Flags for this entry. TBM_* */
} tcl_bind_mask_t;
typedef struct tcl_bind_list_b {
struct tcl_bind_list_b *next;
tcl_bind_mask_t *first; /* Pointer to registered binds
* for this list. */
char name[5]; /* Name of the bind. */
u_8bit_t flags; /* Flags for this element. HT_* */
::Function func; /* Function used as the Tcl calling interface
* for procs actually representing C functions. */
} tcl_bind_list_t, *p_tcl_bind_list;
typedef struct {
char *name;
char *flags;
::Function func;
char *funcname;
} cmd_t;
/*** Prototypes ***/
int BindCommand(unsigned char table, cmd_t* cc, unsigned char bind);
void PutServer(const char* text);
void PutDCC(const int idx, const char* text);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // __HELLO_H__
|
| Code: |
/*
* hello.c -- part of cpphello.mod
*
* Example how to write an eggdrop module in C++
*
* Originally written by Kappa007 2006-01-21
*
*
* Copyright (c) by Kappa007. All rights reserved.
*/
#define MODULE_NAME "CppHello"
#include "src/mod/module.h"
#include <stdlib.h>
#undef global
/*** Include your C++ exports here ***/
#include "hello.hpp"
static Function *global = NULL;
static int CppHello_expmem()
{
return 0;
}
static void CppHello_report(int idx, int details)
{
dprintf(idx, "%s running.", MODULE_NAME);
}
static char* CppHello_close()
{
ShutdownCppModule();
module_undepend(MODULE_NAME);
return NULL;
}
EXPORT_SCOPE char* CppHello_start();
static Function CppHello_table[] = {
(Function) CppHello_start,
(Function) CppHello_close,
(Function) CppHello_expmem,
(Function) CppHello_report,
};
char* CppHello_start(Function *global_funcs)
{
global = global_funcs;
module_register(MODULE_NAME, CppHello_table, 1, 0);
//TODO: check module dependencies here
// Call the "init" of your C++ code
InitCppModule();
return NULL;
}
/*** wrapper functions ***/
int BindCommand(unsigned char table, cmd_t* cc, unsigned char bind)
{
if (cc == NULL)
{
return -1;
}
// get the bind table
p_tcl_bind_list H_temp;
switch (table)
{
case 0:
H_temp = find_bind_table("dcc");
break;
case 1:
H_temp = find_bind_table("msg");
break;
case 2:
H_temp = find_bind_table("pub");
break;
default:
return -1;
}
if (!H_temp) return -1;
// add or remove commands
if (bind != 0)
{
add_builtins(H_temp, cc);
}
else
{
rem_builtins(H_temp, cc);
}
return 0;
}
void PutServer(const char* text)
{
dprintf(DP_SERVER, text);
}
void PutDCC(const int idx, const char* text)
{
dprintf(idx, text);
}
|
| Code: |
/*
* hello.hpp -- part of cpphello.mod
*
* Example how to write an eggdrop module in C++
*
* Originally written by Kappa007 2006-01-21
*
*
* Copyright (c) by Kappa007. All rights reserved.
*/
#ifndef __HELLO_HPP__
#define __HELLO_HPP__
#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus
void InitCppModule();
void ShutdownCppModule();
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // __HELLO_HPP__
|
| Code: |
/*
* hello.cpp -- part of cpphello.mod
*
* Example how to write an eggdrop module in C++
*
* Originally written by Kappa007 2006-01-21
*
*
* Copyright (c) by Kappa007. All rights reserved.
*/
#include "hello.h"
#include "hello.hpp"
#include <string>
using namespace std;
class MyHelloClass;
static MyHelloClass* myHelloClass = NULL;
int ChanHello(char *nick, char *host, char *hand, char *channel, char *text);
class MyHelloClass
{
private:
cmd_t* myCommandTable;
string myReply;
public:
MyHelloClass(string aReply) :
myCommandTable( NULL ),
myReply( aReply )
{
myCommandTable = new cmd_t[2];
myCommandTable[0].name = "!hello";
myCommandTable[0].flags = "";
myCommandTable[0].func = reinterpret_cast<Function>(&ChanHello);
myCommandTable[0].funcname = NULL;
memset(static_cast<void*>(&myCommandTable[1]), 0, sizeof(cmd_t));
::BindCommand(2, myCommandTable, true);
}
~MyHelloClass()
{
::BindCommand(2, myCommandTable, false);
if (myCommandTable != NULL) delete[] myCommandTable;
}
string Reply()
{
return myReply;
}
};
void InitCppModule()
{
myHelloClass = new MyHelloClass("Hello from C++!");
}
void ShutdownCppModule()
{
if (myHelloClass != NULL)
{
delete myHelloClass;
}
}
int ChanHello(char *nick, char *host, char *hand, char *channel, char *text)
{
string aMsg = "";
aMsg += "PRIVMSG ";
aMsg += channel;
aMsg += " :";
aMsg += myHelloClass->Reply();
PutServer( aMsg.c_str() );
return 0;
}
|
| Code: |
# Makefile for src/mod/cpphello.mod/
srcdir = .
doofus:
@echo ""
@echo "Let's try this from the right directory..."
@echo ""
@cd ../../../ && make
static: ../cpphello.o
modules: ../../../cpphello.$(MOD_EXT)
../hello.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -DMAKING_MODS -c $(srcdir)/hello.c
@rm -f ../hello.o
mv hello.o ../
../hello_cpp.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -DMAKING_MODS -c $(srcdir)/hello.cpp -o $(srcdir)/hello_cpp.o
@rm -f ../hello_cpp.o
mv hello_cpp.o ../
../../../cpphello.$(MOD_EXT): \
../hello.o \
../hello_cpp.o
$(LD) -o ../../../cpphello.$(MOD_EXT) ../hello.o ../hello_cpp.o -lstdc++ $(XLIBS) $(MODULE_XLIBS)
$(STRIP) ../../../cpphello.$(MOD_EXT)
depend:
$(CC) $(CFLAGS) $(CPPFLAGS) -MM $(srcdir)/cpphello.c > .depend
clean:
@rm -f .depend *.o *.$(MOD_EXT) *~
distclean: clean
#safety hash
../cpphello.o: .././cpphello.mod/cpphello.c ../../../src/mod/module.h \
../../../src/main.h ../../../src/lang.h ../../../src/eggdrop.h \
../../../src/flags.h ../../../src/proto.h ../../../lush.h \
../../../src/misc_file.h ../../../src/cmdt.h ../../../src/tclegg.h \
../../../src/tclhash.h ../../../src/chan.h ../../../src/users.h \
../../../src/compat/compat.h ../../../src/compat/inet_aton.h \
../../../src/compat/snprintf.h \
../../../src/compat/memset.h ../../../src/compat/memcpy.h \
../../../src/compat/strcasecmp.h ../../../src/mod/modvals.h \
../../../src/tandem.h
|
Tested with eggdrop v1.6.17 and
| Code: |
$ uname -a
CYGWIN_NT-5.2 BETA 1.5.18(0.132/4/2) 2005-07-02 20:30 x86_64 unknown unknown Cygwin
$ gcc -v
Reading specs from /usr/lib/gcc/i686-pc-cygwin/3.4.4/specs
Configured with: /gcc/gcc-3.4.4/gcc-3.4.4-1/configure --verbose --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc --libdir=/usr/l
ib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-languages=c,ada,c++,d,f77,java,objc --enable-n
ls --without-included-gettext --enable-version-specific-runtime-libs --without-x --enable-libgcj --disable-java-awt --with-system-
zlib --enable-interpreter --disable-libgcj-debug --enable-threads=posix --enable-java-gc=boehm --disable-win32-registry --enable-s
jlj-exceptions --enable-hash-synchronization --enable-libstdcxx-debug : (reconfigured)
Thread model: posix
gcc version 3.4.4 (cygming special) (gdc 0.12, using dmd 0.125)
|
Have fun!
Regards,
Kappa007
Last edited by Kappa007 on Sun May 21, 2006 9:56 am; edited 3 times in total |
|
| Back to top |
|
 |
demond Revered One

Joined: 12 Jun 2004 Posts: 3073 Location: San Francisco, CA
|
Posted: Fri Jan 20, 2006 11:50 pm Post subject: |
|
|
congratulations!
good job indeed _________________ connection, sharing, dcc problems? click <here>
before asking for scripting help, read <this>
use [code] tag when posting logs, code |
|
| Back to top |
|
 |
tulpik Voice
Joined: 15 May 2006 Posts: 4
|
Posted: Mon May 15, 2006 7:38 am Post subject: Compilation problems. |
|
|
Hellow Kappa007, i am problem with compile example module.
| Code: |
gcc -pipe -fPIC -g -O2 -Wall -I. -I../../.. -I../../.. -I../../../src/mod -DHAVE_CONFIG_H -DMAKING_MODS -c .././cpphello.mod/hello.c
In file included from ../cpphello.mod/hello.c:20:
../cpphello.mod/hello.hpp:20: error: syntax error before "InitCppModule"
../cpphello.mod/hello.hpp:20: warning: type defaults to `int' in declaration of `InitCppModule'
../cpphello.mod/hello.hpp:20: warning: data definition has no type or storage class
../cpphello.mod/hello.hpp:21: error: syntax error before "ShutdownCppModule"
../cpphello.mod/hello.hpp:21: warning: type defaults to `int' in declaration of `ShutdownCppModule'
../cpphello.mod/hello.hpp:21: warning: data definition has no type or storage class
make[2]: *** [../hello.o] Error 1
make[2]: Leaving directory `/home/gimper/downloads/eggdrop/src/mod/cpphello.mod'
make[1]: *** [cpphello.mod_so] Error 2
make[1]: Leaving directory `/home/gimper/downloads/eggdrop/src/mod'
make: *** [modules] Error 2
|
Please pack your code to zip archive and share it. Thanx!
tulpik |
|
| Back to top |
|
 |
De Kus Revered One

Joined: 15 Dec 2002 Posts: 1361 Location: Germany
|
Posted: Mon May 15, 2006 7:57 am Post subject: |
|
|
the errors occur in
| Code: | void __stdcall InitCppModule();
void __stdcall ShutdownCppModule(); |
seems they don't like the __stdcall, maybe its not defined. missing a header file? _________________ De Kus
StarZ|De_Kus, De_Kus or DeKus on IRC
Copyright © 2005-2009 by De Kus - published under The MIT License
Love hurts, love strengthens... |
|
| Back to top |
|
 |
tulpik Voice
Joined: 15 May 2006 Posts: 4
|
Posted: Mon May 15, 2006 8:05 am Post subject: |
|
|
| What header file? hello.h? No, I copy code form web to files. |
|
| Back to top |
|
 |
De Kus Revered One

Joined: 15 Dec 2002 Posts: 1361 Location: Germany
|
|
| Back to top |
|
 |
tulpik Voice
Joined: 15 May 2006 Posts: 4
|
Posted: Mon May 15, 2006 8:19 am Post subject: |
|
|
Lol
Btw, probaly nothing. |
|
| Back to top |
|
 |
Alchera Revered One

Joined: 11 Aug 2003 Posts: 3344 Location: Ballarat Victoria, Australia
|
Posted: Mon May 15, 2006 7:29 pm Post subject: |
|
|
| tulpik wrote: | | What header file? hello.h? No, I copy code form web to files. |
Did you correctly name the sections (posted above)? There's 5 files in total, not one.
i.e. hello.h hello.c hello.hpp hello.cpp and finally the makefile
Do you know what a header file is? _________________ Add [SOLVED] to the thread title if your issue has been.
Search | FAQ | RTM |
|
| Back to top |
|
 |
tulpik Voice
Joined: 15 May 2006 Posts: 4
|
Posted: Tue May 16, 2006 4:06 am Post subject: |
|
|
| Yes I create 5 files with Makefile. |
|
| Back to top |
|
 |
Kappa007 Voice
Joined: 26 Jul 2005 Posts: 38
|
Posted: Thu May 18, 2006 5:57 pm Post subject: |
|
|
Yes cut the __stdcall, it's not needed.
__stdcall is the calling-convention of the Win32 API it's usually not used on *nix/g++
Only appeared there cause I used cygwin... |
|
| Back to top |
|
 |
De Kus Revered One

Joined: 15 Dec 2002 Posts: 1361 Location: Germany
|
Posted: Fri May 19, 2006 8:02 pm Post subject: |
|
|
then add define to zero string for __stdcall, if its not compiling on win32 . _________________ De Kus
StarZ|De_Kus, De_Kus or DeKus on IRC
Copyright © 2005-2009 by De Kus - published under The MIT License
Love hurts, love strengthens... |
|
| Back to top |
|
 |
Kappa007 Voice
Joined: 26 Jul 2005 Posts: 38
|
Posted: Sun May 21, 2006 9:58 am Post subject: |
|
|
| Edited the code (removed the __stdcall). Should work now. |
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|