From baaedf6aa881b777628dad3f5b8d3ba2ab9e2940 Mon Sep 17 00:00:00 2001 From: Judah Jacobson Date: Mon, 14 May 2018 21:49:43 -0700 Subject: [PATCH] Stop manually generating Cabal macros. It turns out they're generated automatically by GHC since version 8.0, as long as we pass the right package name and version. That's now possible as of tweag/rules_haskell#246. I'll hold off merging this PR until that one goes in, then I'll rebase to `rules_haskell` master. --- .circleci/config.yml | 5 +- WORKSPACE | 2 +- hazel.bzl | 2 +- .../hazel_base_repository.bzl | 19 ++--- .../bzl/cabal/GenerateCabalMacros.hs | 62 -------------- third_party/cabal2bazel/bzl/cabal_package.bzl | 83 +++---------------- 6 files changed, 21 insertions(+), 152 deletions(-) delete mode 100644 third_party/cabal2bazel/bzl/cabal/GenerateCabalMacros.hs diff --git a/.circleci/config.yml b/.circleci/config.yml index de7948d..6c9b2f6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,5 +22,6 @@ jobs: command: bazel test //... - run: name: Test some package repositories - command: bazel build --jobs=2 \ - @haskell_{aeson,language-c,lens,network}//... + command: | + bazel build --jobs=2 \ + @haskell_{aeson,language-c,lens,network}//... diff --git a/WORKSPACE b/WORKSPACE index 90023f0..7f3d679 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -14,7 +14,7 @@ nixpkgs_git_repository( revision = "c33c5239f62b4855b14dc5b01dfa3e2a885cf9ca", ) -RULES_HASKELL_SHA = "2f176d0b7e81371259f39993d7b96bb4711abb3b" +RULES_HASKELL_SHA = "fb6b7c4383d8de7092adab3a6e9ba0d4bcc2c190" http_archive( name = "io_tweag_rules_haskell", urls = ["https://github.com/tweag/rules_haskell/archive/" diff --git a/hazel.bzl b/hazel.bzl index 1a09770..23e7975 100644 --- a/hazel.bzl +++ b/hazel.bzl @@ -94,4 +94,4 @@ def hazel_repositories(prebuilt_dependencies, packages): def hazel_library(name): """Returns the label of the haskell_library rule for the given package.""" - return "@haskell_{}//:{}-lib".format(name,name) + return "@haskell_{}//:{}".format(name,name) diff --git a/hazel_base_repository/hazel_base_repository.bzl b/hazel_base_repository/hazel_base_repository.bzl index a65f2c7..872317c 100644 --- a/hazel_base_repository/hazel_base_repository.bzl +++ b/hazel_base_repository/hazel_base_repository.bzl @@ -8,11 +8,7 @@ def _hazel_base_repository_impl(ctx): "@ai_formation_hazel//third_party/cabal2bazel:src/Google/Google3/Tools/Cabal2Build/Description.hs", ] - generate_cabal_macros_srcs = [ - "@ai_formation_hazel//third_party/cabal2bazel:bzl/cabal/GenerateCabalMacros.hs", - ] - - for f in cabal2bazel_srcs + generate_cabal_macros_srcs: + for f in cabal2bazel_srcs: l = Label(f) ctx.symlink(Label(f), l.name) @@ -21,11 +17,6 @@ def _hazel_base_repository_impl(ctx): if res.return_code != 0: fail("Couldn't build cabal2bazel:\n{}\n{}".format(res.stdout,res.stderr)) - res = ctx.execute(["./ghc", "-Wall", "-Werror", "--make", "-o", "generate-cabal-macros"] - + [Label(f).name for f in generate_cabal_macros_srcs]) - if res.return_code != 0: - fail("Couldn't build generate-cabal-macros:\n{}\n{}".format(res.stdout,res.stderr)) - res = ctx.execute(["./ghc", "--numeric-version"]) if res.return_code != 0: fail("Couldn't get GHC version:\n{}\n{}".format(res.stdout,res.stderr)) @@ -42,7 +33,7 @@ packages = {} ctx.file( "BUILD", - content="""exports_files(["cabal2bazel", "generate-cabal-macros", "ghc-version"])""", + content="""exports_files(["cabal2bazel", "ghc-version"])""", executable=False) hazel_base_repository = repository_rule( @@ -55,7 +46,7 @@ hazel_base_repository = repository_rule( # TODO: don't reload all package names into every repository. def symlink_and_invoke_hazel(ctx, hazel_base_repo_name, cabal_path, output): - for f in ["cabal2bazel", "ghc-version", "generate-cabal-macros"]: + for f in ["cabal2bazel", "ghc-version"]: ctx.symlink(Label("@" + hazel_base_repo_name + "//:" + f), f) ghc_version = ctx.execute(["cat", "ghc-version"]).stdout @@ -70,7 +61,7 @@ def symlink_and_invoke_hazel(ctx, hazel_base_repo_name, cabal_path, output): load("@ai_formation_hazel//third_party/cabal2bazel:bzl/cabal_package.bzl", "cabal_haskell_package", "hazel_symlink") -load("@hazel_base_repository//:packages.bzl", "prebuilt_dependencies", "packages") +load("@hazel_base_repository//:packages.bzl", "prebuilt_dependencies") load("//:package.bzl", "package") # Make a buildable target for easier debugging of the package.bzl file hazel_symlink( @@ -78,5 +69,5 @@ hazel_symlink( src = "package.bzl", out = "package-bzl", ) -cabal_haskell_package(package, prebuilt_dependencies, packages) +cabal_haskell_package(package, prebuilt_dependencies) """) diff --git a/third_party/cabal2bazel/bzl/cabal/GenerateCabalMacros.hs b/third_party/cabal2bazel/bzl/cabal/GenerateCabalMacros.hs deleted file mode 100644 index c5235e2..0000000 --- a/third_party/cabal2bazel/bzl/cabal/GenerateCabalMacros.hs +++ /dev/null @@ -1,62 +0,0 @@ --- Copyright 2018 Google LLC --- --- Licensed under the Apache License, Version 2.0 (the "License"); --- you may not use this file except in compliance with the License. --- You may obtain a copy of the License at --- --- https://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, software --- distributed under the License is distributed on an "AS IS" BASIS, --- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. --- See the License for the specific language governing permissions and --- limitations under the License. - --- | A program to output a header file defining macros for a Cabal package. --- In particular, it defines the MIN_VERSION_{name} macro which many packages --- use to tell the version of their dependencies. --- --- For more information on Cabal macros, see: --- https://www.haskell.org/cabal/users-guide/developing-packages.html#conditional-compilation --- --- Example Usage: --- ...../GenerateCabalMacros third_party/haskell/ghc/.../default-packages.txt --- base --- bytestring --- split-0.2.2 --- text-1.2.0.4 --- --- Package names which appear in default-packages.txt (e.g. "base", --- "bytestring") will be assigned the version number that appears in that file. --- Other packages (e.g. "split", "text") must have their version given on the --- command line. -module Main where - -import Control.Monad (unless) -import Distribution.Compat.ReadP (look, pfail, readP_to_S, ReadP) -import Distribution.Package (PackageIdentifier(..)) -import Distribution.Text (parse) -import Distribution.Simple.Build.Macros (generatePackageVersionMacros) -import System.Environment (getArgs) - -main :: IO () -main = do - packageStrings <- getArgs - putStrLn $ generatePackageVersionMacros $ map parsePackage packageStrings - --- | Parse a package id like "base-4.8.2.0" or --- "base-4.8.2.0-0d6d1084fbc041e1cded9228e80e264d" --- into a PackageIdentifier (pair of name "base" and version [4,8,2,0]). -parsePackage :: String -> PackageIdentifier -parsePackage s = case readP_to_S (parse <* eof) s of - [(p,"")] -> p - cs -> error $ "Parsing " ++ show s ++ " got " ++ show cs - --- | Fail unless this happens at the end of the input. Fixes ambiguity errors --- with Cabal's implementations of parse; for example, "text" and "text-1.2.3" --- are both valid PackageIdentifiers, so we need 'eof' to force the parser to --- choose the latter. -eof :: ReadP r () -eof = do - rest <- look - unless (null rest) pfail diff --git a/third_party/cabal2bazel/bzl/cabal_package.bzl b/third_party/cabal2bazel/bzl/cabal_package.bzl index 57c693e..75dd49f 100644 --- a/third_party/cabal2bazel/bzl/cabal_package.bzl +++ b/third_party/cabal2bazel/bzl/cabal_package.bzl @@ -28,48 +28,6 @@ load("//templates:templates.bzl", "templates") _conditions_default = "//conditions:default" -# Cabal macro generation target name ends with this. -_macros_suffix = "-macros" - -# The _cabal_haskell_macros rule generates a file containing Cabal -# MIN_VERSION_* macros of all of the specified dependencies, as well as some -# other Cabal macros. -# For more details, see //bzl/cabal/GenerateCabalMacros.hs. -# Args: -# deps: A list of cabal_haskell_library rules. -# default_packages: A list of names of default packages that -# this package depends on; e.g., "base". -def _impl_cabal_haskell_macros(ctx): - if not ctx.label.name.endswith(_macros_suffix): - fail("Macros target ends with unexpected suffix.") - ctx.action( - outputs=[ctx.outputs.out], - inputs=[ctx.executable._generate_cabal_macros], - progress_message="Generating Haskell Cabal macros for %s" % str(ctx.label), - mnemonic="HaskellGenerateCabalMacros", - command=( - " ".join( - [ctx.executable._generate_cabal_macros.path] - + ["{}-{}".format(p, ctx.attr.packages[p]) - for p in ctx.attr.packages]) - + " > " + ctx.outputs.out.path), - ) - -_cabal_haskell_macros = rule( - implementation=_impl_cabal_haskell_macros, - attrs={ - "packages": attr.string_dict(mandatory=True), - "_generate_cabal_macros": attr.label( - executable=True, - cfg="host", - allow_files=True, - single_file=True, - default=Label("@hazel_base_repository//:generate-cabal-macros") - ), - }, - outputs={"out": "%{name}.h"}, -) - def _paths_module(desc): return "Paths_" + desc.package.pkgName.replace("-","_") @@ -118,7 +76,7 @@ def _fix_source_dirs(dirs): return [""] def _get_build_attrs(name, build_info, desc, generated_srcs_dir, extra_modules, - prebuilt_dependencies, packages, + prebuilt_dependencies, cc_deps=[], version_overrides=None, ghcopts=[]): """Get the attributes for a particular library or binary rule. @@ -227,32 +185,17 @@ def _get_build_attrs(name, build_info, desc, generated_srcs_dir, extra_modules, # Collect the dependencies. prebuilt_deps = [] - dep_versions = {} for condition, ps in _conditions_dict(depset(build_info.targetBuildDepends).to_list()).items(): if condition not in deps: deps[condition] = [] for p in ps: if p.name in prebuilt_dependencies: - dep_versions[p.name] = prebuilt_dependencies[p.name] prebuilt_deps += [p.name] elif p.name == desc.package.pkgName: # Allow executables to depend on the library in the same package. deps[condition] += [":" + p.name + "-lib"] else: - deps[condition] += ["@haskell_{}//:{}-lib".format(p.name, p.name)] - dep_versions[p.name] = packages[p.name] - - - # Generate the macros for these dependencies. - # TODO: Maybe remove the MIN_VERSION_ macro generation, - # since GHC 8 itself (not Cabal) generates these. But not the - # CURRENT_PACKAGE_KEY macro? - # See https://ghc.haskell.org/trac/ghc/ticket/10970. - _cabal_haskell_macros( - name = name + _macros_suffix, - packages = dep_versions, - ) - ghcopts += ["-optP-include", "-optP%s.h" % (name + _macros_suffix)] + deps[condition] += ["@haskell_{}//:{}".format(p.name, p.name)] ghcopts += ["-optP" + o for o in build_info.cppOptions] @@ -265,8 +208,7 @@ def _get_build_attrs(name, build_info, desc, generated_srcs_dir, extra_modules, for f in build_info.installIncludes]) headers = depset( native.glob(desc.extraSrcFiles) - + install_includes - + [":{}.h".format(name + _macros_suffix)]) + + install_includes) ghcopts += ["-I" + native.package_name() + "/" + d for d in build_info.includeDirs] lib_name = name + "-cbits" for xs in deps.values(): @@ -305,14 +247,13 @@ def _collect_data_files(description): else: return native.glob([paths.join(description.dataDir, d) for d in description.dataFiles]) -def cabal_haskell_package(description, prebuilt_dependencies, packages): +def cabal_haskell_package(description, prebuilt_dependencies): """Create rules for building a Cabal package. - Args: +def cabal_haskell_package(description, prebuilt_dependencies, packages): + Args: description: A Skylark struct generated by cabal2build representing a .cabal file's contents. prebuilt_dependencies: A dict of the builtin GHC packages. - packages: A dict of the non-builtin packages. """ name = description.package.pkgName @@ -326,23 +267,22 @@ def cabal_haskell_package(description, prebuilt_dependencies, packages): lib = description.library if lib and lib.libBuildInfo.buildable: - lib_name = name + "-lib" if not lib.exposedModules: native.cc_library( - name = lib_name, + name = name, visibility = ["//visibility:public"], ) else: - lib_attrs = _get_build_attrs(name + "-lib", lib.libBuildInfo, description, + lib_attrs = _get_build_attrs(name, lib.libBuildInfo, description, "dist/build", lib.exposedModules, - prebuilt_dependencies, - packages) + prebuilt_dependencies) srcs = lib_attrs.pop("srcs") deps = lib_attrs.pop("deps") haskell_library( - name = lib_name, + name = name, srcs = select(srcs), + version = description.package.pkgVersion, deps = select(deps), visibility = ["//visibility:public"], **lib_attrs @@ -363,8 +303,7 @@ def cabal_haskell_package(description, prebuilt_dependencies, packages): # Paths_ module explicitly. [paths_mod] if paths_mod not in exe.buildInfo.otherModules else [], - prebuilt_dependencies, - packages) + prebuilt_dependencies) srcs = attrs.pop("srcs") deps = attrs.pop("deps")