Skip to content

Commit 38f07ff

Browse files
committed
Remove bundled openfhe from PYPI wheel
This change modifies the PyPI distribution of HEIR to no longer build and ship OpenFHE. The user must now provide a self-provided OpenFHE installation (shared libs and heaers) via environment variables. As a consequence, we updated the CI to: 1. Not run frontend tests in bazel 2. After the main bazel build/test, add new steps that install openfhe, `pip install -e .`, and runs `pytest` to evaluate the frontend tests outside of bazel. I also discovered that more recent manylinux containers have a sanctioned clang, so I updated the cibuildwheel container to use 2_34. We may be able to go back to supporting 2_28 after the hermetic LLVM lands, because I believe they have hermetic glibc that you can pick explicitly.
1 parent 0aed724 commit 38f07ff

26 files changed

Lines changed: 731 additions & 717 deletions

.github/build_openfhe.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
# Clone OpenFHE
5+
if [ ! -d "openfhe-development" ]; then
6+
git clone --depth 1 --branch v1.4.2 https://github.com/openfheorg/openfhe-development.git
7+
fi
8+
9+
# Build OpenFHE
10+
mkdir -p openfhe-development/build
11+
cd openfhe-development/build
12+
13+
INSTALL_DIR="$(pwd)/../../openfhe-install"
14+
mkdir -p "$INSTALL_DIR"
15+
16+
cmake .. \
17+
-DCMAKE_BUILD_TYPE=Release \
18+
-DBUILD_UNITTESTS=OFF \
19+
-DBUILD_BENCHMARKS=OFF \
20+
-DBUILD_EXAMPLES=OFF \
21+
-DCMAKE_INSTALL_PREFIX="$INSTALL_DIR"
22+
23+
make -j$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)
24+
make install
25+
26+
# Export variables to GITHUB_ENV if running in GitHub Actions
27+
if [ -n "$GITHUB_ENV" ]; then
28+
echo "OPENFHE_LIB_DIR=$INSTALL_DIR/lib" >> "$GITHUB_ENV"
29+
INC_DIR="$INSTALL_DIR/include/openfhe"
30+
echo "OPENFHE_INCLUDE_DIR=$INSTALL_DIR/include:$INC_DIR:$INC_DIR/binfhe:$INC_DIR/core:$INC_DIR/pke" >> "$GITHUB_ENV"
31+
fi
Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
#!/usr/bin/env bash
2-
3-
# Install clang and lld (container only has gcc by default)
4-
# Pin to clang 20 — some HEIR deps don't yet support clang 21+
5-
# (cf. https://github.com/google/heir/issues/2675).
6-
CLANG_VERSION=20
7-
yum install -y "clang-${CLANG_VERSION}*" "lld-${CLANG_VERSION}*"
2+
set -e
83

94
# Install bazel
105
if ! bazel version; then
@@ -16,7 +11,24 @@ if ! bazel version; then
1611
bazel_version=$(cat /project/.bazelversion)
1712
curl -L -o $HOME/bin/bazel --create-dirs "https://github.com/bazelbuild/bazel/releases/download/${bazel_version}/bazel-${bazel_version}-linux-${arch}"
1813
chmod +x $HOME/bin/bazel
19-
else
20-
# Bazel is installed for the correct architecture
21-
exit 0
2214
fi
15+
16+
manylinux-install-clang -v v20.1.8.0
17+
18+
# Install OpenMP development headers using the CRB repository
19+
dnf install -y --enablerepo=crb libomp-devel
20+
21+
# Symlink OpenMP headers from system Clang to static Clang's include directory
22+
for system_clang_dir in /usr/lib/clang/* /usr/lib64/clang/*; do
23+
[ -d "$system_clang_dir/include" ] || continue
24+
for f in "$system_clang_dir/include"/omp*.h; do
25+
[ -f "$f" ] || continue
26+
for static_clang_include in /opt/clang/lib/clang/*/include; do
27+
[ -d "$static_clang_include" ] || continue
28+
target="$static_clang_include/$(basename "$f")"
29+
if [ ! -e "$target" ]; then
30+
ln -sf "$f" "$target"
31+
fi
32+
done
33+
done
34+
done

.github/workflows/build_and_test.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,31 @@ jobs:
4242
ls -al /etc/alternatives/clang
4343
bazel cquery --output=starlark --starlark:expr="str(providers(target))" @bazel_tools//tools/cpp:current_cc_toolchain | sed 's/,/\n/g' | grep -C 5 clang
4444
45+
# Bazel tests
4546
- name: "Run `bazel build`"
4647
run: |
4748
bazel build -c opt //...
4849
4950
- name: "Run `bazel test`"
5051
run: |
5152
bazel test -c opt //...
53+
54+
# Frontend tests
55+
- name: Build OpenFHE
56+
run: |
57+
./.github/build_openfhe.sh
58+
59+
- name: Install Python 3.12
60+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
61+
with:
62+
python-version: "3.12"
63+
64+
- name: Install python package in editable mode
65+
run: |
66+
python -m pip install --upgrade pip
67+
# This should reuse the pre-built binaries from `bazel build` above.
68+
pip install -e ".[dev,python,openfhe]"
69+
70+
- name: Run Python frontend tests
71+
run: |
72+
pytest frontend/

.github/workflows/nightly.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ jobs:
2727
github.event_name == 'schedule'
2828
runs-on: ${{ matrix.runner }}
2929
strategy:
30+
fail-fast: false
3031
matrix:
3132
include:
3233
- name: linux-x86_64

.github/workflows/release.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ jobs:
8989
github.event.label.name == 'ci:wheels'
9090
runs-on: ${{ matrix.runner }}
9191
strategy:
92+
fail-fast: false
9293
matrix:
9394
include:
9495
- name: linux-x86_64

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ MODULE.bazel.lock
5858

5959
scripts/torch_ci/failure_logs
6060
scripts/torch_ci/models/*.mlir
61+
openfhe-install/
62+
openfhe-development/

frontend/BUILD

Lines changed: 5 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,14 @@
1-
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
2-
load("@heir//frontend:testing.bzl", "frontend_test")
31
load("@rules_python//python:py_library.bzl", "py_library")
4-
load("@rules_python//python:py_test.bzl", "py_test")
52

63
package(
74
default_applicable_licenses = ["@heir//:license"],
85
default_visibility = ["//visibility:public"],
96
)
107

118
DATA_DEPS = [
12-
"@cereal//:headers",
139
"@heir//tools:heir-opt",
1410
"@heir//tools:heir-translate",
15-
"@openfhe//:libopenfhe",
16-
"@openfhe//:headers",
17-
# copybara: openfhe_binfhe_headers
18-
# copybara: openfhe_core_headers
19-
# copybara: openfhe_pke_headers
2011
# copybara: python_runtime_headers
21-
"@rapidjson",
2212
]
2313

2414
# a single-source build dependency that gives the whole (non-test) source tree;
@@ -42,103 +32,8 @@ py_library(
4232
],
4333
)
4434

45-
py_test(
46-
name = "import_isolation_test",
47-
srcs = ["import_isolation_test.py"],
48-
tags = [
49-
# copybara: manual
50-
"notap",
51-
],
52-
deps = [
53-
":frontend",
54-
"@abseil-py//absl/testing:absltest",
55-
"@heir_pip_deps//numba",
56-
"@heir_pip_deps//numpy",
57-
"@heir_pip_deps//pybind11",
58-
],
59-
)
60-
61-
frontend_test(
62-
name = "e2e_test",
63-
srcs = ["e2e_test.py"],
64-
tags = [
65-
# copybara: manual
66-
"notap",
67-
],
68-
)
69-
70-
frontend_test(
71-
name = "loop_test",
72-
srcs = ["loop_test.py"],
73-
tags = [
74-
# copybara: manual
75-
"notap",
76-
],
77-
)
78-
79-
frontend_test(
80-
name = "mixed_bitwidth_test",
81-
srcs = ["mixed_bitwidth_test.py"],
82-
tags = [
83-
# copybara: manual
84-
"notap",
85-
],
86-
)
87-
88-
frontend_test(
89-
name = "tensor_test",
90-
srcs = ["tensor_test.py"],
91-
tags = [
92-
# copybara: manual
93-
"notap",
94-
],
95-
)
96-
97-
frontend_test(
98-
name = "tensor_loop_test",
99-
srcs = ["tensor_loop_test.py"],
100-
tags = [
101-
# copybara: manual
102-
"notap",
103-
],
104-
)
105-
106-
frontend_test(
107-
name = "cggi_test",
108-
srcs = ["cggi_test.py"],
109-
tags = [
110-
# copybara: manual
111-
"notap",
112-
],
113-
)
114-
115-
frontend_test(
116-
name = "cast_test",
117-
srcs = ["cast_test.py"],
118-
tags = [
119-
# copybara: manual
120-
"notap",
121-
],
122-
)
123-
124-
frontend_test(
125-
name = "unique_name_test",
126-
srcs = ["unique_name_test.py"],
127-
tags = [
128-
# copybara: manual
129-
"notap",
130-
],
131-
)
132-
133-
bzl_library(
134-
name = "testing_bzl",
135-
srcs = ["testing.bzl"],
136-
visibility = ["//visibility:public"],
137-
deps = ["@rules_python//python:defs_bzl"],
138-
)
139-
140-
py_library(
141-
name = "example",
142-
srcs = ["example.py"],
143-
deps = [":frontend"],
144-
)
35+
# Because tests require JIT-compiling generated code on the fly, and linking
36+
# with system-provided libs, we cannot run them inside bazel's hermetic C++
37+
# toolchain. Instead the tests are run as a separate CI test, after installing
38+
# the frontend package, using pytest to discover and run tests named
39+
# frontend/**/*_test.py

frontend/README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,24 +58,26 @@ auto-detected resources.
5858
- Defaults to `bazel-bin/tools/heir-{opt,translate}`.
5959
- Cf. `heir/backends/openfhe/config.py` for more details.
6060

61-
- OpenFHE installation locations (default to where `cmake` installs them in the
62-
OpenFHE development repo).
61+
- OpenFHE configuration overrides. Note: If any OpenFHE environment variable is
62+
set, BOTH `OPENFHE_LIB_DIR` and `OPENFHE_INCLUDE_DIR` must be provided
63+
(enforcing atomic overrides), or an error will be raised.
6364

6465
- `OPENFHE_LIB_DIR`: a string containing the directory containing the OpenFHE
65-
.so files. Usually `/usr/local/lib`
66+
.so files. Usually `/usr/local/lib` or `openfhe/lib`.
6667
- `OPENFHE_INCLUDE_DIR`: a colon-separated string of directories containing
67-
OpenFHE headers. Note this usually requires four different paths due to how
68-
OpenFHE organizes its imports, one for each of the three main subdirectories
69-
of the project.
68+
OpenFHE headers. For a standard installation, this usually requires four
69+
paths:
7070
- `/usr/local/include/openfhe`
7171
- `/usr/local/include/openfhe/binfhe`
7272
- `/usr/local/include/openfhe/core`
7373
- `/usr/local/include/openfhe/pke`
74-
- `OPENFHE_LINK_LIBS`: a colon-separated string of libraries to link against
75-
(without `lib` or `.so`). E.g., `"OPENFHEbinfhe:OPENFHEcore:OPENFHEpke"`.
74+
- `OPENFHE_LINK_LIBS`: a colon-separated string of libraries to link against.
75+
Accepts short names (e.g. `"openfhe"`) OR exact library filenames prefixed
76+
by a colon (e.g. `":libOPENFHEcore.so.1"`). Defaults to split libraries:
77+
`":libOPENFHEcore.so.1::libOPENFHEpke.so.1::libOPENFHEbinfhe.so.1"`.
7678
- `OPENFHE_INCLUDE_TYPE`: a string indicating the include path type to use
7779
(see options on `heir-translate --emit-openfhe`). Should be
78-
`install-relative` for a system-wide OpenFHE installation.
80+
`install-relative` for a system-wide or PyPI wheel OpenFHE installation.
7981

8082
## Formatting
8183

frontend/cibuildwheel.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"""Minimal (dependency-free) test of PyPI for cibuildwheel."""
2+
3+
from heir import compile
4+
from heir.mlir import I16, Secret
5+
from heir.backends.cleartext import CleartextBackend
6+
7+
8+
# Custom Pipeline Example
9+
def custom_example():
10+
print("Running custom pipeline example")
11+
12+
@compile(
13+
heir_opt_options=[
14+
"--mlir-to-secret-arithmetic",
15+
"--canonicalize",
16+
"--cse",
17+
],
18+
backend=CleartextBackend(),
19+
debug=True,
20+
)
21+
def custom(x: Secret[I16], y: Secret[I16]):
22+
return (x + y) * (x - y) + (x * y)
23+
24+
25+
# MLIR-input example
26+
def mlir_example():
27+
print("Running MLIR-input example")
28+
# Input should be a single function, just like normal MLIR input to heir-opt
29+
src = """
30+
func.func @myfunc(%a : i32 {secret.secret}, %b : i32) -> i32 {
31+
%sum = arith.addi %a, %b : i32
32+
return %sum : i32
33+
}
34+
"""
35+
# By passing mlir_str instead of using it to decorate a function,
36+
# we can skip the python parsing/type inference/etc stages.
37+
compile(
38+
mlir_str=src,
39+
scheme="bgv",
40+
backend=CleartextBackend(),
41+
debug=True,
42+
)
43+
44+
45+
def main():
46+
custom_example()
47+
mlir_example()
48+
49+
50+
if __name__ == "__main__":
51+
main()

0 commit comments

Comments
 (0)