Skip to content

Commit d7acbcf

Browse files
committed
fix(build-lm): switch from CMake to Bazel (upstream primary build system)
CMake's ExternalProject_Add dep chain failed to resolve flatc/protoc ordering when invoked standalone. The inner cmake expects the outer orchestrator to have built host tools first. Bazel is LiteRT-LM's primary build system and handles all dependency resolution natively. GitHub runners ship bazelisk. Strategy: bazelisk build //c:engine --compilation_mode=opt --copt=-fPIC This produces the C engine static archive with all transitive deps resolved. Post-link step then bundles it into a shared library using the system linker, same version-script/export-list approach as before.
1 parent e780c58 commit d7acbcf

1 file changed

Lines changed: 54 additions & 50 deletions

File tree

.github/workflows/build-litert-lm.yml

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
name: Build libLiteRtLmC
22

3-
# Builds the LiteRT-LM C engine as a shared library from source.
4-
# Strategy: build the project normally (all static archives), then post-link
5-
# them into a single shared library. This avoids patching CMake targets.
3+
# Builds the LiteRT-LM C engine as a shared library using Bazel (the
4+
# upstream's primary build system). CMake was too fragile with its
5+
# ExternalProject dep chain; Bazel handles everything natively.
6+
#
7+
# Strategy: build //c:engine as a static archive via Bazel, then manually
8+
# link it (plus deps) into a shared library with the system linker.
69
on:
710
workflow_dispatch:
811
inputs:
@@ -24,30 +27,30 @@ jobs:
2427
steps:
2528
- uses: actions/checkout@v4
2629

27-
- name: install build deps
28-
run: |
29-
sudo apt-get update && sudo apt-get install -y \
30-
cmake ninja-build g++ git
31-
3230
- name: clone litert-lm
3331
run: |
3432
git clone --depth=1 --branch=${{ env.LITERT_LM_TAG }} \
3533
https://github.com/google-ai-edge/litert-lm.git /tmp/litert-lm
3634
37-
# Use the OUTER CMakeLists.txt — it orchestrates ExternalProject deps
38-
# (protobuf, abseil, flatbuffers, TFLite, etc.) in the right order.
39-
# PIC flags are critical: every .a must be position-independent to
40-
# link into a .so later.
41-
- name: cmake configure (outer)
35+
- name: bazel build C engine (static)
36+
working-directory: /tmp/litert-lm
37+
run: |
38+
bazelisk build //c:engine --compilation_mode=opt --copt=-fPIC \
39+
--action_env=CC=gcc --action_env=CXX=g++ \
40+
2>&1 | tail -30
41+
42+
- name: locate built artifacts
43+
id: artifacts
44+
working-directory: /tmp/litert-lm
4245
run: |
43-
cmake -S /tmp/litert-lm -B /tmp/litert-lm/build \
44-
-DCMAKE_BUILD_TYPE=Release \
45-
-DCMAKE_C_FLAGS="-fPIC" \
46-
-DCMAKE_CXX_FLAGS="-fPIC" \
47-
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
46+
echo "=== engine .a ==="
47+
ENGINE_A=$(find bazel-bin/c -name '*.a' -type f | head -1)
48+
echo "engine_a=$ENGINE_A" >> $GITHUB_OUTPUT
49+
ls -la "$ENGINE_A" 2>/dev/null || echo "No .a found"
4850
49-
- name: cmake build (full project)
50-
run: cmake --build /tmp/litert-lm/build -j$(nproc)
51+
echo "=== all .a under bazel-bin ==="
52+
find bazel-bin -name '*.a' -type f | wc -l
53+
find bazel-bin -name '*.a' -type f | head -20
5154
5255
- name: create version script
5356
run: |
@@ -61,29 +64,30 @@ jobs:
6164
EOF
6265
6366
- name: post-link shared library
67+
working-directory: /tmp/litert-lm
6468
run: |
65-
BUILD=/tmp/litert-lm/build
66-
67-
# The C engine static lib (our API surface)
68-
ENGINE_A=$(find $BUILD -name 'libc_engine.a' -type f | head -1)
69-
echo "engine lib: $ENGINE_A"
70-
71-
# All other static archives (deps)
72-
ALL_A=$(find $BUILD -name '*.a' -type f ! -name 'libc_engine.a' | sort)
69+
ENGINE_A="${{ steps.artifacts.outputs.engine_a }}"
70+
if [ -z "$ENGINE_A" ] || [ ! -f "$ENGINE_A" ]; then
71+
echo "::error::Engine .a not found"
72+
exit 1
73+
fi
74+
75+
# Collect all static deps from bazel-bin
76+
ALL_A=$(find bazel-bin -name '*.a' -type f ! -path "$ENGINE_A" | sort)
7377
echo "total .a files: $(echo "$ALL_A" | wc -l)"
7478
75-
# Link: whole-archive the engine (so all litert_lm_* symbols survive),
76-
# regular-link the deps (only pull what's referenced).
7779
g++ -shared -o /tmp/libLiteRtLmC.so \
7880
-Wl,--version-script=/tmp/litert_lm_exports.map \
79-
-Wl,--whole-archive $ENGINE_A -Wl,--no-whole-archive \
81+
-Wl,--whole-archive "$ENGINE_A" -Wl,--no-whole-archive \
8082
$ALL_A \
8183
-Wl,--allow-multiple-definition \
8284
-lstdc++ -lpthread -ldl -lm
8385
8486
echo "=== output ==="
8587
ls -la /tmp/libLiteRtLmC.so
8688
echo "litert_lm_* symbols:"
89+
nm -D --defined-only /tmp/libLiteRtLmC.so | grep 'litert_lm_' | head -10
90+
echo "total litert_lm_* symbols:"
8791
nm -D --defined-only /tmp/libLiteRtLmC.so | grep -c 'litert_lm_'
8892
8993
- uses: actions/upload-artifact@v4
@@ -99,47 +103,47 @@ jobs:
99103
steps:
100104
- uses: actions/checkout@v4
101105

102-
- name: install build deps
103-
run: brew install cmake ninja
104-
105106
- name: clone litert-lm
106107
run: |
107108
git clone --depth=1 --branch=${{ env.LITERT_LM_TAG }} \
108109
https://github.com/google-ai-edge/litert-lm.git /tmp/litert-lm
109110
110-
- name: cmake configure (outer)
111+
- name: bazel build C engine (static)
112+
working-directory: /tmp/litert-lm
111113
run: |
112-
cmake -S /tmp/litert-lm -B /tmp/litert-lm/build \
113-
-DCMAKE_BUILD_TYPE=Release \
114-
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
114+
bazelisk build //c:engine --compilation_mode=opt \
115+
2>&1 | tail -30
115116
116-
- name: cmake build (full project)
117-
run: cmake --build /tmp/litert-lm/build -j$(sysctl -n hw.ncpu)
117+
- name: locate built artifacts
118+
id: artifacts
119+
working-directory: /tmp/litert-lm
120+
run: |
121+
ENGINE_A=$(find bazel-bin/c -name '*.a' -type f | head -1)
122+
echo "engine_a=$ENGINE_A" >> $GITHUB_OUTPUT
123+
ls -la "$ENGINE_A" 2>/dev/null || echo "No .a found"
124+
find bazel-bin -name '*.a' -type f | wc -l
118125
119126
- name: create export list
120127
run: |
121128
grep -E 'LITERT_LM_C_API_EXPORT' /tmp/litert-lm/c/engine.h -A1 | \
122129
grep 'litert_lm_' | sed 's/.*\(litert_lm_[a-z_]*\).*/\1/' | \
123130
sed 's/^/_/' | sort -u > /tmp/litert_lm_exports.txt
124-
echo "export count: $(wc -l < /tmp/litert_lm_exports.txt)"
125-
cat /tmp/litert_lm_exports.txt
131+
echo "exports: $(wc -l < /tmp/litert_lm_exports.txt)"
126132
127133
- name: post-link shared library
134+
working-directory: /tmp/litert-lm
128135
run: |
129-
BUILD=/tmp/litert-lm/build
130-
131-
ENGINE_A=$(find $BUILD -name 'libc_engine.a' -type f | head -1)
132-
echo "engine lib: $ENGINE_A"
133-
134-
ALL_A=$(find $BUILD -name '*.a' -type f ! -name 'libc_engine.a' | sort)
136+
ENGINE_A="${{ steps.artifacts.outputs.engine_a }}"
137+
ALL_A=$(find bazel-bin -name '*.a' -type f ! -path "$ENGINE_A" | sort)
135138
echo "total .a files: $(echo "$ALL_A" | wc -l)"
136139
137140
clang++ -dynamiclib -o /tmp/libLiteRtLmC.dylib \
138141
-Wl,-exported_symbols_list,/tmp/litert_lm_exports.txt \
139-
-Wl,-all_load $ENGINE_A \
142+
-Wl,-all_load "$ENGINE_A" \
140143
$ALL_A \
141144
-framework Foundation -framework Metal -framework CoreFoundation \
142-
-lstdc++ -lpthread -ldl -lm
145+
-lstdc++ -lpthread -ldl -lm \
146+
2>&1 | tail -20
143147
144148
echo "=== output ==="
145149
ls -la /tmp/libLiteRtLmC.dylib

0 commit comments

Comments
 (0)