changeset 7538:c9fc24b76293 v7.4.1070

commit https://github.com/vim/vim/commit/8a5115cf18751022387af2085f374d38c60dde83 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jan 9 19:41:11 2016 +0100 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)
author Christian Brabandt <cb@256bit.org>
date Sat, 09 Jan 2016 19:45:05 +0100
parents e1a5a830aebb
children f5d3b2c6f971
files runtime/doc/if_tcl.txt runtime/doc/options.txt runtime/doc/quickref.txt runtime/optwin.vim src/Makefile src/auto/configure src/config.h.in src/configure.in src/if_tcl.c src/option.c src/option.h src/version.c
diffstat 12 files changed, 104 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/if_tcl.txt
+++ b/runtime/doc/if_tcl.txt
@@ -515,12 +515,15 @@ startup file (usually "~/.vimrc" on Unix
 ==============================================================================
 9. Dynamic loading					*tcl-dynamic*
 
-On MS-Windows the Tcl library can be loaded dynamically.  The |:version|
-output then includes |+tcl/dyn|.
+On MS-Windows and Unix the Tcl library can be loaded dynamically.  The
+|:version| output then includes |+tcl/dyn|.
 
-This means that Vim will search for the Tcl DLL file only when needed.  When
-you don't use the Tcl interface you don't need it, thus you can use Vim
-without this DLL file.
+This means that Vim will search for the Tcl DLL or shared library file only
+when needed.  When you don't use the Tcl interface you don't need it, thus you
+can use Vim without this file.
+
+
+MS-Windows ~
 
 To use the Tcl interface the Tcl DLL must be in your search path.  In a
 console window type "path" to see what directories are used.
@@ -529,5 +532,12 @@ The name of the DLL must match the Tcl v
 Currently the name is "tcl86.dll".  That is for Tcl 8.6.  To know for sure
 edit "gvim.exe" and search for "tcl\d*.dll\c".
 
+
+Unix ~
+
+The 'tcldll' option can be used to specify the Tcl shared library file instead
+of DYNAMIC_TCL_DLL file what was specified at compile time.  The version of
+the shared library must match the Tcl version Vim was compiled with.
+
 ==============================================================================
  vim:tw=78:ts=8:ft=help:norl:
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -7437,6 +7437,17 @@ A jump table for the options with a shor
 	Resetting this option is useful when using a ":tag" command in a
 	mapping which should not change the tagstack.
 
+						*'tcldll'*
+'tcldll' 		string	(default depends on the build)
+			global
+			{not in Vi}
+			{only available when compiled with the |+tcl/dyn|
+			feature}
+	Specifies the name of the Tcl shared library. The default is
+	DYNAMIC_TCL_DLL, which was specified at compile time.
+	This option cannot be set from a |modeline| or in the |sandbox|, for
+	security reasons.
+
 						*'term'* *E529* *E530* *E531*
 'term'			string	(default is $TERM, if that fails:
 				      in the GUI: "builtin_gui"
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -909,6 +909,7 @@ Short explanation of each option:		*opti
 'tagrelative'	  'tr'	    file names in tag file are relative
 'tags'		  'tag'     list of file names used by the tag command
 'tagstack'	  'tgst'    push tags onto the tag stack
+'tcldll'		    name of the Tcl dynamic library
 'term'			    name of the terminal
 'termbidi'	  'tbidi'   terminal takes care of bi-directionality
 'termencoding'	  'tenc'    character encoding used by the terminal
--- a/runtime/optwin.vim
+++ b/runtime/optwin.vim
@@ -1331,6 +1331,10 @@ if exists("&rubydll")
   call append("$", "rubydll\tname of the Ruby dynamic library")
   call <SID>OptionG("rubydll", &rubydll)
 endif
+if exists("&tcldll")
+  call append("$", "tcldll\tname of the Tcl dynamic library")
+  call <SID>OptionG("tcldll", &tcldll)
+endif
 
 set cpo&vim
 
--- a/src/Makefile
+++ b/src/Makefile
@@ -445,7 +445,9 @@ CClink = $(CC)
 
 # TCL
 # Uncomment this when you want to include the Tcl interface.
+# First one is for static linking, second one for dynamic loading.
 #CONF_OPT_TCL = --enable-tclinterp
+#CONF_OPT_TCL = --enable-tclinterp=dynamic
 #CONF_OPT_TCL = --enable-tclinterp --with-tclsh=tclsh8.4
 
 # CSCOPE
@@ -1375,7 +1377,7 @@ SHELL = /bin/sh
 .SUFFIXES: .c .o .pro
 
 PRE_DEFS = -Iproto $(DEFS) $(GUI_DEFS) $(GUI_IPATH) $(CPPFLAGS) $(EXTRA_IPATHS)
-POST_DEFS = $(X_CFLAGS) $(MZSCHEME_CFLAGS) $(TCL_CFLAGS) $(EXTRA_DEFS)
+POST_DEFS = $(X_CFLAGS) $(MZSCHEME_CFLAGS) $(EXTRA_DEFS)
 
 ALL_CFLAGS = $(PRE_DEFS) $(CFLAGS) $(PROFILE_CFLAGS) $(SANITIZER_CFLAGS) $(LEAK_CFLAGS) $(POST_DEFS)
 
@@ -1383,7 +1385,7 @@ ALL_CFLAGS = $(PRE_DEFS) $(CFLAGS) $(PRO
 # with "-E".
 OSDEF_CFLAGS = $(PRE_DEFS) $(POST_DEFS)
 
-LINT_CFLAGS = -DLINT -I. $(PRE_DEFS) $(POST_DEFS) $(RUBY_CFLAGS) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) -Dinline= -D__extension__= -Dalloca=alloca
+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
 
 LINT_EXTRA = -DUSE_SNIFF -DHANGUL_INPUT -D"__attribute__(x)="
 
@@ -2756,7 +2758,7 @@ objects/if_sniff.o: if_sniff.c
 	$(CCC) -o $@ if_sniff.c
 
 objects/if_tcl.o: if_tcl.c
-	$(CCC) -o $@ if_tcl.c
+	$(CCC) $(TCL_CFLAGS) -o $@ if_tcl.c
 
 objects/integration.o: integration.c
 	$(CCC) -o $@ integration.c
@@ -2801,7 +2803,7 @@ objects/ops.o: ops.c
 	$(CCC) -o $@ ops.c
 
 objects/option.o: option.c
-	$(CCC) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) $(RUBY_CFLAGS) -o $@ option.c
+	$(CCC) $(LUA_CFLAGS) $(PERL_CFLAGS) $(PYTHON_CFLAGS) $(PYTHON3_CFLAGS) $(RUBY_CFLAGS) $(TCL_CFLAGS) -o $@ option.c
 
 objects/os_beos.o: os_beos.c
 	$(CCC) -o $@ os_beos.c
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -1468,7 +1468,7 @@ Optional Features:
   --enable-perlinterp=OPTS     Include Perl interpreter.  default=no OPTS=no/yes/dynamic
   --enable-pythoninterp=OPTS   Include Python interpreter. default=no OPTS=no/yes/dynamic
   --enable-python3interp=OPTS   Include Python3 interpreter. default=no OPTS=no/yes/dynamic
-  --enable-tclinterp      Include Tcl interpreter.
+  --enable-tclinterp=OPTS      Include Tcl interpreter. default=no OPTS=no/yes/dynamic
   --enable-rubyinterp=OPTS     Include Ruby interpreter.  default=no OPTS=no/yes/dynamic
   --enable-cscope         Include cscope interface.
   --enable-workshop       Include Sun Visual Workshop support.
@@ -6616,7 +6616,7 @@ fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tclinterp" >&5
 $as_echo "$enable_tclinterp" >&6; }
 
-if test "$enable_tclinterp" = "yes"; then
+if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then
 
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking --with-tclsh argument" >&5
 $as_echo_n "checking --with-tclsh argument... " >&6; }
@@ -6852,6 +6852,7 @@ fi
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tclver - OK" >&5
 $as_echo "$tclver - OK" >&6; };
       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 -`
+      tcldll=`echo 'puts libtcl[info tclversion][info sharedlibextension]' | $vi_cv_path_tcl -`
 
       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for location of Tcl include" >&5
 $as_echo_n "checking for location of Tcl include... " >&6; }
@@ -6888,7 +6889,11 @@ fi
 	    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $try/tclConfig.sh" >&5
 $as_echo "$try/tclConfig.sh" >&6; }
 	    . "$try/tclConfig.sh"
-	    	    TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
+	    	    if test "$enable_tclinterp" = "dynamic"; then
+	      TCL_LIBS=`eval echo "$TCL_STUB_LIB_SPEC $TCL_LIBS"`
+	    else
+	      TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
+	    fi
 	    	    	    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'`
 	    break
 	  fi
@@ -6937,6 +6942,13 @@ fi
 $as_echo "too old; need Tcl version 8.0 or later" >&6; }
     fi
   fi
+  if test "$enable_tclinterp" = "dynamic"; then
+    if test "X$TCL_SRC" != "X" -a "X$tcldll" != "X"; then
+      $as_echo "#define DYNAMIC_TCL 1" >>confdefs.h
+
+      TCL_CFLAGS="-DDYNAMIC_TCL_DLL=\\\"$tcldll\\\" -DDYNAMIC_TCL_VER=\\\"$tclver\\\" $TCL_CFLAGS"
+    fi
+  fi
   if test "$fail_if_missing" = "yes" -a -z "$TCL_SRC"; then
     as_fn_error $? "could not configure Tcl" "$LINENO" 5
   fi
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -360,6 +360,9 @@
 /* Define if you want to include the Tcl interpreter. */
 #undef FEAT_TCL
 
+/* Define for linking via dlopen() or LoadLibrary() */
+#undef DYNAMIC_TCL
+
 /* Define if you want to include the Sniff interface. */
 #undef FEAT_SNIFF
 
--- a/src/configure.in
+++ b/src/configure.in
@@ -1622,11 +1622,11 @@ fi
 
 AC_MSG_CHECKING(--enable-tclinterp argument)
 AC_ARG_ENABLE(tclinterp,
-	[  --enable-tclinterp      Include Tcl interpreter.], ,
+	[  --enable-tclinterp[=OPTS]      Include Tcl interpreter. [default=no] [OPTS=no/yes/dynamic]], ,
 	[enable_tclinterp="no"])
 AC_MSG_RESULT($enable_tclinterp)
 
-if test "$enable_tclinterp" = "yes"; then
+if test "$enable_tclinterp" = "yes" -o "$enable_tclinterp" = "dynamic"; then
 
   dnl on FreeBSD tclsh is a silly script, look for tclsh8.[5420]
   AC_MSG_CHECKING(--with-tclsh argument)
@@ -1660,6 +1660,7 @@ if test "$enable_tclinterp" = "yes"; the
       tclver=`echo 'puts [[info tclversion]]' | $vi_cv_path_tcl -`
       AC_MSG_RESULT($tclver - OK);
       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 -`
+      tcldll=`echo 'puts libtcl[[info tclversion]][[info sharedlibextension]]' | $vi_cv_path_tcl -`
 
       AC_MSG_CHECKING(for location of Tcl include)
       if test "x$MACOSX" != "xyes"; then
@@ -1694,7 +1695,11 @@ if test "$enable_tclinterp" = "yes"; the
 	    AC_MSG_RESULT($try/tclConfig.sh)
 	    . "$try/tclConfig.sh"
 	    dnl use eval, because tcl 8.2 includes ${TCL_DBGX}
-	    TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
+	    if test "$enable_tclinterp" = "dynamic"; then
+	      TCL_LIBS=`eval echo "$TCL_STUB_LIB_SPEC $TCL_LIBS"`
+	    else
+	      TCL_LIBS=`eval echo "$TCL_LIB_SPEC $TCL_LIBS"`
+	    fi
 	    dnl Use $TCL_DEFS for -D_THREAD_SAFE et al.  But only use the
 	    dnl "-D_ABC" items.  Watch out for -DFOO=long\ long.
 	    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"; the
       AC_MSG_RESULT(too old; need Tcl version 8.0 or later)
     fi
   fi
+  if test "$enable_tclinterp" = "dynamic"; then
+    if test "X$TCL_SRC" != "X" -a "X$tcldll" != "X"; then
+      AC_DEFINE(DYNAMIC_TCL)
+      TCL_CFLAGS="-DDYNAMIC_TCL_DLL=\\\"$tcldll\\\" -DDYNAMIC_TCL_VER=\\\"$tclver\\\" $TCL_CFLAGS"
+    fi
+  fi
   if test "$fail_if_missing" = "yes" -a -z "$TCL_SRC"; then
     AC_MSG_ERROR([could not configure Tcl])
   fi
--- a/src/if_tcl.c
+++ b/src/if_tcl.c
@@ -160,6 +160,20 @@ static struct ref refsdeleted;	/* dummy 
 typedef int HANDLE;
 # endif
 
+# ifndef WIN3264
+#  include <dlfcn.h>
+#  define HANDLE void*
+#  define TCL_PROC void*
+#  define load_dll(n) dlopen((n), RTLD_LAZY|RTLD_GLOBAL)
+#  define symbol_from_dll dlsym
+#  define close_dll dlclose
+# else
+#  define TCL_PROC FARPROC
+#  define load_dll vimLoadLib
+#  define symbol_from_dll GetProcAddress
+#  define close_dll FreeLibrary
+# endif
+
 /*
  * Declare HANDLE for tcl.dll and function pointers.
  */
@@ -170,7 +184,6 @@ void (*dll_Tcl_FindExecutable)(const voi
 /*
  * Table of name to function pointer of tcl.
  */
-#define TCL_PROC FARPROC
 static struct {
     char* name;
     TCL_PROC* ptr;
@@ -197,7 +210,7 @@ tcl_runtime_link_init(char *libname, int
 
     if (hTclLib)
 	return OK;
-    if (!(hTclLib = vimLoadLib(libname)))
+    if (!(hTclLib = load_dll(libname)))
     {
 	if (verbose)
 	    EMSG2(_(e_loadlib), libname);
@@ -205,10 +218,10 @@ tcl_runtime_link_init(char *libname, int
     }
     for (i = 0; tcl_funcname_table[i].ptr; ++i)
     {
-	if (!(*tcl_funcname_table[i].ptr = GetProcAddress(hTclLib,
+	if (!(*tcl_funcname_table[i].ptr = symbol_from_dll(hTclLib,
 			tcl_funcname_table[i].name)))
 	{
-	    FreeLibrary(hTclLib);
+	    close_dll(hTclLib);
 	    hTclLib = NULL;
 	    if (verbose)
 		EMSG2(_(e_loadfunc), tcl_funcname_table[i].name);
@@ -246,13 +259,13 @@ tcl_enabled(verbose)
     int		verbose;
 {
     if (!stubs_initialized && find_executable_arg != NULL
-	    && tcl_runtime_link_init(DYNAMIC_TCL_DLL, verbose) == OK)
+	    && tcl_runtime_link_init((char *)p_tcldll, verbose) == OK)
     {
 	Tcl_Interp *interp;
 
 	dll_Tcl_FindExecutable(find_executable_arg);
 
-	if (interp = dll_Tcl_CreateInterp())
+	if ((interp = dll_Tcl_CreateInterp()) != NULL)
 	{
 	    if (Tcl_InitStubs(interp, DYNAMIC_TCL_VER, 0))
 	    {
@@ -272,7 +285,7 @@ tcl_end()
 #ifdef DYNAMIC_TCL
     if (hTclLib)
     {
-	FreeLibrary(hTclLib);
+	close_dll(hTclLib);
 	hTclLib = NULL;
     }
 #endif
@@ -2039,6 +2052,10 @@ tcldelallrefs(ref)
     int		err;
     char	*result;
 
+    /* TODO: this code currently crashes Vim on exit */
+    if (exiting)
+	return;
+
     while (ref != NULL)
     {
 	next = ref->next;
--- a/src/option.c
+++ b/src/option.c
@@ -2609,6 +2609,12 @@ static struct vimoption
     {"tagstack",    "tgst", P_BOOL|P_VI_DEF,
 			    (char_u *)&p_tgst, PV_NONE,
 			    {(char_u *)TRUE, (char_u *)0L} SCRIPTID_INIT},
+#if defined(DYNAMIC_TCL)
+    {"tcldll",      NULL,   P_STRING|P_VI_DEF|P_SECURE,
+			    (char_u *)&p_tcldll, PV_NONE,
+			    {(char_u *)DYNAMIC_TCL_DLL, (char_u *)0L}
+			    SCRIPTID_INIT},
+#endif
     {"term",	    NULL,   P_STRING|P_EXPAND|P_NODEFAULT|P_NO_MKRC|P_VI_DEF|P_RALL,
 			    (char_u *)&T_NAME, PV_NONE,
 			    {(char_u *)"", (char_u *)0L} SCRIPTID_INIT},
--- a/src/option.h
+++ b/src/option.h
@@ -832,6 +832,9 @@ EXTERN long	p_tl;		/* 'taglength' */
 EXTERN int	p_tr;		/* 'tagrelative' */
 EXTERN char_u	*p_tags;	/* 'tags' */
 EXTERN int	p_tgst;		/* 'tagstack' */
+#if defined(DYNAMIC_TCL)
+EXTERN char_u	*p_tcldll;	/* 'tcldll' */
+#endif
 #ifdef FEAT_ARABIC
 EXTERN int	p_tbidi;	/* 'termbidi' */
 #endif
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1070,
+/**/
     1069,
 /**/
     1068,