tags:

views:

388

answers:

1

Hi, After trying many and searching web option to compile and load dll I could not able to create dll for tcl. Can you explain me how to do this.

+4  A: 

Ok, here is a simple example. This code compiles and works for Tcl8.5 and VS2008. To start with I created a WIN32 dll project called BasicTclExtn that exported symbols.

// BasicTclExtn.h
#ifdef BASICTCLEXTN_EXPORTS
#define BASICTCLEXTN_API __declspec(dllexport)
#else
#define BASICTCLEXTN_API __declspec(dllimport)
#endif

int BasicExtnCmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) ;
extern "C" {
    BASICTCLEXTN_API int Basictclextn_Init(Tcl_Interp *interp) ;
}

And then the .cpp file

// BasicTclExtn.cpp : Defines the exported functions for the DLL application.
#include "stdafx.h"
#include "BasicTclExtn.h"

int
BasicExtnCmd(ClientData data,
             Tcl_Interp *interp,
             int objc,
             Tcl_Obj *CONST objv[])
{

    // Check the number of arguments
    if (objc != 3) {
        Tcl_WrongNumArgs(interp, 1, objv, "arg arg");
        return TCL_ERROR;
    }

    long v1, v2, result ;

    if ( Tcl_GetLongFromObj(interp, objv[1], &v1) != TCL_OK)
     return TCL_ERROR ;

    if ( Tcl_GetLongFromObj(interp, objv[2], &v2)  != TCL_OK)
     return TCL_ERROR ;

    result = v1 + v2 ;

    Tcl_SetObjResult(interp, Tcl_NewIntObj(result)) ;
        return TCL_OK ;
}

    // Note the casing on the _Init function name
    BASICTCLEXTN_API int Basictclextn_Init(Tcl_Interp *interp)
    {
     // Link with the stubs library to make the extension as portable as possible
     if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
      return TCL_ERROR;
     }

     // Declare which package and version is provided by this C code
     if ( Tcl_PkgProvide(interp, "BasicTclExtn", "1.0") != TCL_OK ) {
      return TCL_ERROR ;
     }

     // Create a command
     Tcl_CreateObjCommand(interp, "BasicExtnCmd", BasicExtnCmd, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);

     return TCL_OK ;
    }

You need to #include tcl.h in the stdafx.h.

This example uses the Tcl stubs facility, see the documentation on the Tcl_InitStubs function for more information; when using stubs you need to link to only the tclstub85.lib. To get the code to link properly you need to do the following:

  • Add the include directory where tcl.h is installed to Configuration Properties -> C/C++ -> General -> Additional Include Directories
  • Define the USE_TCL_STUBS symbol, I normally do this in Properties-> C/C++ -> Preprocessor -> Preprocessor Definitions. You may also find that you then need to define the <DLLNAME>_EXPORTS (BASICTCLEXTN_EXPORTS in my example) after this, I'm not sure why this happens.
  • Add the path to the directory where the tclstub85.lib file is as an additional library directory in Configuration Properties -> Linker -> General -> Additional Library Directories.
  • Add tclstub85.lib to Configuration Properties -> Linker -> Input -> Additional Dependancies
  • If the compiler spits out a warning about MSVCRT then exclude MSVCRT by adding it to the ignored libraries in Configuration Properties -> Linker -> Input -> Ignore Specific Library.

All of these .lib, .dll and .h files should be easily found in your Tcl installation. You'll also need to ensure that the related tclstub85.dll and tcl85.dll can be found at run time, making sure the bin directory for Tcl is on the PATH should sort that out. So you should then be able to do the following from Tcl:

C:\Projects\BasicTclExtn\Debug>tclsh
% load BasicTclExtn.dll
% BasicExtnCmd 1 2
3
% BasicExtnCmd 1 2.p
expected integer but got "2.p"
% BasicExtnCmd 1 2
3
% BasicExtnCmd 1
wrong # args: should be "BasicExtnCmd arg arg"
% BasicExtnCmd 1 3
4
% exit

This is the simplest form of Tcl exstention, you can add additional calls to Tcl_CreateObjCommand() to add more commnds into this extension. Tcl provides some faciities to help with the processing of the command line paramters passed into the command. The example code used Tcl_WrongNumArgs() but you should also look at the Tcl_GetIndexFromObj() functions.

I would also suggest you get a copy of Practical Programming in Tcl and Tk by Brent Welch. You can read some sample chapter here http://www.beedub.com/book/, the chapter on C programming for Tcl from the 3rd edition will help you a lot.

Jackson
BasicTclExtn.obj : error LNK2019: unresolved external symbol __imp__Tcl_SetObjResult referenced in function "int __cdecl BasicExtnCmd(void *,struct Tcl_Interp *,int,struct Tcl_Obj * const * const)" (?BasicExtnCmd@@YAHPAXPAUTcl_Interp@@HQBQAUTcl_Obj@@@Z)
OliveOne
after trying to compile on VS 2008 and tcl8.5 with all settings of include and lib.
OliveOne
Have you used precompiled header? I used empty project and added seperate stdafx.h in include
OliveOne
It looks like your getting the code to compile but not to link. You need to check that you have specified the correct .lib files and that you have added the directory that the .lib files are in as an Additional Library Directory in the project properties->Linker->General.
Jackson
I had added .lib file in same but then I added those in additional lib in project properties and hurray!!! dll is ready.One more question Do I need to keep same format of function (BasicExtnCmd) if I want to add new function?
OliveOne
Sorry for bothering again. I am strucked at Tcl_Obj *CONST.... Code: double BasicExtnCmd(ClientData data, Tcl_Interp *interp, double objc, Tcl_Obj *CONST objv[]) { // do some thing here on double varriables }
OliveOne
You need to start by reading the chapter on TCL and C here http://www.beedub.com/book/. The thing to remember is that all of the command procdures have exactly the same signature. If you expect doubles as paramters then use `Tcl_GetDoubleFromObj()` and `Tcl_NewDoubleObj` when setting the result. The command procedure always returns an int - usually TCL_OK or TCK_ERROR. If you want more detail then post another question with the code you've got so far.
Jackson
I have read that. Now I am able to have double data type calculations.Thank you very much....
OliveOne