3

Tcl インタープリターを作成し、tcl と tk を初期化し、指定された tcl/tk スクリプトをロードする単純な C プログラムが必要です。tcl および tk スタブを使用したい (異なるバージョンの tcl/tk がインストールされたコンピューターでプログラムが確実に実行されるようにするため)。Wish を実行する代わりに、このプログラムを使用します (移植性の問題があるため)。

#include <stdio.h>
#include <stdlib.h>
#include <tcl.h>
#include <tk.h>

int AppInit(Tcl_Interp *interp) {
  if(Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR;
  if(Tk_Init(interp) == TCL_ERROR) return TCL_ERROR;
  Tcl_EvalFile(interp,"myscript.tcl");
  return TCL_OK;
}

int main(int argc, char *argv[]) {
  Tk_Main(argc, argv, AppInit);
  return 0;
}

次のコマンドで(GNU/Linux上で)コンパイルしようとしました。プログラムはエラーなしでコンパイルされますが、セグメンテーション違反で停止します。

gcc -I/usr/include/tcl8.5 -DUSE_TCL_STUBS -DUSE_TK_STUBS -o main.exe ../main.c /usr/lib/libtclstub.a /usr/lib/libtkstub.a
4

1 に答える 1

3

tl;dr

を使用してプログラムをコンパイルするときは、スタブを使用しないmainでください。代わりに、 and を定義せずにビルドし、 and に対してリンクします(どのようなバージョン番号が付けられていても)。Unix リンカの特殊性のため、Tk ライブラリを Tcl ライブラリの前に配置する必要があります (また、X ライブラリなどの他のライブラリに対しても手動でリンクする必要がある場合があります。リンクは、少し黒魔術のようなものである場合があります)。USE_TCL_STUBSUSE_TK_STUBSlibtcl.solibtk.so

背景説明

スタブ メカニズムは、Tcl ライブラリ自体にリンクすることなく、Tcl 拡張ライブラリが Tcl (および Tk) の C API を使用できるようにすることを目的としています。これは、ライブラリが、それをロードするプロセスに存在する Tcl の正確なバージョンに依存せず、代わりに Tcl API の特定のバージョンに依存することを意味します (Tcl は、長期的な API と ABI の互換性を管理するのに非常に優れています)。ただし、これはすべて、他のすべての API 関数を検索できる非常に特殊な種類のポインターを使用して呼び出されるライブラリー初期化関数に依存します。(Tcl がこのようにブートストラップされると、他のすべての API を見つけるのがはるかに簡単になります。) あなたが行っているようなアプリケーションを作成するとき、コードがリンクする既存のブートストラップされた Tcl ライブラリ インスタンスがないという問題に遭遇します。 ;Tcl_Mainこの正確な理由から、スタブ化されてTk_Mainいない関数です)。

自宅でこの記事を読んでいる人は、これは Tcl がシステムのダイナミック リンカが行うことの多くを繰り返していると考えるかもしれません。あなたは正しいでしょう。ただし、システムの動的リンカーには、正しく機能しないことを行う方法がいくつかあり (たとえば、複数のバージョンのライブラリがあると非常に混乱する可能性があります)、プラットフォーム間で機能が微妙に異なります。Tcl は独自のメカニズムを使用しているため、どこでも (Tcl に対して) 正確に機能し、長期的な ABI 互換性をより適切に制御できます。

スタブに関する上記の規則には例外があり、それはtclkit です。これは、単一のファイル内の完全な Tcl および Tk ランタイム (および小さな NoSQL DB) です。ただし、tclkit のブートストラップ コードは非常に複雑です。そのようなことに対処する必要はありません。単一ファイルの Tcl ランタイムが必要な場合は、tclkit (またはほとんど同等のことを行う数少ない他のシステムの 1 つ) を使用します。

于 2012-06-15T08:51:32.467 に答える