From d67085d947733438e8d992cfacd2a737b03bc495 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Thu, 30 May 2024 15:03:12 +0200 Subject: [PATCH 1/3] Fix using the single threaded RTS Since GHC 9.4.1, the rts library has `hs-libraries: HSrts-1.0.2 Cffi` in the package config. We have special handling for HSrts (and Cffi) but that fails due to the name change. --- haskell/private/pkgdb_to_bzl.py | 2 +- haskell/toolchain.bzl | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/haskell/private/pkgdb_to_bzl.py b/haskell/private/pkgdb_to_bzl.py index 9729c72be..78a9372e7 100755 --- a/haskell/private/pkgdb_to_bzl.py +++ b/haskell/private/pkgdb_to_bzl.py @@ -100,7 +100,7 @@ def hs_library_pattern(name, mode = "static", profiling = False): # See https://gitlab.haskell.org/ghc/ghc/wikis/commentary/rts/config#rts-configurations configs = ["_p"] if profiling else [""] # Special case HSrts or Cffi - include both libXYZ and libXYZ_thr. - if name == "HSrts" or name == "Cffi": + if name == "HSrts" or name.startswith("HSrts-") or name == "Cffi": configs = [ prefix + config for config in configs diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 8fb1b9016..8af7b716c 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -250,6 +250,15 @@ def _haskell_toolchain_libraries(ctx, libraries): if len(ext_components) == 2 and ext_components[0] == "so": libs[libname]["dynamic"] = lib else: + # with GHC >= 9.4.1 the rts library has a version number + # included in the name. + # for handling single-threaded and threading variants below, + # we normalize the name and strip the version number + if libname.startswith("HSrts-"): + idx = libname.find("_") + suffix = libname[idx:] if idx > 0 else "" + libname = "HSrts" + suffix + libs[libname] = {"dynamic": lib} for lib in target[HaskellImportHack].static_libraries.to_list(): name = get_static_hs_lib_name(with_profiling, lib) From a776c9ba0bdd5ec5a05479cc1103253df8440dd9 Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Wed, 5 Jun 2024 12:26:09 +0200 Subject: [PATCH 2/3] Also apply HSrts normalization to static lib --- haskell/toolchain.bzl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/haskell/toolchain.bzl b/haskell/toolchain.bzl index 8af7b716c..dd751afdf 100644 --- a/haskell/toolchain.bzl +++ b/haskell/toolchain.bzl @@ -262,6 +262,16 @@ def _haskell_toolchain_libraries(ctx, libraries): libs[libname] = {"dynamic": lib} for lib in target[HaskellImportHack].static_libraries.to_list(): name = get_static_hs_lib_name(with_profiling, lib) + + # with GHC >= 9.4.1 the rts library has a version number + # included in the name. + # for handling single-threaded and threading variants below, + # we normalize the name and strip the version number + if name.startswith("HSrts-"): + idx = name.find("_") + suffix = name[idx:] if idx > 0 else "" + name = "HSrts" + suffix + entry = libs.get(name, {}) entry["static"] = lib libs[name] = entry From ea41a9136e039ef3aa38d323300bcdeec99206dd Mon Sep 17 00:00:00 2001 From: Claudio Bley Date: Mon, 10 Jun 2024 07:59:17 +0200 Subject: [PATCH 3/3] Refactor `hs_libary_pattern` in `pkgdb_to_bzl.py` According to the cabal docs, the `hs-libraries` entries of a package config needs to comply to specific file naming conventions, see [1]. Only names starting with `HS` or `C` are allowed and dynamic libs prefixed with `C` need to be handled specially as the "C" prefix should be stripped. The "rts" hs-libraries also exist in all configured GHC ways, single/multi threaded and debug/non-debug variants. Before, only rts's Cffi was handled correctly but other C libs were not. [1]: https://cabal.readthedocs.io/en/3.4/cabal-package.html#pkg-field-extra-bundled-libraries --- haskell/private/pkgdb_to_bzl.py | 48 ++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/haskell/private/pkgdb_to_bzl.py b/haskell/private/pkgdb_to_bzl.py index 78a9372e7..0a039ffdd 100755 --- a/haskell/private/pkgdb_to_bzl.py +++ b/haskell/private/pkgdb_to_bzl.py @@ -84,10 +84,11 @@ def path_to_label(path, pkgroot, output=None): else: print("WARN: could not handle", path, file=sys.stderr) -def hs_library_pattern(name, mode = "static", profiling = False): +def hs_library_pattern(package_name, name, mode = "static", profiling = False): """Convert hs-libraries entry to glob patterns. Args: + package_name: The name of the package. name: The library name. E.g. HSrts or Cffi. mode: The linking mode. Either "static" or "dynamic". profiling: Look for profiling mode libraries. @@ -96,30 +97,41 @@ def hs_library_pattern(name, mode = "static", profiling = False): List of globbing patterns for the library file. """ + configs = ["_p"] if profiling else [""] + + # Library names must either be prefixed with "HS" or "C" and corresponding + # library file names must match: + # - Libraries with name "HS": + # - `libHS.a` + # - `libHS-ghc.*` + # - Libraries with name "C": + # - `libC.a` + # - `lib.*` + if name.startswith("C"): + libname = name[1:] if mode == "dynamic" else name + elif name.startswith("HS"): + libname = name + else: + sys.error("do not know how to handle hs-library `{}` in package {}".format(name, package_name)) + # The RTS configuration suffix. # See https://gitlab.haskell.org/ghc/ghc/wikis/commentary/rts/config#rts-configurations - configs = ["_p"] if profiling else [""] - # Special case HSrts or Cffi - include both libXYZ and libXYZ_thr. - if name == "HSrts" or name.startswith("HSrts-") or name == "Cffi": + # Special case for rts - include multi threaded and single threaded, and debug / non-debug variants + if package_name == "rts": configs = [ prefix + config for config in configs - for prefix in ["", "_thr"] + for prefix in ["", "_thr", "_debug", "_thr_debug"] ] - # Special case libCffi - dynamic lib has no configs and is called libffi. - if name == "Cffi" and mode == "dynamic": - libname = "ffi" - configs = [""] - else: - libname = name + libnames = [libname + config for config in configs] - # Special case libCffi - dynamic lib has no version suffix. - if mode == "dynamic" and name != "Cffi": - libnames = [libname + "-ghc*" for libname in libnames] + if mode == "dynamic": - exts = ["so", "so.*", "dylib", "dll"] + libnames = [libname + "-ghc*" for libname in libnames] + exts = ["so", "so.*", "dylib", "dll"] if mode == "dynamic" else ["a"] else: exts = ["a"] + return [ "lib{}.{}".format(libname, ext) for libname in libnames @@ -235,21 +247,21 @@ def hs_library_pattern(name, mode = "static", profiling = False): static_libraries = join_paths([ [path_to_label(library_dir, pkgroot, output), library] for hs_library in pkg.hs_libraries - for pattern in hs_library_pattern(hs_library, mode = "static", profiling = False) + for pattern in hs_library_pattern(pkg.name, hs_library, mode = "static", profiling = False) for library_dir in pkg.library_dirs for library in match_glob(resolve(library_dir, pkgroot), pattern) ]), static_profiling_libraries = join_paths([ [path_to_label(library_dir, pkgroot, output), library] for hs_library in pkg.hs_libraries - for pattern in hs_library_pattern(hs_library, mode = "static", profiling = True) + for pattern in hs_library_pattern(pkg.name, hs_library, mode = "static", profiling = True) for library_dir in pkg.library_dirs for library in match_glob(resolve(library_dir, pkgroot), pattern) ]), shared_libraries = join_paths([ [path_to_label(dynamic_library_dir, pkgroot, output), library] for hs_library in pkg.hs_libraries - for pattern in hs_library_pattern(hs_library, mode = "dynamic", profiling = False) + for pattern in hs_library_pattern(pkg.name, hs_library, mode = "dynamic", profiling = False) for dynamic_library_dir in set(pkg.dynamic_library_dirs + pkg.library_dirs) for library in match_glob(resolve(dynamic_library_dir, pkgroot), pattern) ]),