diff options
author | John W. Parent <45471568+johnwparent@users.noreply.github.com> | 2024-01-18 14:47:52 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-18 12:47:52 -0700 |
commit | 883014e56ab553f7b791e384b828aba7a9831138 (patch) | |
tree | 4eedb2b218a5f2242852b16675b30ff71c9b01d1 | |
parent | eb625321aea55e1c53f8f3f462ad7620acf30160 (diff) | |
download | spack-883014e56ab553f7b791e384b828aba7a9831138.tar.gz spack-883014e56ab553f7b791e384b828aba7a9831138.tar.bz2 spack-883014e56ab553f7b791e384b828aba7a9831138.tar.xz spack-883014e56ab553f7b791e384b828aba7a9831138.zip |
Tcl package: support build on Windows (#41939)
-rw-r--r-- | var/spack/repos/builtin/packages/tcl/package.py | 195 | ||||
-rw-r--r-- | var/spack/repos/builtin/packages/tcl/tcl-quote-cc-path.patch | 13 |
2 files changed, 136 insertions, 72 deletions
diff --git a/var/spack/repos/builtin/packages/tcl/package.py b/var/spack/repos/builtin/packages/tcl/package.py index 66cfa63df2..0d1dd1e819 100644 --- a/var/spack/repos/builtin/packages/tcl/package.py +++ b/var/spack/repos/builtin/packages/tcl/package.py @@ -4,14 +4,32 @@ # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os +import sys from llnl.util.filesystem import find_first from spack.package import * from spack.util.environment import is_system_path +is_windows = sys.platform == "win32" -class Tcl(AutotoolsPackage, SourceforgePackage): + +class TclHelper: + @staticmethod + def find_script_dir(spec): + # Put more-specific prefixes first + check_prefixes = [ + join_path(spec.prefix, "share", "tcl{0}".format(spec.package.version.up_to(2))), + spec.prefix, + ] + for prefix in check_prefixes: + result = find_first(prefix, "init.tcl") + if result: + return os.path.dirname(result) + raise RuntimeError("Cannot locate init.tcl") + + +class Tcl(AutotoolsPackage, NMakePackage, SourceforgePackage, TclHelper): """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 @@ -20,6 +38,7 @@ class Tcl(AutotoolsPackage, SourceforgePackage): homepage = "https://www.tcl.tk/" sourceforge_mirror_path = "tcl/tcl8.6.11-src.tar.gz" + tags = ["windows"] license("TCL") @@ -37,53 +56,30 @@ class Tcl(AutotoolsPackage, SourceforgePackage): depends_on("zlib-api") - configure_directory = "unix" - - filter_compiler_wrappers("tclConfig.sh", relative_root="lib") - - def install(self, spec, prefix): - with working_dir(self.build_directory): - make("install") - - # https://wiki.tcl-lang.org/page/kitgen - if self.spec.satisfies("@8.6:"): - make("install-headers") - - # Some applications like Expect require private Tcl headers. - make("install-private-headers") - - # Copy source to install tree - # A user-provided install option might re-do this - # https://github.com/spack/spack/pull/4102/files - installed_src = join_path(self.spec.prefix, "share", self.name, "src") - stage_src = os.path.realpath(self.stage.source_path) - install_tree(stage_src, installed_src) - - # Replace stage dir -> installed src dir in tclConfig - filter_file( - stage_src, - installed_src, - join_path(self.spec["tcl"].libs.directories[0], "tclConfig.sh"), - ) - - # Don't install binaries in src/ tree - with working_dir(join_path(installed_src, self.configure_directory)): - make("clean") - - @run_after("install") - def symlink_tclsh(self): - with working_dir(self.prefix.bin): - symlink("tclsh{0}".format(self.version.up_to(2)), "tclsh") + # No compiler wrappers on Windows + for plat in ["linux", "darwin", "cray", "freebsd"]: + filter_compiler_wrappers("tclConfig.sh", relative_root="lib", when=f"platform={plat}") + build_system("autotools", "nmake") + patch("tcl-quote-cc-path.patch", when="platform=windows") # ======================================================================== # Set up environment to make install easy for tcl extensions. # ======================================================================== @property + def _tcl_name(self): + ver_suffix = self.version.up_to(2) + win_suffix = "" + if is_windows: + if self.spec.satisfies("@:8.7"): + win_suffix = "t" + ver_suffix = ver_suffix.joined + return f"{ver_suffix}{win_suffix}" + + @property def libs(self): - return find_libraries( - ["libtcl{0}".format(self.version.up_to(2))], root=self.prefix, recursive=True - ) + lib = "lib" if not is_windows else "" + return find_libraries([f"{lib}tcl{self._tcl_name}"], root=self.prefix, recursive=True) @property def command(self): @@ -95,21 +91,8 @@ class Tcl(AutotoolsPackage, SourceforgePackage): # 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 _find_script_dir(self): - # Put more-specific prefixes first - check_prefixes = [ - join_path(self.prefix, "share", "tcl{0}".format(self.version.up_to(2))), - self.prefix, - ] - for prefix in check_prefixes: - result = find_first(prefix, "init.tcl") - if result: - return os.path.dirname(result) - raise RuntimeError("Cannot locate init.tcl") + exe = ".exe" if is_windows else "" + return Executable(os.path.realpath(self.prefix.bin.join(f"tclsh{self._tcl_name}{exe}"))) def setup_run_environment(self, env): """Set TCL_LIBRARY to the directory containing init.tcl. @@ -120,7 +103,41 @@ class Tcl(AutotoolsPackage, SourceforgePackage): """ # 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", self._find_script_dir()) + env.set("TCL_LIBRARY", TclHelper.find_script_dir(self.spec)) + + 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-lang.org/page/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(dependent_spec.prefix, lib) + if os.path.exists(tcllibpath): + env.prepend_path("TCLLIBPATH", tcllibpath, separator=" ") + + +class BaseBuilder(TclHelper, metaclass=spack.builder.PhaseCallbacksMeta): + @run_after("install") + def symlink_tclsh(self): + # There's some logic regarding this suffix in the build system + # but the way Spack builds tcl, the Windows suffix is always 't' + # unless the version is >= 8.7, in which case there is no suffix + # if the build is ever switched to static, this will need to change + # to be "s[t]" + win_suffix = "" + ver_suffix = self.pkg.version.up_to(2) + if is_windows: + win_suffix = "t" if self.spec.satisfies("@:8.7") else "" + win_suffix += ".exe" + ver_suffix = ver_suffix.joined + + with working_dir(self.prefix.bin): + symlink(f"tclsh{ver_suffix}{win_suffix}", "tclsh") def setup_dependent_build_environment(self, env, dependent_spec): """Set TCL_LIBRARY to the directory containing init.tcl. @@ -132,15 +149,15 @@ class Tcl(AutotoolsPackage, SourceforgePackage): * https://wiki.tcl-lang.org/page/TCL_LIBRARY * https://wiki.tcl-lang.org/page/TCLLIBPATH """ - env.set("TCL_LIBRARY", self._find_script_dir()) + env.set("TCL_LIBRARY", TclHelper.find_script_dir(self.spec)) # If we set TCLLIBPATH, we must also ensure that the corresponding # tcl is found in the build environment. This to prevent cases # where a system provided tcl is run against the standard libraries # of a Spack built tcl. See issue #7128 that relates to python but # it boils down to the same situation we have here. - if not is_system_path(self.prefix.bin): - env.prepend_path("PATH", self.prefix.bin) + if not is_system_path(self.spec.prefix.bin): + env.prepend_path("PATH", self.spec.prefix.bin) # WARNING: paths in $TCLLIBPATH must be *space* separated, # its value is meant to be a Tcl list, *not* an env list @@ -162,17 +179,51 @@ class Tcl(AutotoolsPackage, SourceforgePackage): 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: +class AutotoolsBuilder(BaseBuilder, spack.build_systems.autotools.AutotoolsBuilder): + configure_directory = "unix" - * https://wiki.tcl-lang.org/page/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(dependent_spec.prefix, lib) - if os.path.exists(tcllibpath): - env.prepend_path("TCLLIBPATH", tcllibpath, separator=" ") + def install(self, pkg, spec, prefix): + with working_dir(self.build_directory): + make("install") + + # https://wiki.tcl-lang.org/page/kitgen + if self.spec.satisfies("@8.6:"): + make("install-headers") + + # Some applications like Expect require private Tcl headers. + make("install-private-headers") + + # Copy source to install tree + # A user-provided install option might re-do this + # https://github.com/spack/spack/pull/4102/files + installed_src = join_path(self.spec.prefix, "share", pkg.name, "src") + stage_src = os.path.realpath(pkg.stage.source_path) + install_tree(stage_src, installed_src) + + # Replace stage dir -> installed src dir in tclConfig + filter_file( + stage_src, + installed_src, + join_path(self.spec["tcl"].libs.directories[0], "tclConfig.sh"), + ) + + # Don't install binaries in src/ tree + with working_dir(join_path(installed_src, self.configure_directory)): + make("clean") + + +class NMakeBuilder(BaseBuilder, spack.build_systems.nmake.NMakeBuilder): + build_targets = ["all"] + install_targets = ["install"] + + @property + def makefile_root(self): + return f"{self.stage.source_path}\\win" + + @property + def makefile_name(self): + return "makefile.vc" + + def nmake_install_args(self): + return [self.define("INSTALLDIR", self.spec.prefix)] diff --git a/var/spack/repos/builtin/packages/tcl/tcl-quote-cc-path.patch b/var/spack/repos/builtin/packages/tcl/tcl-quote-cc-path.patch new file mode 100644 index 0000000000..53039c1aa2 --- /dev/null +++ b/var/spack/repos/builtin/packages/tcl/tcl-quote-cc-path.patch @@ -0,0 +1,13 @@ +diff --git a/win/rules.vc b/win/rules.vc +index 8a91b58b46..9e888ce8cb 100644 +--- a/win/rules.vc ++++ b/win/rules.vc +@@ -416,7 +416,7 @@ _INSTALLDIR=$(_INSTALLDIR)\lib + # MACHINE - same as $(ARCH) - legacy + # _VC_MANIFEST_EMBED_{DLL,EXE} - commands for embedding a manifest if needed + +-cc32 = $(CC) # built-in default. ++cc32 = "$(CC)" # built-in default. + link32 = link + lib32 = lib + rc32 = $(RC) # built-in default. |