From: | Patrick Samson <p_samson(at)yahoo(dot)com> |
---|---|
To: | pgsql-cygwin(at)postgresql(dot)org |
Subject: | pltcl - cannot create 'normal' interpreter - Tcl_CreateSlave() fails - A solution |
Date: | 2004-01-07 13:21:38 |
Message-ID: | 20040107132138.57308.qmail@web60304.mail.yahoo.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-cygwin |
A follow-up of:
http://archives.postgresql.org/pgsql-cygwin/2003-11/msg00074.php
http://archives.postgresql.org/pgsql-cygwin/2003-01/msg00131.php
http://sources.redhat.com/ml/insight/2003-q1/msg00049.php
http://archives.postgresql.org/pgsql-interfaces/2003-04/msg00164.php
Here is a description of how I succeeded to run a
PL/Tcl script on Postgresql/Cygwin.
1. First, some words about what appends, and the
"failure stack":
When you try to run a PL/Tcl code, the operation fails
with the message:
"ERROR: pltcl: internal error - cannot create
'normal' interpreter"
This is due to the failure of:
-> pl/tcl/pltcl.c - pltcl_init_all()
-> tcl8.4.1/generic/tclInterp.c - Tcl_CreateSlave()
-> tcl8.4.1/win/tclWinInit.c - Tcl_Init()
-> Tcl_Eval(interp, initScript)
-> tcl8.4.1/generic/tclInitScript.h - error $msg -
Can't find a usable init.tcl ...
With some debugging trace, one can see that the
directory list to search for a init.tcl is empty.
Conclusion:
It is mandatory to feed the initialization step with
some directory paths.
Let's see how.
2. tclInitScript.h mentions 4 ways to specify the
directories.
- $tcl_library: this variable should be set after
Tcl_CreateInterp() and before Tcl_Init(),
so in tclInterp.c. As I don't want to touch the tcl
package, forget it.
- $env(TCL_LIBRARY): this way seems to solve the
problem, but another one appears (see 6. below).
- $tclDefaultLibrary: is set for the unix version
(tcl8.4.1/unix/tclUnixInit.c),
but not for the win version
(tcl8.4.1/win/tclWinInit.c). Forget it.
- $tcl_libPath: is set with the result of
TclGetLibraryPath().
Fine, but who is in charge to call
TclSetLibraryPath()?
Some investigation leads me to the following tree:
TclSetLibraryPath()
<- win/tclWinInit.c - TclpInitLibraryPath()
<- generic/tclEncoding.c - TclFindEncodings()
<- generic/tclEncoding.c - Tcl_FindExecutable(argv[0])
3. TclpInitLibraryPath() is a very interesting place,
indeed.
This is where the directory path is initialized.
Let's browse the categories:
a. installLib[2], "library", developLib:
What may be fine with tclsh.exe
(X:/cygwin/bin/tclsh.exe) is not with pgtclsh.exe or
postgres.exe
(X:/cygwin/usr/local/pgsql/bin/ path).
These options compose the following useless
directories:
X:/cygwin/usr/local/pgsql/share/tcl8.4
X:/cygwin/usr/local/pgsql/usr/share/tcl8.4
X:/cygwin/usr/local/share/tcl8.4
X:/cygwin/usr/local/pgsql/library
X:/cygwin/usr/local/library
X:/cygwin/usr/local/../tcl8.4.1/library
X:/cygwin/usr/../tcl8.4.1/library
b. Tcl_GetDefaultEncodingDir(): is empty; useless
c. AppendDllPath(): would be the perfect solution, but
is not yet adapted for cygwin standard
(see
http://cygwin.com/ml/cygwin/2004-01/msg00108.html)
d. AppendEnvironment(): have to be THE solution,
because there is no one else.
So TCL_LIBRARY have to be defined as an environment
variable.
4. For pgtclsh.exe or if you run postgres.exe
manually, you can do:
export TCL_LIBRARY=$(cygpath -w /usr/share/tcl8.4)
[Jason, you were on the right way with it]
5. But if you run postmaster as a windows Service, you
should define TCL_LIBRARY
as a system environment variable. Something like
"X:\cygwin\usr\share\tcl8.4".
Stop/Start postmaster is not enough: don't forget (as
I did) to reboot the machine,
as Windows loads the environment variables which are
available to services when
the machine is booted.
6. Add a call to Tcl_FindExecutable() in pltcl.c -
pltcl_init_all(),
just before the call to Tcl_CreateInterp().
It should be called with argv[0] as argument, but I
don't know how to get this piece of information for
pltcl.dll. Anyway, for Windows, it is unused (see
win/tclWinFile.c - TclpFindExecutable()). Just a value
!= NULL is OK, so I used an empty string.
[Jan, I'm only interested in cygwin platform. I
suggest you investigate deeper to make this
"workaround" cleaner, in order to be also compatible
with pure Unix platforms.]
Without this call, and with only the setting of the
environment variable, Tcl_CreateSlave() seems to fail
somewhere else, with this message:
--------------------------
server closed the connection unexpectedly
This probably means the server terminated
abnormally
before or while processing the request.
The connection to the server was lost. Attempting
reset: Succeeded.
--------------------------
I didn't spend time on this issue, just added the
call.
7. For the pltcl.dll to be built, I had to:
a. Permute the order of tcl.h and postgres.h.
See
http://archives.postgresql.org/pgsql-bugs/2003-12/msg00184.php
[Peter, Tom, I know you don't consider it as a
definitive fix, but meanwhile it worked for me.]
b. Add $(BE_DLLLIBS) to SHLIB_LINK in Makefile.
See
http://archives.postgresql.org/pgsql-bugs/2003-12/msg00183.php
Is fixed in version 7.4
This was suggested by Jason in his never-submitted
patch, see:
http://archives.postgresql.org/pgsql-cygwin/2003-01/msg00080.php
http://archives.postgresql.org/pgsql-cygwin/2003-11/msg00074.php
Just for completeness, here are the output of my build
and my patch:
--------------------------
Samson(at)pc2020 /opt/postgresql-7.3.5/src/pl/tcl
$ make
gcc -O2 -Wall -Wmissing-prototypes
-Wmissing-declarations -I../../../src/include -c -o
pltcl.o pltcl.c
In file included from
../../../src/include/pg_config.h:673,
from ../../../src/include/c.h:53,
from
../../../src/include/postgres.h:48,
from pltcl.c:43:
../../../src/include/pg_config_os.h:26:1: warning:
"DLLIMPORT" redefined
In file included from pltcl.c:41:
/usr/include/tcl.h:201:1: warning: this is the
location of the previous definition
pltcl.c: In function `pltcl_init_interp':
pltcl.c:270: warning: passing arg 3 of
`Tcl_CreateCommand' from incompatible pointer type
pltcl.c:272: warning: passing arg 3 of
`Tcl_CreateCommand' from incompatible pointer type
pltcl.c:274: warning: passing arg 3 of
`Tcl_CreateCommand' from incompatible pointer type
pltcl.c:276: warning: passing arg 3 of
`Tcl_CreateCommand' from incompatible pointer type
pltcl.c:279: warning: passing arg 3 of
`Tcl_CreateCommand' from incompatible pointer type
pltcl.c:281: warning: passing arg 3 of
`Tcl_CreateCommand' from incompatible pointer type
pltcl.c:283: warning: passing arg 3 of
`Tcl_CreateCommand' from incompatible pointer type
pltcl.c:285: warning: passing arg 3 of
`Tcl_CreateCommand' from incompatible pointer type
pltcl.c: In function `pltcl_trigger_handler':
pltcl.c:827: warning: passing arg 4 of `Tcl_SplitList'
from incompatible pointer type
pltcl.c: In function `pltcl_SPI_prepare':
pltcl.c:1754: warning: passing arg 4 of
`Tcl_SplitList' from incompatible pointer type
pltcl.c: In function `pltcl_SPI_execp':
pltcl.c:2063: warning: passing arg 4 of
`Tcl_SplitList' from incompatible pointer type
dlltool --export-all --output-def pltcl.def pltcl.o
dllwrap -o pltcl.dll --dllname pltcl.dll --def
pltcl.def pltcl.o ../../../src/utils/dllinit.o
-L/usr/local/lib -L../../../src/backend -lpostgres
-L/usr/lib -ltcl84
dlltool --dllname pltcl.dll --def pltcl.def
--output-lib libpltcl.a
make -C modules all
make[1]: Entering directory
`/opt/postgresql-7.3.5/src/pl/tcl/modules'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory
`/opt/postgresql-7.3.5/src/pl/tcl/modules'
--------------------------
$ diff -u pltcl.orig pltcl.c
--- pltcl.orig 2003-10-30 03:00:44.000000000 +0100
+++ pltcl.c 2004-01-06 13:54:03.937500000 +0100
@@ -35,10 +35,13 @@
*
**********************************************************************/
-#include "postgres.h"
-
+//psa: change order of tcl.h and postgres.h
+//
http://archives.postgresql.org/pgsql-cygwin/2003-01/msg00080.php
+//
http://archives.postgresql.org/pgsql-cygwin/2003-11/msg00074.php
#include <tcl.h>
+#include "postgres.h"
+
#include <unistd.h>
#include <fcntl.h>
#include <setjmp.h>
@@ -207,6 +210,9 @@
* Create the dummy hold interpreter to
prevent close of
* stdout and stderr on DeleteInterp
************************************************************/
+//psa: argument should be argv[0]. But anyway, it is
unused on Windows: just have to be != NULL.
+Tcl_FindExecutable("");
+
if ((pltcl_hold_interp = Tcl_CreateInterp())
== NULL)
{
elog(ERROR, "pltcl: internal error -
cannot create 'hold' "
@@ -219,6 +225,8 @@
if ((pltcl_norm_interp =
Tcl_CreateSlave(pltcl_hold_interp,
"norm", 0)) == NULL)
{
+//psa: tell me more about the fail
+elog(LOG,Tcl_GetStringResult(pltcl_hold_interp));
elog(ERROR,
"pltcl: internal error - cannot
create 'normal' interpreter");
}
@@ -227,6 +235,8 @@
if ((pltcl_safe_interp =
Tcl_CreateSlave(pltcl_hold_interp,
"safe", 1)) == NULL)
{
+//psa: tell me more about the fail
+elog(LOG,Tcl_GetStringResult(pltcl_hold_interp));
elog(ERROR,
"pltcl: internal error -
cannot create 'safe' interpreter");
}
__________________________________
Do you Yahoo!?
Yahoo! Hotjobs: Enter the "Signing Bonus" Sweepstakes
http://hotjobs.sweepstakes.yahoo.com/signingbonus
From | Date | Subject | |
---|---|---|---|
Next Message | Jason Tishler | 2004-01-07 13:57:30 | Re: Cygwin PostgreSQL 7.4.1 Regression Test Issue |
Previous Message | LitelWang | 2004-01-07 01:26:20 | new install(latest version) problem in windows 2000/xp |