Repository navigation
recipe: xgboost 3.4.1 - #125
Merged
Merged
Conversation
Gradient boosting, the lightgbm sibling — same ctypes-C-API shape, very different build system: a custom hatchling backend (packager/) that drives CMake itself and reads no CMAKE_ARGS. The mobile.patch teaches it three things: FORGE_CMAKE_ARGS injection (appended after its own args so recipe toolchain/OpenMP flags win), FORGE_LIB_NAME (its _lib_name() switches on the BUILD HOST platform, so a macOS-hosted cross build would look for libxgboost.dylib while CMake produced .so), and — critically — disabling its silent retry-WITHOUT-OpenMP on any cmake failure whenever FORGE_CMAKE_ARGS is set (a broken cross setup would otherwise 'succeed' as a degraded build). Plus the lightgbm ctypes-on-iOS treatment: lib named .so on iOS with the VERSION/SOVERSION symlink chain dropped, and libpath.py taught the 'ios' and 'android' sys.platform values (absent upstream entirely — it would fail before ctypes even loaded) and the .fwork pointer form. iOS single-threaded (USE_OPENMP=OFF); Android real OpenMP (dynamic libomp.so -> flet-libomp, same as lightgbm). armeabi-v7a excluded: upstream assumes 64-bit size_t (narrowing hard error in quantile.cc) and ships no 32-bit builds; lightgbm covers that arch. The sdist variant has no nvidia-nccl dep (that marker lives in the cp-wheel variants only). 5/5 applicable slices green; patched sdist proven on desktop CPython 3.14. Tests mirror lightgbm's: native xgb.train (no sklearn dep), UBJSON save/load roundtrip, and pred_contribs TreeSHAP reconstructing the margin.
3.4 replaced the custom hatchling backend with scikit-build-core, so the three backend hunks the 3.3.0 recipe needed are gone and CMAKE_ARGS carries the cross toolchain. What remains is running under Flet: - iOS: name the library .so so serious_python framework-izes it, and let libpath.py find the .fwork pointer. - Android: Flet moves the .so into the APK's native lib dir, so libpath.py falls back to the bare soname. _py_version() reads VERSION through importlib.resources: site-packages ships as a zip, and the old __file__ open() broke every `import xgboost` there. - No SOVERSION on mobile, so the soname matches the shipped file. Android links the NDK's libomp (flet-libomp); iOS builds without OpenMP. armeabi-v7a stays excluded: quantile.cc still narrows into a 32-bit size_t. Tests add a desktop-trained .joblib classifier, loaded without scikit-learn, and the OpenMP flag per platform. README and the iris-explainer example cover training on a desktop and predicting on the device. [skip ci]
- libpath.py: flet's iOS runtime reports "ios" on 3.12 too, so iOS gets its own branch and upstream's darwin branch stays byte-identical. - README: with scikit-learn installed but not extracted, `import xgboost` itself fails on Android (xgboost imports sklearn eagerly and catches only ImportError). List what an unpickled model can and cannot do without scikit-learn, and that scikit-learn pickles need the version pypi.flet.dev carries. Thread count follows the pickled n_jobs. An APK carries the unpacked size. - Test: the booster thread cap works on the desktop-trained model. - Example: the load error keeps the exception type and path. [skip ci]
- forge-error-catalogue: a meta-only extract_packages fix passes CI and breaks consumers; patch a package's own __file__ read to importlib.resources instead. xgboost as a ctypes-by-__file__ instance. flet's iOS 3.12 reports sys.platform "ios", not "darwin". - new-mobile-recipe: the in-package ctypes C-API library shape. - local-recipe-testing: finishing an iOS build by hand when a new Xcode rejects flet's 13.0 deployment target; flet 1.0.3 bundles 3.14. [skip ci]
Flet calls a handler with no parameters without the event, so show() needs no placeholder argument.
# Conflicts: # .claude/skills/local-recipe-testing/SKILL.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds a recipe for xgboost 3.4.1 — gradient-boosted trees, the model family behind most tabular ML. Requested in flet#6912, to load
.joblibmodels on a phone.Upstream ships no Android or iOS wheels, and the PyPI wheels are host-only, so this is the only way to run a desktop-trained XGBoost model inside a Flet app.
Recipe shape
XGBoost 3.4 replaced its custom hatchling backend with scikit-build-core, so this is the
soxr/duckdbshape:CMAKE_ARGScarries the cross toolchain, and the three backend hunks an earlier 3.3.0 draft of this recipe needed are gone. The Python package loadslibxgboostthroughctypesfrom a path built off__file__, and that is what the onemobile.patchis about:.fworkpointer;libpath.pygets aniosbranch that follows it (flet's iOS runtime reportsioson 3.12 too), and upstream'sdarwinbranch stays untouched..sointo the APK's native library directory, solibpath.pyfalls back to the bare soname when no on-disk candidate exists.SOVERSIONis dropped so the soname matches the shipped file.import xgboostcrashed on Android under Flet 0.86+ withNotADirectoryError: …/sitepackages.zip/xgboost/VERSION:_c_api._py_version()opens the version file through__file__on every import. The patch reads it throughimportlib.resources, which zipimport serves, so consumers need noextract_packagesentry. A meta.yamlextract_packageswould have made CI green while every consumer app still crashed — that copy only reaches the test app.The same zip has a consumer-facing consequence the README leads its Install section with:
import xgboostimports scikit-learn whenever it is installed, so an Android app that has scikit-learn for any reason must list it inextract_packages, orimport xgboostfails.Android builds with the NDK's OpenMP and links
libomp.so(flet-libomp); iOS has no OpenMP runtime and builds withUSE_OPENMP=OFF, which upstream supports.armeabi-v7ais excluded: 3.4.1 still fails atquantile.cc:39, narrowing into a 32-bitsize_t.Validation
DT_NEEDEDis bionic +libc++_shared.so+libomp.so, sonamelibxgboost.so, everyLOADaligned0x4000; iOS links only libc++/libSystem.mobile_test_pythons=ALL: run 37148157624, then run 37167791098 on this exact tree after a claim audit. 5 passed / EXIT 0 on device in every leg of both.iris-explainerexample (flet 1.0.3) runs on an Android arm64 emulator and the iOS Simulator: it loads a desktop-trained.joblibfrom assets without scikit-learn, and its predictions and TreeSHAP contributions match the desktop's to two decimals on both. A prediction plus explanation takes 0.5–3 ms on the emulator and 0.6 ms on the simulator.flet build apkwithouttarget_archfails withNo matching distribution found for xgboost==3.4.1on armeabi-v7a, as the README warns.Changes
recipes/xgboost/—meta.yaml, one patch, 5 on-device tests (incl. a 7.9 KB desktop-trained.joblibfixture loaded without scikit-learn, a booster thread cap, and the OpenMP flag per platform),README.md, and the example (pinned to flet 1.0.3)..claude/skills/— the zip-safeimportlib.resourcesfix for__file__data reads (and why meta-onlyextract_packagesis a trap), the in-package ctypes-library recipe shape, and the local Xcode 27 iOS deployment-target workaround.Consumer notes
A bare
XGBClassifier/XGBRegressorsaved withjoblibloads and predicts on device without scikit-learn; aPipelineneeds scikit-learn as well. On Android XGBoost uses every core by default, on iOS one.import xgboostbrings scipy, which is most of the size. Details, including model-version compatibility and thetarget_archline, are in the recipe README.