Skip to content

flagcx: take the library from the installed package, not a source tree - #525

Draft
tengqm wants to merge 3 commits into
flagos-ai:mainfrom
tengqm:feat/flagcx-package-import
Draft

tengqm wants to merge 3 commits into
flagos-ai:mainfrom
tengqm:feat/flagcx-package-import

Conversation

@tengqm

@tengqm tengqm commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

The flagcx wheel ships the ctypes facade as flagcx.api, next to
libflagcx.so under the package's own lib/:

flagcx/_C.cpython-312-x86_64-linux-gnu.so
flagcx/api.py
flagcx/__init__.py
flagcx/lib/libflagcx.so

A backend that installs the wheel therefore has no source tree to point
FLAGCX_PATH at, and every place that reached for the FlagCX Python API
assumed one. The package root only re-exports the compiled bindings, so the
names below have to come from flagcx.api rather than flagcx.

The change is additive: flagcx.api becomes the primary import, and the
existing FLAGCX_PATH-driven resolution stays as the path for a source tree.
No import path is renamed and no new environment variable is introduced.

Imports

Three call sites imported plugin.interservice.flagcx_wrapper after appending
FLAGCX_PATH to sys.path. Each now tries flagcx.api first and falls back
to the wrapper. The fallback is what FLAGCX_PATH still guards, so a source
tree keeps working:

  • vllm_fl/distributed/device_communicators/flagcx.py
  • vllm_fl/distributed/kv_transfer/flagcx_connector.py
  • vllm_fl/dispatch/backends/vendor/sunrise/patch.py

The connector's ImportError message now names both shapes instead of telling
the reader to set FLAGCX_PATH.

Library resolution

FLAGCXLibrary already resolves the .so on its own — FLAGCX_PATH, then the
installed package's lib/, then a source build tree, then ldconfig — so the
hand-assembled <FLAGCX_PATH>/build/lib/libflagcx.so paths are gone. The
communicator still threads its library_path argument through for callers that
pass one; the connector called the same join with no argument, so it now calls
FLAGCXLibrary() and lets the ladder resolve it. That is also the fix for the
wheel-only case, where the old join produced os.path.join(None, ...).

FLAGCX_LIB_PATH is removed. It existed only to override the hand-built
path above; with the ladder in FLAGCXLibrary it has no job left, and keeping
it would mean carrying a second way to say what FLAGCX_PATH already says.

Backend selection

platform.py selected the flagcx dist backend on "FLAGCX_PATH" in os.environ, which is how a source tree announced itself. A wheel-only install
has no such variable, so it fell through to nccl. _flagcx_backend_enabled()
now accepts either shape: FLAGCX_PATH set, or the flagcx distribution
importable.

Test gates and docs

has_flagcx() in conftest.py and the two distributed test modules probed
only <FLAGCX_PATH>/build/lib/libflagcx.so. They now probe the installed
package first, and accept lib/libflagcx.so as well as build/lib/… so a
meson-layout source tree is not reported missing.

examples/disaggregated_serving_xpyd/run_flagcx_connector.md taught a source
build; it now installs the wheel and drops the FLAGCX_PATH exports, keeping
a sentence on how to point at a source build instead. The FLAGCX_PATH row in
vllm_fl/dispatch/README.md is reworded the same way.

Verification

End-to-end on metax124 (MACA 3.8.1.3, vLLM 0.24.0 +flagos empty wheel,
Qwen3-4B, TP=2): both ranks select backend=flagcx with no FLAGCX_*
variable set in the environment
— the wheel-only shape, which is the case
that previously fell through to nccl.

The flagcx wheel came from the vendor index, not a local build:
flagcx-0.14.0rc2.post2.dev4+maca3.8.1.3.20260914.g08ab373-cp312-cp312-linux_x86_64.whl
installed by pip with an empty direct_url.json, resolving
flagcx/lib/libflagcx.so from site-packages. The names imported here
(FLAGCXLibrary, buffer_type, flagcxComm_t, flagcxDataTypeEnum,
flagcxUniqueId, flagcxRedOpTypeEnum) are all defined in that wheel's
api.py.

Note for anyone reproducing this: the metax path additionally needs the vLLM
0.24.0 compatibility fixes, which are unrelated to this PR and tracked
separately (#377).

This PR was written in part with the assistance of generative AI.

The flagcx wheel ships the ctypes facade as flagcx.api next to
libflagcx.so under the package's lib/, so a backend that installs the
wheel has no source tree to point FLAGCX_PATH at. Import flagcx.api
first and keep plugin.interservice.flagcx_wrapper as the fallback for
the source-tree shape, and let FLAGCXLibrary resolve the .so itself
(FLAGCX_PATH, the installed package, a build tree, then ldconfig)
instead of assembling <FLAGCX_PATH>/build/lib/libflagcx.so by hand.

platform.py now selects the flagcx dist backend when the distribution
is importable, not only when FLAGCX_PATH is set: that variable is how a
source tree announced itself, and a wheel-only install has no such tree.
@github-actions github-actions Bot added the core label Sep 15, 2026
Comment on lines +41 to +48
buffer_type,
flagcxComm_t,
flagcxDataTypeEnum,
flagcxUniqueId,
flagcxRedOpTypeEnum,
)
_flagcx_available = True
except (ImportError, ModuleNotFoundError):
)
_flagcx_available = True
except (ImportError, ModuleNotFoundError):
_flagcx_available = False
except (ImportError, ModuleNotFoundError):
_flagcx_available = False
FLAGCXLibrary = None
buffer_type = None
The import switch covered the runtime code paths only. The unit-test gates
still keyed on FLAGCX_PATH, so a wheel-only install skipped the flagcx
tests, and the connector example still walked users through building the
library by hand.

Probe flagcx.api first in the three gates and keep the FLAGCX_PATH check
as the source-tree fallback, and turn the example's build-flagcx section
into a wheel install. The path append stays where the source-tree shape
needs it: it now runs only on the import fallback, so a wheel-only install
never touches sys.path.

FLAGCX_LIB_PATH goes away. FLAGCXLibrary already resolves the .so from
FLAGCX_PATH, the installed package, a build tree and ldconfig, so the
variable was an override that nothing but the connector ever read.
@tengqm
tengqm force-pushed the feat/flagcx-package-import branch 2 times, most recently from 758c996 to 7cd9668 Compare September 15, 2026 16:14
The example installed the wheel with a bare `pip install flagcx`, which
cannot resolve: flagcx is not on PyPI. It is built per vendor and published
to that vendor's own FlagOS index, so the index has to be passed.

Leave the vendor as a placeholder rather than naming one. Each index carries
only its own builds and not every vendor has published a wheel yet, so an
example naming a single vendor invites reading it as the one index every
package lives on.
@tengqm
tengqm force-pushed the feat/flagcx-package-import branch from 7cd9668 to 626bf8d Compare September 15, 2026 16:16
@tengqm
tengqm marked this pull request as draft September 15, 2026 16:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants