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")