9292BUILT_CONTOUR = False
9393BUILT_GDK = False
9494
95+ TCL_TK_CACHE = None
96+
9597AGG_VERSION = 'agg23'
9698
9799# for nonstandard installation/build with --prefix variable
@@ -797,51 +799,6 @@ def add_wx_flags(module, wxconfig):
797799# or else you'll build for a wrong version of the Tcl
798800# interpreter (leading to nasty segfaults).
799801
800- class FoundTclTk :
801- pass
802-
803- def find_tcltk ():
804- """Finds Tcl/Tk includes/libraries/version by interrogating Tkinter."""
805- # By this point, we already know that Tkinter imports correctly
806- import Tkinter
807- o = FoundTclTk ()
808- try :
809- tk = Tkinter .Tk ()
810- except Tkinter .TclError :
811- o .tcl_lib = "/usr/local/lib"
812- o .tcl_inc = "/usr/local/include"
813- o .tk_lib = "/usr/local/lib"
814- o .tk_inc = "/usr/local/include"
815- o .tkv = ""
816- else :
817- tk .withdraw ()
818- o .tcl_lib = os .path .normpath (os .path .join (str (tk .getvar ('tcl_library' )), '../' ))
819- o .tk_lib = os .path .normpath (os .path .join (str (tk .getvar ('tk_library' )), '../' ))
820- o .tkv = str (Tkinter .TkVersion )[:3 ]
821- o .tcl_inc = os .path .normpath (os .path .join (str (tk .getvar ('tcl_library' )),
822- '../../include/tcl' + o .tkv ))
823- if not os .path .exists (o .tcl_inc ):
824- o .tcl_inc = os .path .normpath (os .path .join (str (tk .getvar ('tcl_library' )),
825- '../../include' ))
826- o .tk_inc = os .path .normpath (os .path .join (str (tk .getvar ('tk_library' )),
827- '../../include/tk' + o .tkv ))
828- if not os .path .exists (o .tk_inc ):
829- o .tk_inc = os .path .normpath (os .path .join (str (tk .getvar ('tk_library' )),
830- '../../include' ))
831-
832- if ((not os .path .exists (os .path .join (o .tk_inc ,'tk.h' ))) and
833- os .path .exists (os .path .join (o .tcl_inc ,'tk.h' ))):
834- o .tk_inc = o .tcl_inc
835-
836- if not os .path .exists (o .tcl_inc ):
837- # this is a hack for suse linux, which is broken
838- if (sys .platform .startswith ('linux' ) and
839- os .path .exists ('/usr/include/tcl.h' ) and
840- os .path .exists ('/usr/include/tk.h' )):
841- o .tcl_inc = '/usr/include/'
842- o .tk_inc = '/usr/include/'
843- return o
844-
845802def check_for_tk ():
846803 gotit = False
847804 explanation = None
@@ -853,29 +810,27 @@ def check_for_tk():
853810 explanation = 'Tkinter present but import failed'
854811 else :
855812 if Tkinter .TkVersion < 8.3 :
856- explanation = "Tcl/Tk v8.3 or later required\n "
857- sys .exit (1 )
813+ explanation = "Tcl/Tk v8.3 or later required"
858814 else :
859- try :
860- tk = Tkinter .Tk ()
861- tk .withdraw ()
862- except Tkinter .TclError :
863- explanation = """\
864- Using default library and include directories for Tcl and Tk because a
865- Tk window failed to open. You may need to define DISPLAY for Tk to work
866- so that setup can determine where your libraries are located."""
867815 gotit = True
868-
816+
869817 if gotit :
870818 module = Extension ('test' , [])
871819 try :
872- add_tk_flags (module )
820+ explanation = add_tk_flags (module )
873821 except RuntimeError , e :
874822 explanation = str (e )
875823 gotit = False
876- if not find_include_file (module .include_dirs , "tk.h" ):
877- explanation = 'Tkinter present, but header files are not installed. You may need to install development packages.'
878-
824+ else :
825+ if not find_include_file (module .include_dirs , "tk.h" ):
826+ message = 'Tkinter present, but header files are not found. ' + \
827+ 'You may need to install development packages.'
828+ if explanation is not None :
829+ explanation += '\n ' + message
830+ else :
831+ explanation = message
832+ gotit = False
833+
879834 if gotit :
880835 print_status ("Tkinter" , "Tkinter: %s, Tk: %s, Tcl: %s" %
881836 (Tkinter .__version__ .split ()[- 2 ], Tkinter .TkVersion , Tkinter .TclVersion ))
@@ -885,34 +840,74 @@ def check_for_tk():
885840 print_message (explanation )
886841 return gotit
887842
843+ def query_tcltk ():
844+ """Tries to open a Tk window in order to query the Tk object about its library paths.
845+ This should never be called more than once by the same process, as Tk intricacies
846+ may cause the Python interpreter to hang. The function also has a workaround if
847+ no X server is running (useful for autobuild systems)."""
848+ global TCL_TK_CACHE
849+ # Use cached values if they exist, which ensures this function only executes once
850+ if TCL_TK_CACHE is not None :
851+ return TCL_TK_CACHE
852+
853+ # By this point, we already know that Tkinter imports correctly
854+ import Tkinter
855+ tcl_lib_dir = ''
856+ tk_lib_dir = ''
857+ # First try to open a Tk window (requires a running X server)
858+ try :
859+ tk = Tkinter .Tk ()
860+ except Tkinter .TclError :
861+ # Next, start Tcl interpreter without opening a Tk window (no need for X server)
862+ # This feature is available in python version 2.4 and up
863+ try :
864+ tcl = Tkinter .Tcl ()
865+ except AttributeError : # Python version not high enough
866+ pass
867+ except Tkinter .TclError : # Something went wrong while opening Tcl
868+ pass
869+ else :
870+ tcl_lib_dir = str (tcl .getvar ('tcl_library' ))
871+ # Guess Tk location based on Tcl location
872+ tk_lib_dir = tcl_lib_dir .replace ('Tcl' , 'Tk' ).replace ('tcl' , 'tk' )
873+ else :
874+ # Obtain Tcl and Tk locations from Tk widget
875+ tk .withdraw ()
876+ tcl_lib_dir = str (tk .getvar ('tcl_library' ))
877+ tk_lib_dir = str (tk .getvar ('tk_library' ))
878+
879+ # Save directories and version string to cache
880+ TCL_TK_CACHE = tcl_lib_dir , tk_lib_dir , str (Tkinter .TkVersion )[:3 ]
881+ return TCL_TK_CACHE
882+
888883def add_tk_flags (module ):
889884 'Add the module flags to build extensions which use tk'
890- if sys .platform == 'win32' :
885+ message = None
886+ if sys .platform == 'win32' :
891887 major , minor1 , minor2 , s , tmp = sys .version_info
892- if major == 2 and minor1 in [3 , 4 , 5 ]:
888+ if major == 2 and minor1 in [3 , 4 , 5 ]:
893889 module .include_dirs .extend (['win32_static/include/tcl8.4' ])
894890 module .libraries .extend (['tk84' , 'tcl84' ])
895- elif major == 2 and minor1 == 2 :
891+ elif major == 2 and minor1 == 2 :
896892 module .include_dirs .extend (['win32_static/include/tcl8.3' ])
897893 module .libraries .extend (['tk83' , 'tcl83' ])
898894 else :
899895 raise RuntimeError ('No tk/win32 support for this python version yet' )
900896 module .library_dirs .extend ([os .path .join (sys .prefix , 'dlls' )])
901- return
902-
903- elif sys .platform == 'darwin' :
897+
898+ elif sys .platform == 'darwin' :
904899 # this config section lifted directly from Imaging - thanks to
905900 # the effbot!
906-
901+
907902 # First test for a MacOSX/darwin framework install
908903 from os .path import join , exists
909904 framework_dirs = [
910905 '/System/Library/Frameworks/' ,
911906 '/Library/Frameworks' ,
912907 join (os .getenv ('HOME' ), '/Library/Frameworks' )
913908 ]
914-
915- # Find the directory that contains the Tcl.framwork and Tk.framework
909+
910+ # Find the directory that contains the Tcl.framework and Tk.framework
916911 # bundles.
917912 # XXX distutils should support -F!
918913 tk_framework_found = 0
@@ -936,7 +931,7 @@ def add_tk_flags(module):
936931 for fw in 'Tcl' , 'Tk'
937932 for H in 'Headers' , 'Versions/Current/PrivateHeaders'
938933 ]
939-
934+
940935 # For 8.4a2, the X11 headers are not included. Rather than include a
941936 # complicated search, this is a hard-coded path. It could bail out
942937 # if X11 libs are not found...
@@ -945,14 +940,54 @@ def add_tk_flags(module):
945940 module .include_dirs .extend (tk_include_dirs )
946941 module .extra_link_args .extend (frameworks )
947942 module .extra_compile_args .extend (frameworks )
948- return
949-
950- # you're still here? ok we'll try it this way
951- o = find_tcltk () # todo: try/except
952- module .include_dirs .extend ([o .tcl_inc , o .tk_inc ])
953- module .library_dirs .extend ([o .tcl_lib , o .tk_lib ])
954- module .libraries .extend (['tk' + o .tkv , 'tcl' + o .tkv ])
955-
943+
944+ # you're still here? ok we'll try it this way...
945+ else :
946+ # Query Tcl/Tk system for library paths and version string
947+ tcl_lib_dir , tk_lib_dir , tk_ver = query_tcltk () # todo: try/except
948+
949+ # Process base directories to obtain include + lib dirs
950+ if tcl_lib_dir != '' and tk_lib_dir != '' :
951+ tcl_lib = os .path .normpath (os .path .join (tcl_lib_dir , '../' ))
952+ tk_lib = os .path .normpath (os .path .join (tk_lib_dir , '../' ))
953+ tcl_inc = os .path .normpath (os .path .join (tcl_lib_dir ,
954+ '../../include/tcl' + tk_ver ))
955+ if not os .path .exists (tcl_inc ):
956+ tcl_inc = os .path .normpath (os .path .join (tcl_lib_dir ,
957+ '../../include' ))
958+ tk_inc = os .path .normpath (os .path .join (tk_lib_dir ,
959+ '../../include/tk' + tk_ver ))
960+ if not os .path .exists (tk_inc ):
961+ tk_inc = os .path .normpath (os .path .join (tk_lib_dir ,
962+ '../../include' ))
963+
964+ if ((not os .path .exists (os .path .join (tk_inc ,'tk.h' ))) and
965+ os .path .exists (os .path .join (tcl_inc ,'tk.h' ))):
966+ tk_inc = tcl_inc
967+
968+ if not os .path .exists (tcl_inc ):
969+ # this is a hack for suse linux, which is broken
970+ if (sys .platform .startswith ('linux' ) and
971+ os .path .exists ('/usr/include/tcl.h' ) and
972+ os .path .exists ('/usr/include/tk.h' )):
973+ tcl_inc = '/usr/include'
974+ tk_inc = '/usr/include'
975+ else :
976+ message = """\
977+ Using default library and include directories for Tcl and Tk because a
978+ Tk window failed to open. You may need to define DISPLAY for Tk to work
979+ so that setup can determine where your libraries are located."""
980+ tcl_inc = "/usr/local/include"
981+ tk_inc = "/usr/local/include"
982+ tcl_lib = "/usr/local/lib"
983+ tk_lib = "/usr/local/lib"
984+ tk_ver = ""
985+ # Add final versions of directories and libraries to module lists
986+ module .include_dirs .extend ([tcl_inc , tk_inc ])
987+ module .library_dirs .extend ([tcl_lib , tk_lib ])
988+ module .libraries .extend (['tk' + tk_ver , 'tcl' + tk_ver ])
989+
990+ return message
956991
957992def add_windowing_flags (module ):
958993 'Add the module flags to build extensions using windowing api'
@@ -1031,9 +1066,6 @@ def build_tkagg(ext_modules, packages):
10311066 deps ,
10321067 )
10331068
1034- # add agg flags before pygtk because agg only supports freetype1
1035- # and pygtk includes freetype2. This is a bit fragile.
1036-
10371069 add_tk_flags (module ) # do this first
10381070 add_agg_flags (module )
10391071 add_ft2font_flags (module )
0 commit comments