В настоящее время я использую ctypes в Python 3 для создания приложения Tcl, которое оборачивает библиотеку, написанную на Python.
from ctypes import *
import sys
tcl = cdll.LoadLibrary("libtcl.so")
TCL_OK = 0
TCL_ERROR = 1
def say_hello(cdata: c_void_p, interp: c_void_p, argc: c_int, argv: POINTER(c_char_p)) -> int:
"This function wraps some functionality that is written in Python"
print("hello, world")
return TCL_OK
# useful type definitions
Tcl_AppInitProc = CFUNCTYPE(c_int, c_void_p)
Tcl_CmdProc = CFUNCTYPE(c_int, c_void_p, c_void_p, c_int, POINTER(c_char_p))
Tcl_CmdDeleteProc = CFUNCTYPE(None, c_int)
def app_init(interp: c_void_p) -> int:
# initialize the interpreter
tcl.Tcl_Init.restype = c_int
tcl.Tcl_Init.argtypes = [c_void_p]
if tcl.Tcl_Init(interp) == TCL_ERROR:
return TCL_ERROR
# create custom commands
tcl.Tcl_CreateCommand.restype = c_void_p
tcl.Tcl_CreateCommand.argtypes = [c_void_p, c_char_p, Tcl_CmdProc, c_int, Tcl_CmdDeleteProc]
tcl.Tcl_CreateCommand(interp, b"say_hello", Tcl_CmdProc(say_hello), 0, Tcl_CmdDeleteProc(0))
return TCL_OK
if __name__ == "__main__":
# initialize argv
Argv = c_char_p * (1 + len(sys.argv))
argv = Argv(*(bytes(arg, "utf-8") for arg in sys.argv), 0)
# summon the chief interpreter
tcl.Tcl_Main.argtypes = [c_int, POINTER(c_char_p), Tcl_AppInitProc]
tcl.Tcl_Main(len(sys.argv), argv, Tcl_AppInitProc(app_init))
Из командной строки это работает как интерпретатор Tcl с дополнительными командами, которыйименно то, что я хочу. Он анализирует sys.argv
и работает как интерактивная оболочка и для запуска сценариев Tcl.
bash$ python3 hello.py
% say_hello
hello, world
% ls
foo.tcl hello.py
% exit
bash$ cat foo.tcl
say_hello
bash$ python3 hello.py foo.tcl
hello, world
bash$
Однако я знаю, что Python поставляется с интерпретатором Tcl уже в модуле tkinter. Вместо этого я бы хотел использовать это, потому что у него уже есть хороший API-интерфейс, заключенный в Python, и он мог бы сэкономить немного времени на ctypes.
Я могу достаточно легко создать интерпретатор и добавить команды.
from tkinter import *
def say_hello():
print("hello, world")
if __name__ == "__main__":
tcl = Tcl()
tcl.createcommand("say_hello", say_hello)
tcl.eval("say_hello")
Но я не могу найти способ позвонить Tcl_Init
или Tcl_Main
, и без них я не могу запустить его в интерактивном режиме. Хотя меня не волнует анализатор командной строки, было бы много работы, чтобы попытаться воспроизвести интерактивную оболочку Tcl в Python со всеми ее функциями, такими как запуск внешних программ, как если бы они были командами Tcl (такими как ls
в приведенном выше примере). Если это мой единственный вариант, я просто буду использовать ctypes.
Есть ли способ, даже хакерский или неподдерживаемый, запустить интерпретатор Tcl, который поставляется с Tkinter в качестве интерактивной оболочки?