2009-09-08 56 views
4

在嘗試了很多並搜索web選項來編譯和加載dll後,我無法爲tcl創建dll。你能解釋我如何做到這一點。如何在tcl中編譯dll加載

+0

嘗試從http://wiki.tcl.tk/2419獲得代碼併成功但無法添加自己的函數(例如,HelloObjCmdProc) – OliveOne 2009-09-08 07:49:31

+0

我們可以看到您到目前爲止的代碼以及您收到的錯誤嗎?代碼是否編譯但無法加載到TCL中?您使用哪種編譯器來構建dll? – Jackson 2009-09-08 08:24:38

回答

8

好的,下面是一個簡單的例子。此代碼編譯並適用於Tcl8.5和VS2008。首先我創建了一個叫做BasicTclExtn的WIN32 dll項目,它導出了符號。

// 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) ; 
} 

然後.cpp文件

// 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 ; 
    } 

你需要在stdafx.h中#包括tcl.h。

本示例使用Tcl存根設備,有關更多信息,請參閱Tcl_InitStubs函數的文檔;當使用存根時,只需鏈接到tclstub85.lib。爲了讓代碼正確鏈接,你需要做到以下幾點:

  • 添加包括其中tcl.h安裝到配置屬性目錄 - > C/C++ - >常規 - >附加包含目錄
  • 定義USE_TCL_STUBS符號,我通常在屬性 - > C/C++ - >預處理器 - >預處理器定義中執行此操作。在此之後,您可能還會發現需要定義<DLLNAME>_EXPORTSBASICTCLEXTN_EXPORTS),我不確定爲什麼會發生這種情況。
  • 將tclstub85.lib文件的路徑添加到Configuration Properties - > Linker - > General - > Additional Library Directories中作爲附加庫目錄。
  • 添加tclstub85.lib配置屬性 - >鏈接器 - >輸入 - >附加依賴關係
  • 如果編譯器吐出警告有關MSVCRT然後將其添加到配置屬性被忽略的圖書館排除MSVCRT - >鏈接 - >輸入 - >忽略特定庫。

所有這些.lib,.dll和.h文件應該很容易在您的Tcl安裝中找到。您還需要確保在運行時可以找到相關的tclstub85.dll和tcl85.dll,確保Tcl的bin目錄在PATH上應該排除。所以,你應該然後能夠從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 

這是Tcl的exstention的最簡單的形式,你可以到Tcl_CreateObjCommand()添加額外調用更多commnds加入到這個擴展。 Tcl提供了一些輔助功能來幫助處理傳入命令的命令行參數。示例代碼使用Tcl_WrongNumArgs(),但您也應該查看Tcl_GetIndexFromObj()函數。

我也建議你在Tcl和Tk中通過Brent Welch獲得實用編程的副本。你可以在這裏閱讀一些示例章節http://www.beedub.com/book/,從第3版開始的關於Tcl C編程的章節將對你有所幫助。

+0

BasicTclExtn.obj:錯誤LNK2019:無法解析的外部符號__imp__Tcl_SetObjResult在函數中引用「int __cdecl BasicExtnCmd(void *,struct Tcl_Interp *,int,struct Tcl_Obj * const * const)」(?BasicExtnCmd @@ YAHPAXPAUTcl_Interp @@ HQBQAUTcl_Obj @@@ Z) – OliveOne 2009-09-08 17:08:15

+0

嘗試在VS 2008和tcl8.5上進行編譯,包含include和lib的所有設置。 – OliveOne 2009-09-08 17:09:10

+0

你使用過預編譯頭文件嗎?我使用了空項目並在include中添加了單獨的stdafx.h – OliveOne 2009-09-08 17:10:46