Skip to content

Commit 8a5115c

Browse files
committed
patch 7.4.1070
Problem: The Tcl interface can't be loaded dynamically on Unix. Solution: Make it possible to load it dynamically. (Ken Takata)
1 parent 5f24542 commit 8a5115c

12 files changed

Lines changed: 104 additions & 22 deletions

File tree

runtime/doc/if_tcl.txt

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -515,12 +515,15 @@ startup file (usually "~/.vimrc" on Unix):
515515
==============================================================================
516516
9. Dynamic loading *tcl-dynamic*
517517

518-
On MS-Windows the Tcl library can be loaded dynamically. The |:version|
519-
output then includes |+tcl/dyn|.
518+
On MS-Windows and Unix the Tcl library can be loaded dynamically. The
519+
|:version| output then includes |+tcl/dyn|.
520520

521-
This means that Vim will search for the Tcl DLL file only when needed. When
522-
you don't use the Tcl interface you don't need it, thus you can use Vim
523-
without this DLL file.
521+
This means that Vim will search for the Tcl DLL or shared library file only
522+
when needed. When you don't use the Tcl interface you don't need it, thus you
523+
can use Vim without this file.
524+
525+
526+
MS-Windows ~
524527

525528
To use the Tcl interface the Tcl DLL must be in your search path. In a
526529
console window type "path" to see what directories are used.
@@ -529,5 +532,12 @@ The name of the DLL must match the Tcl version Vim was compiled with.
529532
Currently the name is "tcl86.dll". That is for Tcl 8.6. To know for sure
530533
edit "gvim.exe" and search for "tcl\d*.dll\c".
531534

535+
536+
Unix ~
537+
538+
The 'tcldll' option can be used to specify the Tcl shared library file instead
539+
of DYNAMIC_TCL_DLL file what was specified at compile time. The version of
540+
the shared library must match the Tcl version Vim was compiled with.
541+
532542
==============================================================================
533543
vim:tw=78:ts=8:ft=help:norl:

runtime/doc/options.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7437,6 +7437,17 @@ A jump table for the options with a short description can be found at |Q_op|.
74377437
Resetting this option is useful when using a ":tag" command in a
74387438
mapping which should not change the tagstack.
74397439

7440+
*'tcldll'*
7441+
'tcldll' string (default depends on the build)
7442+
global
7443+
{not in Vi}
7444+
{only available when compiled with the |+tcl/dyn|
7445+
feature}
7446+
Specifies the name of the Tcl shared library. The default is
7447+
DYNAMIC_TCL_DLL, which was specified at compile time.
7448+
This option cannot be set from a |modeline| or in the |sandbox|, for
7449+
security reasons.
7450+
74407451
*'term'* *E529* *E530* *E531*
74417452
'term' string (default is $TERM, if that fails:
74427453
in the GUI: "builtin_gui"

runtime/doc/quickref.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,7 @@ Short explanation of each option: *option-list*
909909
'tagrelative' 'tr' file names in tag file are relative
910910
'tags' 'tag' list of file names used by the tag command
911911
'tagstack' 'tgst' push tags onto the tag stack
912+
'tcldll' name of the Tcl dynamic library
912913
'term' name of the terminal
913914
'termbidi' 'tbidi' terminal takes care of bi-directionality
914915
'termencoding' 'tenc' character encoding used by the terminal

runtime/optwin.vim

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,10 @@ if exists("&rubydll")
13311331
call append("$", "rubydll\tname of the Ruby dynamic library")
13321332
call <SID>OptionG("rubydll", &rubydll)
13331333
endif
1334+
if exists("&tcldll")
1335+
call append("$", "tcldll\tname of the Tcl dynamic library")
1336+
call <SID>OptionG("tcldll", &tcldll)
1337+
endif
13341338

13351339
set cpo&vim
13361340

src/Makefile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,9 @@ CClink = $(CC)
445445

446446
# TCL
447447
# Uncomment this when you want to include the Tcl interface.
448+
# First one is for static linking, second one for dynamic loading.
448449
#CONF_OPT_TCL = --enable-tclinterp
450+
#CONF_OPT_TCL = --enable-tclinterp=dynamic
449451
#CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4
450452

451453
# CSCOPE
@@ -1375,15 +1377,15 @@ SHELL = /bin/sh
13751377
.SUFFIXES: .c .o .pro
13761378

13771379
PRE_DEFS = -Iproto $(DEFS) $(GUI_DEFS) $(GUI_IPATH) $(CPPFLAGS) $(EXTRA_IPATHS)
1378-
POST_DEFS = $(X_CFLAGS) $(MZSCHEME_CFLAGS) $(TCL_CFLAGS) $(EXTRA_DEFS)
1380+
POST_DEFS = $(X_CFLAGS) $(MZSCHEME_CFLAGS) $(EXTRA_DEFS)
13791381

13801382
ALL_CFLAGS = $(PRE_DEFS) $(CFLAGS) $(PROFILE_CFLAGS) $(SANITIZER_CFLAGS) $(LEAK_CFLAGS) $(POST_DEFS)
13811383

13821384
# Exclude $CFLAGS for osdef.sh, for Mac 10.4 some flags don't work together
13831385
# with "-E".
13841386
OSDEF_CFLAGS = $(PRE_DEFS) $(POST_DEFS)
13851387

1386-
LINT_CFLAGS = -DLINT -I. $(PRE_DEFS) $(POST_DEFS) $(RUBY_CFLAGS) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) -Dinline= -D__extension__= -Dalloca=alloca
1388+
LINT_CFLAGS = -DLINT -I. $(PRE_DEFS) $(POST_DEFS) $(RUBY_CFLAGS) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) $(TCL_CFLAGS) -Dinline= -D__extension__= -Dalloca=alloca
13871389

13881390
LINT_EXTRA = -DUSE_SNIFF -DHANGUL_INPUT -D"__attribute__(x)="
13891391

@@ -2756,7 +2758,7 @@ objects/if_sniff.o: if_sniff.c
27562758
$(CCC) -o $@ if_sniff.c
27572759

27582760
objects/if_tcl.o: if_tcl.c
2759-
$(CCC) -o $@ if_tcl.c
2761+
$(CCC) $(TCL_CFLAGS) -o $@ if_tcl.c
27602762

27612763
objects/integration.o: integration.c
27622764
$(CCC) -o $@ integration.c
@@ -2801,7 +2803,7 @@ objects/ops.o: ops.c
28012803
$(CCC) -o $@ ops.c
28022804

28032805
objects/option.o: option.c
2804-
$(CCC) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) $(RUBY_CFLAGS) -o $@ option.c
2806+
$(CCC) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) $(RUBY_CFLAGS) $(TCL_CFLAGS) -o $@ option.c
28052807

28062808
objects/os_beos.o: os_beos.c
28072809
$(CCC) -o $@ os_beos.c

src/auto/configure

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,7 +1468,7 @@ Optional Features:
14681468
--enable-perlinterp=OPTS Include Perl interpreter. default=no OPTS=no/yes/dynamic
14691469
--enable-pythoninterp=OPTS Include Python interpreter. default=no OPTS=no/yes/dynamic
14701470
--enable-python3interp=OPTS Include Python3 interpreter. default=no OPTS=no/yes/dynamic
1471-
--enable-tclinterp Include Tcl interpreter.
1471+
--enable-tclinterp=OPTS Include Tcl interpreter. default=no OPTS=no/yes/dynamic
14721472
--enable-rubyinterp=OPTS Include Ruby interpreter. default=no OPTS=no/yes/dynamic
14731473
--enable-cscope Include cscope interface.
14741474
--enable-workshop Include Sun Visual Workshop support.
@@ -6616,7 +6616,7 @@ fi
66166616
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tclinterp" >&5
66176617
$as_echo "$enable_tclinterp" >&6; }
66186618

6619-
if test "$enable_tclinterp" = "yes"; then
6619+
if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then
66206620

66216621
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-tclsh argument" >&5
66226622
$as_echo_n "checking --with-tclsh argument... " >&6; }
@@ -6852,6 +6852,7 @@ $as_echo_n "checking Tcl version... " >&6; }
68526852
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $tclver - OK" >&5
68536853
$as_echo "$tclver - OK" >&6; };
68546854
tclloc=`echo 'set l [info library];set i [string last lib $l];incr i -2;puts [string range $l 0 $i]' | $vi_cv_path_tcl -`
6855+
tcldll=`echo 'puts libtcl[info tclversion][info sharedlibextension]' | $vi_cv_path_tcl -`
68556856

68566857
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of Tcl include" >&5
68576858
$as_echo_n "checking for location of Tcl include... " >&6; }
@@ -6888,7 +6889,11 @@ $as_echo_n "checking for location of tclConfig.sh script... " >&6; }
68886889
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $try/tclConfig.sh" >&5
68896890
$as_echo "$try/tclConfig.sh" >&6; }
68906891
. "$try/tclConfig.sh"
6891-
TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
6892+
if test "$enable_tclinterp" = "dynamic"; then
6893+
TCL_LIBS=`eval echo "$TCL_STUB_LIB_SPEC $TCL_LIBS"`
6894+
else
6895+
TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
6896+
fi
68926897
TCL_DEFS=`echo $TCL_DEFS | sed -e 's/\\\\ /\\\\X/g' | tr ' ' '\012' | sed -e '/^[^-]/d' -e '/^-[^D]/d' -e '/-D[^_]/d' -e 's/-D_/ -D_/' | tr '\012' ' ' | sed -e 's/\\\\X/\\\\ /g'`
68936898
break
68946899
fi
@@ -6937,6 +6942,13 @@ $as_echo "<not found>" >&6; }
69376942
$as_echo "too old; need Tcl version 8.0 or later" >&6; }
69386943
fi
69396944
fi
6945+
if test "$enable_tclinterp" = "dynamic"; then
6946+
if test "X$TCL_SRC" != "X" -a "X$tcldll" != "X"; then
6947+
$as_echo "#define DYNAMIC_TCL 1" >>confdefs.h
6948+
6949+
TCL_CFLAGS="-DDYNAMIC_TCL_DLL=\\\"$tcldll\\\" -DDYNAMIC_TCL_VER=\\\"$tclver\\\" $TCL_CFLAGS"
6950+
fi
6951+
fi
69406952
if test "$fail_if_missing" = "yes" -a -z "$TCL_SRC"; then
69416953
as_fn_error $? "could not configure Tcl" "$LINENO" 5
69426954
fi

src/config.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,9 @@
360360
/* Define if you want to include the Tcl interpreter. */
361361
#undef FEAT_TCL
362362

363+
/* Define for linking via dlopen() or LoadLibrary() */
364+
#undef DYNAMIC_TCL
365+
363366
/* Define if you want to include the Sniff interface. */
364367
#undef FEAT_SNIFF
365368

src/configure.in

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,11 +1622,11 @@ fi
16221622

16231623
AC_MSG_CHECKING(--enable-tclinterp argument)
16241624
AC_ARG_ENABLE(tclinterp,
1625-
[ --enable-tclinterp Include Tcl interpreter.], ,
1625+
[ --enable-tclinterp[=OPTS] Include Tcl interpreter. [default=no] [OPTS=no/yes/dynamic]], ,
16261626
[enable_tclinterp="no"])
16271627
AC_MSG_RESULT($enable_tclinterp)
16281628

1629-
if test "$enable_tclinterp" = "yes"; then
1629+
if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then
16301630

16311631
dnl on FreeBSD tclsh is a silly script, look for tclsh8.[5420]
16321632
AC_MSG_CHECKING(--with-tclsh argument)
@@ -1660,6 +1660,7 @@ if test "$enable_tclinterp" = "yes"; then
16601660
tclver=`echo 'puts [[info tclversion]]' | $vi_cv_path_tcl -`
16611661
AC_MSG_RESULT($tclver - OK);
16621662
tclloc=`echo 'set l [[info library]];set i [[string last lib $l]];incr i -2;puts [[string range $l 0 $i]]' | $vi_cv_path_tcl -`
1663+
tcldll=`echo 'puts libtcl[[info tclversion]][[info sharedlibextension]]' | $vi_cv_path_tcl -`
16631664

16641665
AC_MSG_CHECKING(for location of Tcl include)
16651666
if test "x$MACOSX" != "xyes"; then
@@ -1694,7 +1695,11 @@ if test "$enable_tclinterp" = "yes"; then
16941695
AC_MSG_RESULT($try/tclConfig.sh)
16951696
. "$try/tclConfig.sh"
16961697
dnl use eval, because tcl 8.2 includes ${TCL_DBGX}
1697-
TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
1698+
if test "$enable_tclinterp" = "dynamic"; then
1699+
TCL_LIBS=`eval echo "$TCL_STUB_LIB_SPEC $TCL_LIBS"`
1700+
else
1701+
TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
1702+
fi
16981703
dnl Use $TCL_DEFS for -D_THREAD_SAFE et al. But only use the
16991704
dnl "-D_ABC" items. Watch out for -DFOO=long\ long.
17001705
TCL_DEFS=`echo $TCL_DEFS | sed -e 's/\\\\ /\\\\X/g' | tr ' ' '\012' | sed -e '/^[[^-]]/d' -e '/^-[[^D]]/d' -e '/-D[[^_]]/d' -e 's/-D_/ -D_/' | tr '\012' ' ' | sed -e 's/\\\\X/\\\\ /g'`
@@ -1739,6 +1744,12 @@ if test "$enable_tclinterp" = "yes"; then
17391744
AC_MSG_RESULT(too old; need Tcl version 8.0 or later)
17401745
fi
17411746
fi
1747+
if test "$enable_tclinterp" = "dynamic"; then
1748+
if test "X$TCL_SRC" != "X" -a "X$tcldll" != "X"; then
1749+
AC_DEFINE(DYNAMIC_TCL)
1750+
TCL_CFLAGS="-DDYNAMIC_TCL_DLL=\\\"$tcldll\\\" -DDYNAMIC_TCL_VER=\\\"$tclver\\\" $TCL_CFLAGS"
1751+
fi
1752+
fi
17421753
if test "$fail_if_missing" = "yes" -a -z "$TCL_SRC"; then
17431754
AC_MSG_ERROR([could not configure Tcl])
17441755
fi

src/if_tcl.c

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,20 @@ static struct ref refsdeleted; /* dummy object for deleted ref list */
160160
typedef int HANDLE;
161161
# endif
162162

163+
# ifndef WIN3264
164+
# include <dlfcn.h>
165+
# define HANDLE void*
166+
# define TCL_PROC void*
167+
# define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
168+
# define symbol_from_dll dlsym
169+
# define close_dll dlclose
170+
# else
171+
# define TCL_PROC FARPROC
172+
# define load_dll vimLoadLib
173+
# define symbol_from_dll GetProcAddress
174+
# define close_dll FreeLibrary
175+
# endif
176+
163177
/*
164178
* Declare HANDLE for tcl.dll and function pointers.
165179
*/
@@ -170,7 +184,6 @@ void (*dll_Tcl_FindExecutable)(const void *);
170184
/*
171185
* Table of name to function pointer of tcl.
172186
*/
173-
#define TCL_PROC FARPROC
174187
static struct {
175188
char* name;
176189
TCL_PROC* ptr;
@@ -197,18 +210,18 @@ tcl_runtime_link_init(char *libname, int verbose)
197210

198211
if (hTclLib)
199212
return OK;
200-
if (!(hTclLib = vimLoadLib(libname)))
213+
if (!(hTclLib = load_dll(libname)))
201214
{
202215
if (verbose)
203216
EMSG2(_(e_loadlib), libname);
204217
return FAIL;
205218
}
206219
for (i = 0; tcl_funcname_table[i].ptr; ++i)
207220
{
208-
if (!(*tcl_funcname_table[i].ptr = GetProcAddress(hTclLib,
221+
if (!(*tcl_funcname_table[i].ptr = symbol_from_dll(hTclLib,
209222
tcl_funcname_table[i].name)))
210223
{
211-
FreeLibrary(hTclLib);
224+
close_dll(hTclLib);
212225
hTclLib = NULL;
213226
if (verbose)
214227
EMSG2(_(e_loadfunc), tcl_funcname_table[i].name);
@@ -246,13 +259,13 @@ tcl_enabled(verbose)
246259
int verbose;
247260
{
248261
if (!stubs_initialized && find_executable_arg != NULL
249-
&& tcl_runtime_link_init(DYNAMIC_TCL_DLL, verbose) == OK)
262+
&& tcl_runtime_link_init((char *)p_tcldll, verbose) == OK)
250263
{
251264
Tcl_Interp *interp;
252265

253266
dll_Tcl_FindExecutable(find_executable_arg);
254267

255-
if (interp = dll_Tcl_CreateInterp())
268+
if ((interp = dll_Tcl_CreateInterp()) != NULL)
256269
{
257270
if (Tcl_InitStubs(interp, DYNAMIC_TCL_VER, 0))
258271
{
@@ -272,7 +285,7 @@ tcl_end()
272285
#ifdef DYNAMIC_TCL
273286
if (hTclLib)
274287
{
275-
FreeLibrary(hTclLib);
288+
close_dll(hTclLib);
276289
hTclLib = NULL;
277290
}
278291
#endif
@@ -2039,6 +2052,10 @@ tcldelallrefs(ref)
20392052
int err;
20402053
char *result;
20412054

2055+
/* TODO: this code currently crashes Vim on exit */
2056+
if (exiting)
2057+
return;
2058+
20422059
while (ref != NULL)
20432060
{
20442061
next = ref->next;

src/option.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2609,6 +2609,12 @@ static struct vimoption
26092609
{"tagstack", "tgst", P_BOOL|P_VI_DEF,
26102610
(char_u *)&p_tgst, PV_NONE,
26112611
{(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
2612+
#if defined(DYNAMIC_TCL)
2613+
{"tcldll", NULL, P_STRING|P_VI_DEF|P_SECURE,
2614+
(char_u *)&p_tcldll, PV_NONE,
2615+
{(char_u *)DYNAMIC_TCL_DLL, (char_u *)0L}
2616+
SCRIPTID_INIT},
2617+
#endif
26122618
{"term", NULL, P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RALL,
26132619
(char_u *)&T_NAME, PV_NONE,
26142620
{(char_u *)"", (char_u *)0L} SCRIPTID_INIT},

0 commit comments

Comments
 (0)