Repository navigation
fix(rocm): install libcuopt.so and libmps_parser.so into the wheels - #5
Merged
awelling2801 merged 1 commit intoOct 6, 2026
Conversation
Both the librocopt and rocopt wheels are missing compiled shared
libraries that their own Python loaders / RPATH=$ORIGIN extension
modules expect to find bundled alongside them, so `import cuopt`
fails on a clean install with errors like:
libmps_parser.so: cannot open shared object file
- python/libcuopt/CMakeLists.txt: the USE_ROCM branch returned early
with zero install() rules, so libcuopt.so (already compiled by the
C++ build step) never made it into the wheel at all. load.py's
_load_wheel_installation() looks for it at <pkg>/lib64/libcuopt.so,
matching the layout of NVIDIA's own CUDA wheel; this adds the
missing install(FILES ...) call for that exact path, with a
FATAL_ERROR guard if the prebuilt .so is missing so this fails
loudly at build time instead of silently shipping an empty wheel.
- python/cuopt/cuopt/linear_programming/data_model/CMakeLists.txt:
data_model_wrapper's compiled extension links against the
cuopt::mps_parser IMPORTED target but never installs it, even
though WheelHelpers.cmake's install_aliased_imported_targets()
exists in this repo for exactly this purpose (and is otherwise
unused anywhere in the codebase). This adds the missing call,
installing libmps_parser.so next to data_model_wrapper's compiled
module where its INSTALL_RPATH=$ORIGIN expects to find it.
Verified against the actual published wheels
(pypi.amd.com/rocm-7.2.3/packages/rocopt/): librocopt-1.0.0 currently
contains no compiled binaries at all (confirmed via full wheel content
listing), and rocopt-1.0.0's data_model_wrapper*.so has
RPATH=$ORIGIN per readelf -d, with no libmps_parser.so present
alongside it in the wheel. Manually placing libmps_parser.so at that
exact path was confirmed to resolve the import error.
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.
Problem
Installing the published ROCm wheels (
rocopt-mps-parser,librocopt,rocopt,rocopt-server,rocopt-sh-client) frompypi.amd.comand runningimport cuoptfails on a clean environment:Even if that's patched around, the next failure is the same thing for
libcuopt.so. Neither library is actually present anywhere in the published wheels.Root cause
Two separate missing
install()rules, both ROCm-specific:1.
python/libcuopt/CMakeLists.txt— theUSE_ROCMbranch returns early with zero install rules:libcuopt.sois already compiled by the C++ build step (cpp/build/libcuopt.so), but this function never copies it into the wheel.load.py's_load_wheel_installation()looks for it at<package>/lib64/libcuopt.so— exactly matching the layout of NVIDIA's own CUDA wheel (libcuopt-cu12, which bundleslibcuopt/lib64/libcuopt.so) — but that path is never populated on the ROCm side. This is why the project's own Docker image (dockerfile.rocm) works around it by hardcodingcpp/build/ontoLD_LIBRARY_PATHinstead of relying on the wheel being self-contained.2.
python/cuopt/cuopt/linear_programming/data_model/CMakeLists.txt—data_model_wrapper's compiled extension links against thecuopt::mps_parserIMPORTED target but never installs it:WheelHelpers.cmakealready definesinstall_aliased_imported_targets()for exactly this purpose ("Making libraries available inside wheels by installing the associated targets") — it's just never called anywhere in the repo, on either the CUDA or ROCm path.Fix
install(FILES ...)call forlibcuopt.soinpython/libcuopt/CMakeLists.txt, with aFATAL_ERRORguard if the prebuilt.sodoesn't exist yet (fail loudly at build time instead of silently shipping an empty wheel).install_aliased_imported_targets(TARGETS cuopt::mps_parser DESTINATION cuopt/linear_programming/data_model)call solibmps_parser.solands next todata_model_wrapper's compiled module, matching itsINSTALL_RPATH=$ORIGIN.Verification
Confirmed against the actual published wheels at
pypi.amd.com/rocm-7.2.3/packages/rocopt/:librocopt-1.0.0contains no compiled binaries at all (full wheel content listing, ~10KB total).rocopt-1.0.0'sdata_model_wrapper*.sohasRPATH=$ORIGINperreadelf -d, with nolibmps_parser.soanywhere in the wheel.libmps_parser.soat that exact path (as a local shim wheel layered on top) was confirmed to resolve the import error, isolating this as the precise root cause.I wasn't able to do a full ROCm build in this environment to produce a rebuilt wheel end-to-end, so this PR is scoped to the CMake install-rule fix itself; CI should pick it up on rebuild.
Related
Also checked
python/cuopt/cuopt/linear_programming/internals/CMakeLists.txt, which has the samecuopt::cuoptlinking pattern without an explicit install. This one appears to be fine as-is:cuopt/__init__.pyalready doesimport libcuopt; libcuopt.load_library()before importinginternals/linear_programming, which preloadslibcuopt.sointo the process viactypes.CDLLahead of time (the same pattern already used forlibrmm/libraft/rapids_logger). Once libcuopt.so actually ships (fix #1 above), that preload should letinternals'sDT_NEEDED=libcuopt.soresolve against the already-loaded instance without needing its own bundled copy.Made with Cursor