Switch from pkgutil to importlib.resources.

For loading resources, use `importlib.resources.files()` instead of
`pkgutil.get_data()`.  This works across project boundaries with Bazel
7, as well as through the `embossc` driver.

Also packaged resource loading into a utility function, so that
further changes can be more easily accomodated.
diff --git a/compiler/back_end/cpp/BUILD b/compiler/back_end/cpp/BUILD
index 3d31ec2..427b724 100644
--- a/compiler/back_end/cpp/BUILD
+++ b/compiler/back_end/cpp/BUILD
@@ -53,6 +53,7 @@
         "//compiler/util:ir_pb2",
         "//compiler/util:ir_util",
         "//compiler/util:name_conversion",
+        "//compiler/util:resources",
     ],
 )
 
diff --git a/compiler/back_end/cpp/header_generator.py b/compiler/back_end/cpp/header_generator.py
index 922d80b..a761bde 100644
--- a/compiler/back_end/cpp/header_generator.py
+++ b/compiler/back_end/cpp/header_generator.py
@@ -29,11 +29,11 @@
 from compiler.util import ir_pb2
 from compiler.util import ir_util
 from compiler.util import name_conversion
+from compiler.util import resources
 from compiler.util import traverse_ir
 
-_TEMPLATES = code_template.parse_templates(pkgutil.get_data(
-    "compiler.back_end.cpp",
-    "generated_code_templates").decode(encoding="UTF-8"))
+_TEMPLATES = code_template.parse_templates(resources.load(
+    "compiler.back_end.cpp", "generated_code_templates"))
 
 _CPP_RESERVED_WORDS = set((
     # C keywords.  A few of these are not (yet) C++ keywords, but some compilers
diff --git a/compiler/front_end/BUILD b/compiler/front_end/BUILD
index 024524d..776efed 100644
--- a/compiler/front_end/BUILD
+++ b/compiler/front_end/BUILD
@@ -98,6 +98,7 @@
         ":lr1",
         ":module_ir",
         ":tokenizer",
+        "//compiler/util:resources",
         "//compiler/util:simple_memoizer",
     ],
 )
@@ -137,6 +138,7 @@
         "//compiler/util:ir_pb2",
         "//compiler/util:error",
         "//compiler/util:parser_types",
+        "//compiler/util:resources",
     ],
 )
 
@@ -322,6 +324,7 @@
         "//compiler/util:ir_pb2",
         "//compiler/util:error",
         "//compiler/util:ir_util",
+        "//compiler/util:resources",
         "//compiler/util:traverse_ir",
     ],
 )
diff --git a/compiler/front_end/constraints.py b/compiler/front_end/constraints.py
index 6beaf31..5f67d7c 100644
--- a/compiler/front_end/constraints.py
+++ b/compiler/front_end/constraints.py
@@ -14,12 +14,11 @@
 
 """Routines to check miscellaneous constraints on the IR."""
 
-import pkgutil
-
 from compiler.front_end import attributes
 from compiler.util import error
 from compiler.util import ir_pb2
 from compiler.util import ir_util
+from compiler.util import resources
 from compiler.util import traverse_ir
 
 
@@ -394,9 +393,8 @@
   global _RESERVED_WORDS
   _RESERVED_WORDS = {}
   language = None
-  for line in pkgutil.get_data(
-      "compiler.front_end",
-      "reserved_words").decode(encoding="UTF-8").splitlines():
+  for line in resources.load(
+      "compiler.front_end", "reserved_words").splitlines():
     stripped_line = line.partition("#")[0].strip()
     if not stripped_line:
       continue
diff --git a/compiler/front_end/glue.py b/compiler/front_end/glue.py
index c19385d..0dceaf9 100644
--- a/compiler/front_end/glue.py
+++ b/compiler/front_end/glue.py
@@ -19,7 +19,6 @@
 """
 
 import collections
-import pkgutil
 
 from compiler.front_end import attribute_checker
 from compiler.front_end import constraints
@@ -36,6 +35,7 @@
 from compiler.util import error
 from compiler.util import ir_pb2
 from compiler.util import parser_types
+from compiler.util import resources
 
 _IrDebugInfo = collections.namedtuple("IrDebugInfo", ["ir", "debug_info",
                                                       "errors"])
@@ -202,9 +202,7 @@
 def get_prelude():
   """Returns the module IR and debug info of the Emboss Prelude."""
   return parse_module_text(
-      pkgutil.get_data("compiler.front_end",
-                       "prelude.emb").decode(encoding="UTF-8"),
-      "")
+      resources.load("compiler.front_end", "prelude.emb"), "")
 
 
 def parse_emboss_file(file_name, file_reader, stop_before_step=None):
diff --git a/compiler/front_end/parser.py b/compiler/front_end/parser.py
index 600b644..6ece324 100644
--- a/compiler/front_end/parser.py
+++ b/compiler/front_end/parser.py
@@ -14,11 +14,10 @@
 
 """Routines to generate a shift-reduce parser from the module_ir module."""
 
-import pkgutil
-
 from compiler.front_end import lr1
 from compiler.front_end import module_ir
 from compiler.front_end import tokenizer
+from compiler.util import resources
 from compiler.util import simple_memoizer
 
 
@@ -104,9 +103,8 @@
 
 @simple_memoizer.memoize
 def _load_module_parser():
-  path = "compiler.front_end"
   error_examples = parse_error_examples(
-      pkgutil.get_data(path, "error_examples").decode("utf-8"))
+      resources.load("compiler.front_end", "error_examples"))
   return generate_parser(module_ir.START_SYMBOL, module_ir.PRODUCTIONS,
                          error_examples)
 
diff --git a/compiler/util/BUILD b/compiler/util/BUILD
index 4c34cc1..d0e3d3f 100644
--- a/compiler/util/BUILD
+++ b/compiler/util/BUILD
@@ -167,3 +167,9 @@
         ":name_conversion",
     ],
 )
+
+py_library(
+    name = "resources",
+    srcs = ["resources.py"],
+    deps = [],
+)
diff --git a/compiler/util/resources.py b/compiler/util/resources.py
new file mode 100644
index 0000000..606b1d9
--- /dev/null
+++ b/compiler/util/resources.py
@@ -0,0 +1,23 @@
+# Copyright 2024 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.
+
+"""Routines to load resource files from within the compiler."""
+
+import importlib.resources
+
+def load(package, file, encoding="utf-8"):
+  """Returns the contents of `file` from the Python package loader."""
+  with importlib.resources.files(
+      package).joinpath(file).open("r", encoding=encoding) as f:
+    return f.read()