From 92be3585822759323986e1cc580c531eb001405c Mon Sep 17 00:00:00 2001 From: "Adam J. Stewart" Date: Tue, 8 Jun 2021 12:45:04 -0500 Subject: Python: fix +tkinter+tix support (#23980) * Tcl: fix TCLLIBPATH * Fix TCL|TK|TIX_LIBRARY paths * Fix TCL_LIBRARY, no tcl8.6 subdir * Don't rely on os.listdirs sorting For tcl and tk, we also install the source directory, so there are two init.tcl and tk.tcl locations. We want the one in lib/lib64, which should come before the one in share. * Add more patches * Fix dylib on macOS * Tk: add smoke tests * Tix: add smoke test --- var/spack/repos/builtin/packages/tcl/package.py | 103 +++++++++++++-------- var/spack/repos/builtin/packages/tix/package.py | 68 +++++++++++++- var/spack/repos/builtin/packages/tix/test/test.tcl | 5 + var/spack/repos/builtin/packages/tk/package.py | 101 +++++++++++++------- var/spack/repos/builtin/packages/tk/test/test.tcl | 5 + 5 files changed, 203 insertions(+), 79 deletions(-) create mode 100644 var/spack/repos/builtin/packages/tix/test/test.tcl create mode 100644 var/spack/repos/builtin/packages/tk/test/test.tcl (limited to 'var') diff --git a/var/spack/repos/builtin/packages/tcl/package.py b/var/spack/repos/builtin/packages/tcl/package.py index 5d82bb7eef..74ea8815ab 100644 --- a/var/spack/repos/builtin/packages/tcl/package.py +++ b/var/spack/repos/builtin/packages/tcl/package.py @@ -9,14 +9,13 @@ from spack.util.environment import is_system_path class Tcl(AutotoolsPackage, SourceforgePackage): - """Tcl (Tool Command Language) is a very powerful but easy to - learn dynamic programming language, suitable for a very wide - range of uses, including web and desktop applications, - networking, administration, testing and many more. Open source - and business-friendly, Tcl is a mature yet evolving language - that is truly cross platform, easily deployed and highly - extensible.""" - homepage = "http://www.tcl.tk" + """Tcl (Tool Command Language) is a very powerful but easy to learn dynamic + programming language, suitable for a very wide range of uses, including web and + desktop applications, networking, administration, testing and many more. Open source + and business-friendly, Tcl is a mature yet evolving language that is truly cross + platform, easily deployed and highly extensible.""" + + homepage = "https://www.tcl.tk/" sourceforge_mirror_path = "tcl/tcl8.6.11-src.tar.gz" version('8.6.11', sha256='8c0486668586672c5693d7d95817cb05a18c5ecca2f40e2836b9578064088258') @@ -38,7 +37,7 @@ class Tcl(AutotoolsPackage, SourceforgePackage): with working_dir(self.build_directory): make('install') - # http://wiki.tcl.tk/17463 + # https://wiki.tcl-lang.org/page/kitgen if self.spec.satisfies('@8.6:'): make('install-headers') @@ -81,22 +80,39 @@ class Tcl(AutotoolsPackage, SourceforgePackage): def command(self): """Returns the tclsh command. - :returns: The tclsh command - :rtype: Executable + Returns: + Executable: the tclsh command """ - return Executable(os.path.realpath(self.prefix.bin.tclsh)) + # Although we symlink tclshX.Y to tclsh, we also need to support external + # installations that may not have this symlink, or may have multiple versions + # of Tcl installed in the same directory. + return Executable(os.path.realpath(self.prefix.bin.join( + 'tclsh{0}'.format(self.version.up_to(2))))) def setup_run_environment(self, env): - # When using Tkinter from within spack provided python+tkinter, python - # will not be able to find Tcl/Tk unless TCL_LIBRARY is set. - env.set('TCL_LIBRARY', self.spec['tcl'].libs.directories[0]) + """Set TCL_LIBRARY to the directory containing init.tcl. + + For further info see: + + * https://wiki.tcl-lang.org/page/TCL_LIBRARY + """ + # When using tkinter from within spack provided python+tkinter, + # python will not be able to find Tcl unless TCL_LIBRARY is set. + env.set('TCL_LIBRARY', os.path.dirname( + sorted(find(self.prefix, 'init.tcl'))[0])) def setup_dependent_build_environment(self, env, dependent_spec): - """Set TCLLIBPATH to include the tcl-shipped directory for + """Set TCL_LIBRARY to the directory containing init.tcl. + Set TCLLIBPATH to include the tcl-shipped directory for extensions and any other tcl extension it depends on. - For further info see: https://wiki.tcl.tk/1787""" - env.set('TCL_LIBRARY', self.spec['tcl'].libs.directories[0]) + For further info see: + + * https://wiki.tcl-lang.org/page/TCL_LIBRARY + * https://wiki.tcl-lang.org/page/TCLLIBPATH + """ + env.set('TCL_LIBRARY', os.path.dirname( + sorted(find(self.prefix, 'init.tcl'))[0])) # If we set TCLLIBPATH, we must also ensure that the corresponding # tcl is found in the build environment. This to prevent cases @@ -106,35 +122,40 @@ class Tcl(AutotoolsPackage, SourceforgePackage): if not is_system_path(self.prefix.bin): env.prepend_path('PATH', self.prefix.bin) - tcl_paths = [join_path(self.spec['tcl'].libs.directories[0], - 'tcl{0}'.format(self.version.up_to(2)))] + # WARNING: paths in $TCLLIBPATH must be *space* separated, + # its value is meant to be a Tcl list, *not* an env list + # as explained here: https://wiki.tcl-lang.org/page/TCLLIBPATH: + # "TCLLIBPATH is a Tcl list, not some platform-specific + # colon-separated or semi-colon separated format" + + # WARNING: Tcl and Tcl extensions like Tk install their configuration files + # in subdirectories like `/lib/tcl8.6`. However, Tcl is aware of this, + # and $TCLLIBPATH should only contain `/lib`. $TCLLIBPATH is only needed + # because we install Tcl extensions to different directories than Tcl. See: + # https://core.tcl-lang.org/tk/tktview/447bd3e4abe17452d19a80e6840dcc8a2603fcbc + env.prepend_path( + 'TCLLIBPATH', self.spec['tcl'].libs.directories[0], separator=' ') for d in dependent_spec.traverse(deptype=('build', 'run', 'test')): if d.package.extends(self.spec): # Tcl libraries may be installed in lib or lib64, see #19546 for lib in ['lib', 'lib64']: - tcl_paths.append(join_path( - d.prefix, lib, 'tcl{0}'.format(self.version.up_to(2)))) - - # WARNING: paths in $TCLLIBPATH must be *space* separated, - # its value is meant to be a Tcl list, *not* an env list - # as explained here: https://wiki.tcl.tk/1787: - # "TCLLIBPATH is a Tcl list, not some platform-specific - # colon-separated or semi-colon separated format" - tcllibpath = ' '.join(tcl_paths) - env.set('TCLLIBPATH', tcllibpath) + tcllibpath = join_path(d.prefix, lib) + if os.path.exists(tcllibpath): + env.prepend_path('TCLLIBPATH', tcllibpath, separator=' ') def setup_dependent_run_environment(self, env, dependent_spec): """Set TCLLIBPATH to include the tcl-shipped directory for extensions and any other tcl extension it depends on. - For further info see: https://wiki.tcl.tk/1787""" - - # For run time environment set only the path for - # dependent_spec and prepend it to TCLLIBPATH - if dependent_spec.package.extends(self.spec): - # Tcl libraries may be installed in lib or lib64, see #19546 - for lib in ['lib', 'lib64']: - tcllibpath = join_path( - self.prefix, lib, 'tcl{0}'.format(self.version.up_to(2))) - if os.path.exists(tcllibpath): - env.prepend_path('TCLLIBPATH', tcllibpath, separator=' ') + + For further info see: + + * https://wiki.tcl-lang.org/page/TCLLIBPATH + """ + for d in dependent_spec.traverse(deptype=('build', 'run', 'test')): + if d.package.extends(self.spec): + # Tcl libraries may be installed in lib or lib64, see #19546 + for lib in ['lib', 'lib64']: + tcllibpath = join_path(d.prefix, lib) + if os.path.exists(tcllibpath): + env.prepend_path('TCLLIBPATH', tcllibpath, separator=' ') diff --git a/var/spack/repos/builtin/packages/tix/package.py b/var/spack/repos/builtin/packages/tix/package.py index 2dc682d2e2..237c3fad3f 100644 --- a/var/spack/repos/builtin/packages/tix/package.py +++ b/var/spack/repos/builtin/packages/tix/package.py @@ -3,20 +3,46 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) +import os + from spack import * class Tix(AutotoolsPackage): - """Tix is a powerful high-level widget set that expands the capabilities - of your Tk/Tcl and Python applications.""" + """Tix, the Tk Interface eXtension, is a powerful set of user interface components + that expands the capabilities of your Tcl/Tk and Python applications. Using Tix + together with Tk will greatly enhance the appearance and functionality of your + application.""" homepage = "https://sourceforge.net/projects/tix/" url = "https://sourceforge.net/projects/tix/files/tix/8.4.3/Tix8.4.3-src.tar.gz/download" + version('8.4.3', sha256='562f040ff7657e10b5cffc2c41935f1a53c6402eb3d5f3189113d734fd6c03cb') - extends('tcl') - depends_on('tk@:8.5.99') - depends_on('tcl@:8.5.99') + extends('tcl', type=('build', 'link', 'run')) + depends_on('tk', type=('build', 'link', 'run')) + + patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tix/files/panic.patch', + sha256='1be1a1c7453f6ab8771f90d7e7c0f8959490104752a16a8755bbb7287a841a96', + level=0) + patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tix/files/implicit.patch', + sha256='8a2720368c7757896814684147029d8318b9aa3b0914b3f37dd5e8a8603a61d3', + level=0) + patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tix/files/patch-generic-tixGrSort.c.diff', + sha256='99b33cc307f71bcf9cc6f5a44b588f22956884ce3f1e4c716ad64c79cf9c5f41', + level=0) + patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tix/files/patch-missing-headers.diff', + sha256='d9f789dcfe5f4c5ee4589a18f9f410cdf162e41d35d00648c1ef37831f4a2b2b', + level=0) + patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tix/files/patch-tk_x11.diff', + sha256='1e28d8eee1aaa956a00571cf495a4775e72a993958dff1cabfbc5f102e327a6f', + level=0) + patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tix/files/patch-tk_aqua.diff', + sha256='41a717f5d95f61b4b8196ca6f14ece8f4764d4ba58fb2e1ae15e3240ee5ac534', + level=0, when='platform=darwin') + patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tix/files/patch-dyld_variable.diff', + sha256='719eb2e4d8c5d6aae897e5f676cf5ed1a0005c1bd07fd9b18705d81a005f592b', + level=0, when='platform=darwin') def configure_args(self): spec = self.spec @@ -27,7 +53,39 @@ class Tix(AutotoolsPackage): ] return args + @run_after('install') + def darwin_fix(self): + # The shared library is not installed correctly on Darwin; fix this + if 'platform=darwin' in self.spec: + fix_darwin_install_name(self.prefix.lib.Tix + str(self.version)) + + def test(self): + test_data_dir = self.test_suite.current_test_data_dir + test_file = test_data_dir.join('test.tcl') + self.run_test(self.spec['tcl'].command.path, test_file, + purpose='test that tix can be loaded') + @property def libs(self): return find_libraries(['libTix{0}'.format(self.version)], root=self.prefix, recursive=True) + + def setup_run_environment(self, env): + """Set TIX_LIBRARY to the directory containing Tix.tcl. + + For further info, see: + + * http://tix.sourceforge.net/docs/pdf/TixUser.pdf + """ + # When using tkinter.tix from within spack provided python+tkinter+tix, + # python will not be able to find Tix unless TIX_LIBRARY is set. + env.set('TIX_LIBRARY', os.path.dirname(find(self.prefix, 'Tix.tcl')[0])) + + def setup_dependent_build_environment(self, env, dependent_spec): + """Set TIX_LIBRARY to the directory containing Tix.tcl. + + For further info, see: + + * http://tix.sourceforge.net/docs/pdf/TixUser.pdf + """ + env.set('TIX_LIBRARY', os.path.dirname(find(self.prefix, 'Tix.tcl')[0])) diff --git a/var/spack/repos/builtin/packages/tix/test/test.tcl b/var/spack/repos/builtin/packages/tix/test/test.tcl new file mode 100644 index 0000000000..02b3ab986f --- /dev/null +++ b/var/spack/repos/builtin/packages/tix/test/test.tcl @@ -0,0 +1,5 @@ +#!/usr/bin/env tclsh + +package require Tix + +exit diff --git a/var/spack/repos/builtin/packages/tk/package.py b/var/spack/repos/builtin/packages/tk/package.py index d02734fba8..a96d2564a5 100644 --- a/var/spack/repos/builtin/packages/tk/package.py +++ b/var/spack/repos/builtin/packages/tk/package.py @@ -3,18 +3,18 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) -from spack import * import os +from spack import * + class Tk(AutotoolsPackage, SourceforgePackage): - """Tk is a graphical user interface toolkit that takes developing - desktop applications to a higher level than conventional - approaches. Tk is the standard GUI not only for Tcl, but for - many other dynamic languages, and can produce rich, native - applications that run unchanged across Windows, Mac OS X, Linux - and more.""" - homepage = "http://www.tcl.tk" + """Tk is a graphical user interface toolkit that takes developing desktop + applications to a higher level than conventional approaches. Tk is the standard GUI + not only for Tcl, but for many other dynamic languages, and can produce rich, native + applications that run unchanged across Windows, Mac OS X, Linux and more.""" + + homepage = "https://www.tcl.tk" sourceforge_mirror_path = "tcl/tk8.6.5-src.tar.gz" version('8.6.11', sha256='5228a8187a7f70fa0791ef0f975270f068ba9557f57456f51eb02d9d4ea31282') @@ -25,14 +25,12 @@ class Tk(AutotoolsPackage, SourceforgePackage): version('8.6.3', sha256='ba15d56ac27d8c0a7b1a983915a47e0f635199b9473cf6e10fbce1fc73fd8333') version('8.5.19', sha256='407af1de167477d598bd6166d84459a3bdccc2fb349360706154e646a9620ffa') - variant('xft', default=True, - description='Enable X FreeType') - variant('xss', default=True, - description='Enable X Screen Saver') + variant('xft', default=True, description='Enable X FreeType') + variant('xss', default=True, description='Enable X Screen Saver') - extends('tcl') + extends('tcl', type=('build', 'link', 'run')) - depends_on('tcl@8.6:', when='@8.6:') + depends_on('tcl@8.6:', type=('build', 'link', 'run'), when='@8.6:') depends_on('libx11') depends_on('libxft', when='+xft') depends_on('libxscrnsaver', when='+xss') @@ -45,6 +43,21 @@ class Tk(AutotoolsPackage, SourceforgePackage): patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tk/files/patch-unix-Makefile.in.diff', sha256='54bba3d2b3550b7e2c636881c1a3acaf6e1eb743f314449a132864ff47fd0010', level=0, when='@:8.6.11 platform=darwin') + patch('https://raw.githubusercontent.com/macports/macports-ports/master/x11/tk/files/patch-dyld_fallback_library_path.diff', + sha256='9ce6512f1928db9987986f4d3540207c39429395d5234bd6489ba9d86a6d9c31', + level=0, when='platform=darwin') + + def configure_args(self): + spec = self.spec + config_args = [ + '--with-tcl={0}'.format(spec['tcl'].libs.directories[0]), + '--x-includes={0}'.format(spec['libx11'].headers.directories[0]), + '--x-libraries={0}'.format(spec['libx11'].libs.directories[0]) + ] + config_args += self.enable_or_disable('xft') + config_args += self.enable_or_disable('xss') + + return config_args def install(self, spec, prefix): with working_dir(self.build_directory): @@ -64,32 +77,54 @@ class Tk(AutotoolsPackage, SourceforgePackage): stage_src, installed_src, join_path(self.spec['tk'].libs.directories[0], 'tkConfig.sh')) + @run_after('install') + def symlink_wish(self): + with working_dir(self.prefix.bin): + symlink('wish{0}'.format(self.version.up_to(2)), 'wish') + + def test(self): + self.run_test(self.spec['tk'].command.path, ['-h'], + purpose='test wish command') + + test_data_dir = self.test_suite.current_test_data_dir + test_file = test_data_dir.join('test.tcl') + self.run_test(self.spec['tcl'].command.path, test_file, + purpose='test that tk can be loaded') + + @property + def command(self): + """Returns the wish command. + + Returns: + Executable: the wish command + """ + # Although we symlink wishX.Y to wish, we also need to support external + # installations that may not have this symlink, or may have multiple versions + # of Tk installed in the same directory. + return Executable(os.path.realpath(self.prefix.bin.join( + 'wish{0}'.format(self.version.up_to(2))))) + @property def libs(self): return find_libraries(['libtk{0}'.format(self.version.up_to(2))], root=self.prefix, recursive=True) def setup_run_environment(self, env): - # When using Tkinter from within spack provided python+tkinter, python - # will not be able to find Tcl/Tk unless TK_LIBRARY is set. - env.set('TK_LIBRARY', self.spec['tk'].libs.directories[0]) + """Set TK_LIBRARY to the directory containing tk.tcl. - def setup_dependent_build_environment(self, env, dependent_spec): - env.set('TK_LIBRARY', self.spec['tk'].libs.directories[0]) + For further info, see: - def configure_args(self): - spec = self.spec - config_args = [ - '--with-tcl={0}'.format(spec['tcl'].libs.directories[0]), - '--x-includes={0}'.format(spec['libx11'].headers.directories[0]), - '--x-libraries={0}'.format(spec['libx11'].libs.directories[0]) - ] - config_args += self.enable_or_disable('xft') - config_args += self.enable_or_disable('xss') + * https://www.tcl-lang.org/man/tcl/TkCmd/tkvars.htm + """ + # When using tkinter from within spack provided python+tkinter, + # python will not be able to find Tk unless TK_LIBRARY is set. + env.set('TK_LIBRARY', os.path.dirname(sorted(find(self.prefix, 'tk.tcl'))[0])) - return config_args + def setup_dependent_build_environment(self, env, dependent_spec): + """Set TK_LIBRARY to the directory containing tk.tcl. - @run_after('install') - def symlink_wish(self): - with working_dir(self.prefix.bin): - symlink('wish{0}'.format(self.version.up_to(2)), 'wish') + For further info, see: + + * https://www.tcl-lang.org/man/tcl/TkCmd/tkvars.htm + """ + env.set('TK_LIBRARY', os.path.dirname(sorted(find(self.prefix, 'tk.tcl'))[0])) diff --git a/var/spack/repos/builtin/packages/tk/test/test.tcl b/var/spack/repos/builtin/packages/tk/test/test.tcl new file mode 100644 index 0000000000..b52c3b8b9f --- /dev/null +++ b/var/spack/repos/builtin/packages/tk/test/test.tcl @@ -0,0 +1,5 @@ +#!/usr/bin/env tclsh + +package require Tk + +exit -- cgit v1.2.3-60-g2f50