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: Select all
/*
* 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: Select all
/*
* 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: Select all
/*
* 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: Select all
/*
* 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: Select all
# 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
Code: Select all
$ 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