Click here to Skip to main content
Click here to Skip to main content
Go to top

Gecko! Embedded C++ scripting for your applications

, 31 Aug 2003
Rate this:
Please Sign up or sign in to vote.
Embed a C++ compiler in your project, use C++ as a compiled "scripting" language!

What? Are you Crazy?

Scripting languages are a trendy thing. Take the game Morrowind by Bethesda Softworks, for example. This game runs a lot of scripts in a custom language: tons of scripts compiled in a pseudo bytecode form before to be run inside the game. Same for the game Age of Mythology by Ensemble Studios: it uses a custom script language for the computer AI programming. This is thus a critical part in several programs, and program's speed depends in a part on them.

I love speed. I love speedy programs, well-programmed applications. I'm still looking for speed, and I hope, like many of you. I then thought, as I was really inspired: why not embed a C++ compiler to use C++ as a compiled "scripting" language?

I thought about the well-known GNU GCC project. If you don't know it, it is an open-source C/C++/Java/others compiler, aiming primarily Linux platforms. The major advantage of this set of developer tools is that it is free. I thought I would be able to compile the GCC sources in a pretty Windows DLL; that revealed to be pretty impossible. I found out the MinGW project. This was pretty good: compiled compiler + Windows and standard headers + libraries in a relatively small package (15MB).

Surely, a 15MB package is actually big to some projects. But this article aims primarily big projects such as games. And, if you keep only the needed files (headers + libraries + c++ compiler) from the MinGW package, you will get easily to less than 4MB (compressed).

And, embedding MinGW is actually not necessary if you don't want to give end-user the ability to modify or create new scripts.

Actually Gecko brings you the fastest "scripting" language on the world! See the The Great Computer Language Shootout, and see how fast is gcc (even g++) compared to some well-known languages. Besides, using native machine code (compiled C++) allows having a very low memory usage, compared to some other scripting languages which can require an interpreter, or a bytecode interpreter. Furthermore, thanks to MinGW supplied libraries and headers, you have infinite possibilities: use windows.h functions, math.h functions, IO functions...

Another thing: you may be wondering: why Gecko? Gecko stands for "Gnu Embedded C++ KOmpiler" (I was really, really inspired this day Smile | :) ). Gecko produces ECK files. ECK stands for "Embedded C++, Kompiled". ECK files are in fact renamed DLL files, as you may have guessed.

But What is Gecko?

The Gecko thing consists actually of several things:

  • The idea of an embedded C++ compiler for scripting facility,
  • The GeckoSetup tool which generates a lot a code for your convenience (GeckoSetup relies on PXPerl namespace).
  • The CGecko class. Sample use:
CGecko gecko;


if (!gecko.IsEckUpToDate("test"))
  gecko.Compile("test");

if (gecko.Load("test"))
{
  if (gecko.RunThreaded())
  {
    printf("[Press any key to abort]");
    getchar();
    gecko.AbortThread();
  }
}

Visually

The CGecko class - Public Methods

The CGecko class relies on the CRedirect class to redirect standard IO while running MinGW (class found on codeproject -- great thanks to his author).

Read carefully each comment before using functions.

class CGecko : protected CRedirect
{

public:
  // ctor does nothing special.
  // dtor will call AbortThread() and Unload() if you ommit them.
  CGecko(void);
  ~CGecko(void);


  // Normally initialization is done automatically 
  // thanks to GeckoSetup code
  // so you shouldn't use these functions. Anyway they 
  // are self-explanatory.
  void SetMinGWDir(LPCSTR szDir);
  void SetGeckoDir(LPCSTR szDir);


  // Tests if a ECK file is up-to-date, by checking the
  // INI written when compiled.
  // If the ECK file or the INI file can't be found,
  // eckIsUpToDate() returns false.
  bool eckIsUpToDate(LPCSTR szName);
  // Tests if ECK file exists.
  bool eckExists(LPCSTR szName);
  // Launches compilation/linkage of the "szName.cpp" file.
  // Compiler/linker outputs will go to virtual functions below.
  // WARNING: if you try to re-compile to an ECK 
  // previously loaded, even unloaded,
  // the linker will complain: 'Unable to write(...)'. That's 
  // because I don't manage to have
  // the ECK file unmapped from process. See eckUnload() below.
  bool eckCompile(LPCSTR szName);

  // Overridable functions called when compiling.
  virtual void OnCommandStart(LPCSTR lpszCmdLine) {};
  virtual void OnCommandSTDOUT(LPCSTR lpszOutput) {};
  virtual void OnCommandSTDERR(LPCSTR lpszOutput) {};
  virtual void OnCommandEnd(bool bSuccessful) {};

  // Loads an ECK file. If a ECK file is already loaded/running, 
  // it will be automatically stopped/unloaded.
  // To execute several ECK's, construct several CGecko.
  bool eckLoad(LPCSTR szName);
  // Unloads an ECK file. Actually it will never be unloaded 
  // completely until program termination:
  // variables will remain with the same value at next Load() 
  // of the same ECK.
  // That's because I don't manage to have the ECK file unmapped
  // from process, even with several calls
  // to FreeLibrary(). If someone has an idea...
  void eckUnload(void);

  // Runs a previously loaded ECK file (same as calling
  // eckSendMessage(GM_RUN)).
  // Returns what you returns in your script, or -1 in case 
  // of error (no ECK loaded for example).
  int eckRun(WPARAM wParam=0, LPARAM lParam=0);
  // Aborts (stops) a previously loaded and running ECK file 
  // (same as calling eckSendMessage(GM_ABORT)).
  // Returns what you returns in your script, or -1 in case of error.
  int eckAbort(WPARAM wParam=0, LPARAM lParam=0);
  // Sends a message to currently loaded ECK file.
  // Returns what you returns in your script, or -1 in case of error.
  int eckSendMessage(UINT nMsg, WPARAM wParam=0, LPARAM lParam=0);

  // Creates a thread and runs the loaded ECK file from it. 
  bool eckRunThreaded(WPARAM wParam=0, LPARAM lParam=0, 
    int nPriority=THREAD_PRIORITY_NORMAL);
  // Returns true if a thread is running.
  bool eckIsThreadRunning(void);
  // Returns the thread handle of current running script. 
  // Can be NULL if no thread.
  HANDLE GetThreadHandle(void);
  // Aborts running script (sending GM_ABORT), causing thread 
  // to return if the script indeed stops.
  // If the running script doesn't stop within the specified time 
  // (in milli-seconds), either bAllowKill
  // is true and the thread will be terminated with TerminateThread(), 
  // or eckAbortThread() will return.
  // Returns true if the script is aborted and thread is stopped.
  bool eckAbortThread(DWORD dwTimeout=5000, bool bAllowKill=false);
};

Security, Reponsibility etc.

The only problem is: providing a C++ compiler and low-level functions to non-experienced users can be dangerous. If you integrate Gecko and embed MinGW, you must thus engage end-user responsibility and warn him about risks for his computer if he does whatsoever. This is why I put a big disclaimer: I won't be responsible for any damage caused by a mis-usage of the Gecko component, or by a script.

You can however choose not to embed MinGW: you will then be able to run ECK files but not to compile. That eliminates the problem.

Setup

  1. Create a file named gecko.natives.h in your project directory. Declare in it the functions you would like to access from within your scripts, according to the following model:
    GECKO_NATIVE void GECKO_NATIVE_CALL SetPlayerHealth(int nNewHealth);
    GECKO_NATIVE void GECKO_NATIVE_CALL AlertDamage(int nDamage);
    GECKO_NATIVE void GECKO_NATIVE_CALL AppendOutput(LPCSTR szText);
    GECKO_NATIVE int GECKO_NATIVE_CALL foo(int i);
    GECKO_NATIVE const char* GECKO_NATIVE_CALL bar(LPCSTR a, float d);
    ...
    
    Only C-style functions are supported for now. No classes here. Put the functions bodies in any .cpp file of your project, taking care to include MyGecko.h before:
    #include "MyGecko.h"
    
    GECKO_NATIVE void GECKO_NATIVE_CALL SetPlayerHealth(int nNewHealth)
    {
    ...
    }
    
    GECKO_NATIVE void GECKO_NATIVE_CALL AlertDamage(int nDamage)
    {
    ...
    }
    
    ...
  2. Run GeckoSetup.exe. Fill in the fields, click Go! and that's ok.



  3. Add MyGecko.cpp and MyGecko.h to your project (these files have been copied in your project directory). Wherever you need to use the CGecko class, include the file MyGecko.h.

That's all Smile | :)

About MinGW

Necessary Files

  • In the doc directory, keep only the MinGW directory.
  • In the lib directory, delete the gcc-lib sub-directory.

With these efforts you get to only 3.25 MB (zip-compressed).

Licensing Terms

URL - http://www.mingw.org/licensing.shtml:

Basic MinGW runtime MinGW base runtime package is uncopyrighted and placed in the public domain. This basically means that you can do what you want with the code.

w32api You are free to use, modify and copy this package. No restrictions are imposed on programs or object files compiled with this library. You may not restrict the the usage of this library. You may distribute this library as part of another package or as a modified package if and only if you do not restrict the usage of the portions consisting of this (optionally modified) library. If distributed as a modified package then this file must be included.

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.

MinGW profiling code MinGW profiling code is distributed under the GNU General Public License.

The development tools such as GCC, GDB, GNU Make, etc all covered by GNU General Public License.

Here is the relevant part of the GNU General Public License:

"1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program."

"3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,

b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,

c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)"

In a nutshell

If you want to embed the partial MinGW package in a noncommercial product: "Accompany it with the information you received as to the offer to distribute corresponding source code."

You must provide the source for the following packages if you plan to embed the partial MinGW package in a commercial product:

  • gcc-core-3.3.1-20030804-1-src.tar.gz
  • gcc-g++-3.3.1-20030804-1-src.tar.gz
  • binutils-2.14.90-20030807-1-src.tar.gz

These packages can be found at: http://www.mingw.org/download.shtml

History

  • 29 August 2003 : First release.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

PixiGreg
Software Developer
France France
Bouh

Comments and Discussions

 
GeneralGeckoSetup doesn't run PinmemberKehrhahn26-May-04 23:45 
GeneralRe: GeckoSetup doesn't run PinsussPixiGreg18-Feb-05 5:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140926.1 | Last Updated 1 Sep 2003
Article Copyright 2003 by PixiGreg
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid