mirror of
https://github.com/facebook/proxygen.git
synced 2026-10-30 05:48:31 +03:00
Summary:
Changes to support the thrift-py-deprecated to thrift-python migration in the OSS build environment.
Changes:
1. CMakeLists.txt — Complete migration to thrift-python:
- Remove include(FBThriftPyLibrary), all add_fbthrift_py_library() targets
- Add 15 add_fbthrift_python_library() targets with correct NAMESPACE
values matching mstch_python generator output paths
- Add all transitive thrift deps (fb303, common, mpls, Address, link,
prbs, io_stats, fboss, bcm_config, asic_config)
- Key insight: NAMESPACE must be <namespace_py3>.<basename> to match
the generator's output directory structure
2. Consumer cmake files — switch to add_fb_thrift_python_executable:
- AsicConfigV2ConfigCli.cmake (+ add wedge800bact.py to SOURCES)
- PlatformMappingGenUnitTest.cmake
- PlatformMappingGenNoRegressionTest.cmake
- PlatformMappingV2ConfigCli.cmake
3. Address.thrift —
- Replace `package;` with `package "facebook.com/network/address"`
- Remove thrift.AllowLegacyMissingUris (unnecessary with non-empty package)
- Required because struct "Address" collides with module name "Address"
when package is empty
4. CMakeLists.txt — Detect Python sysconfig -march flag and apply to
CMAKE_CXX_FLAGS to avoid F14LinkCheck ABI mismatch with folly-python.
5. run-getdeps.py — detect -march flag from Python sysconfig and propagate
to CXXFLAGS for all dependency builds. Required because Cython extensions
inherit -march=x86-64-v2 from Python 3.12 sysconfig on CentOS Stream 9,
but cmake does not.
8. Dockerfiles — install Cython, wheel, auditwheel, patchelf, setuptools,
filelock for building folly-python/fbthrift-python Cython extensions and
wheels. Install Python 3.12 as system default on CentOS (required >= 3.10).
OK : 6
FAILED : 0
SKIPPED : 0 TIMEOUT : 0
./bin/run_test.py link --agent-run-mode multi_switch --hw-agent-bin-path /opt/fboss/bin/fboss_hw_agent-sai_impl --config /opt/fboss/share/link_test_configs/montblanc.materialized_JSON --qsfp-config /opt/fboss/share/qsfp_test_configs/montblanc.materialized_JSON --filter AgentEnsembleQsfpFsdbTest.* 2>&1 | tee "coldboot_Test.log"
...
Removed '/etc/systemd/system/multi-user.target.wants/fboss_hw_agent_oss@0.service'.
Removed '/etc/systemd/system/fboss_hw_agent_oss@0.service'.
Cleaning up qsfp_service_oss
Cleaning up fsdb_service_oss
Cleaning up FBOSS HW Agent Service for index=0...
Running all tests took 0:12:14.758873 between 2026-03-31 14:07:59.506379 and 2026-03-31 14:20:14.265252
[ OK ] warm_boot.AgentEnsembleQsfpFsdbTest.tcvr (33887 ms)
[ OK ] warm_boot.AgentEnsembleQsfpFsdbTest.phy (33943 ms)
[ OK ] warm_boot.AgentEnsembleQsfpFsdbTest.portState (25910 ms)
[ OK ] warm_boot.AgentEnsembleQsfpFsdbTest.portStateWithResetHold (53598 ms)
OK : 4
FAILED : 0
SKIPPED : 0
TIMEOUT : 0
[root@fboss330347219.ash6 /opt/fboss]# ./bin/run_test.py sai_agent --agent-run-mode multi_switch --num-npus 2 --hw-agent-bin-path /opt/fboss/bin/fboss_hw_agent-sai_impl --filter '*AgentEmpty*:*Vlan*' --config /opt/fboss/share/hw_test_configs/montblanc.agent.materialized_JSON --qsfp-config /opt/fboss/share/qsfp_test_configs/montblanc.materialized_JSON --skip-known-bad-tests "brcm/13.3.0.0_dnx_odp/13.3.0.0_dnx_odp/jericho3" 2>&1 | tee "test_output_$(date +%Y%m%d_%H%M%S).log"
...
Failed to stop fboss_hw_agent@0.service: Unit fboss_hw_agent@0.service not loaded.
Failed to stop fboss_hw_agent_for_testing_0.service: Unit fboss_hw_agent_for_testing_0.service not loaded.
Removed '/etc/systemd/system/multi-user.target.wants/fboss_hw_agent_oss@0.service'.
Removed '/etc/systemd/system/fboss_hw_agent_oss@0.service'.
Failed to stop fboss_hw_agent@1.service: Unit fboss_hw_agent@1.service not loaded.
Failed to stop fboss_hw_agent_for_testing_1.service: Unit fboss_hw_agent_for_testing_1.service not loaded.
Removed '/etc/systemd/system/multi-user.target.wants/fboss_hw_agent_oss@1.service'.
Removed '/etc/systemd/system/fboss_hw_agent_oss@1.service'.
Cleaning up FBOSS HW Agent Service for index=0...
Cleaning up FBOSS HW Agent Service for index=1...
Running all tests took 0:02:01.342550 between 2026-03-27 15:48:31.906896 and 2026-03-27 15:50:33.249446
[ OK ] warm_boot.AgentEmptyTest.CheckInit (13025 ms)
[ OK ] warm_boot.AgentEmptyVoqTest.CheckInit (12780 ms)
OK : 2
FAILED : 0
SKIPPED : 0
TIMEOUT : 0
```
Reviewed By: joseph5wu
Differential Revision: D98059537
fbshipit-source-id: 849a9699d0f73fde30ecceb07f60e0a210d51344
333 lines
13 KiB
CMake
333 lines
13 KiB
CMake
# Copyright (c) Facebook, Inc. and its affiliates.
|
||
|
||
include(FBCMakeParseArgs)
|
||
include(FBPythonBinary)
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# thrift-python runtime discovery
|
||
# ---------------------------------------------------------------------------
|
||
# thrift_types.py (generated by mstch_python) needs two C-extension packages
|
||
# at runtime:
|
||
# 1. thrift.python – from the pip-installed fbthrift-python wheel
|
||
# 2. folly – from folly-python site-packages
|
||
#
|
||
# Because these are C extensions (.so), they CANNOT be loaded from inside a
|
||
# Python zip archive. Any executable that transitively depends on a
|
||
# thrift-python library MUST use TYPE dir (not the default zipapp).
|
||
#
|
||
# Call fb_find_thrift_python_runtime() once at configure time to locate the
|
||
# site-packages directories. Then use add_fb_thrift_python_executable()
|
||
# instead of add_fb_python_executable() for targets that import thrift_types.
|
||
# ---------------------------------------------------------------------------
|
||
|
||
macro(fb_find_thrift_python_runtime)
|
||
if(NOT DEFINED _FB_THRIFT_PYTHON_RUNTIME_FOUND)
|
||
# Ensure Python3 is found so we can use ${Python3_EXECUTABLE}
|
||
if(NOT Python3_EXECUTABLE)
|
||
find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
||
endif()
|
||
|
||
# Derive the getdeps install root (where all dependencies are installed).
|
||
# getdeps sets GETDEPS_INSTALL_DIR; fall back to CMAKE_INSTALL_PREFIX/..
|
||
if(DEFINED ENV{GETDEPS_INSTALL_DIR})
|
||
set(_getdeps_root "$ENV{GETDEPS_INSTALL_DIR}")
|
||
else()
|
||
get_filename_component(_getdeps_root "${CMAKE_INSTALL_PREFIX}/.." ABSOLUTE)
|
||
endif()
|
||
message(STATUS "getdeps install root: ${_getdeps_root}")
|
||
|
||
# --- thrift.python (from pip-installed fbthrift-python wheel) ---
|
||
# Detect via import thrift.python.types — this module only exists in
|
||
# fbthrift-python, not in Apache Thrift, so it's an unambiguous check.
|
||
# If not available, auto-install the wheel from getdeps build output.
|
||
execute_process(
|
||
COMMAND "${Python3_EXECUTABLE}" -c
|
||
"import thrift.python.types; import thrift, os; print(os.path.dirname(os.path.dirname(thrift.__file__)))"
|
||
OUTPUT_VARIABLE THRIFT_PYTHON_SITE_PACKAGES
|
||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||
ERROR_QUIET
|
||
RESULT_VARIABLE _thrift_result
|
||
)
|
||
if(NOT _thrift_result EQUAL 0 OR NOT THRIFT_PYTHON_SITE_PACKAGES)
|
||
# Not pip-installed yet — auto-install from getdeps build output
|
||
file(GLOB _fbthrift_wheels
|
||
"${_getdeps_root}/fbthrift-python/share/thrift/wheels/*.whl"
|
||
)
|
||
if(_fbthrift_wheels)
|
||
list(GET _fbthrift_wheels 0 _fbthrift_whl)
|
||
message(STATUS "Auto-installing fbthrift-python wheel: ${_fbthrift_whl}")
|
||
execute_process(
|
||
COMMAND "${Python3_EXECUTABLE}" -m pip install --no-deps "${_fbthrift_whl}"
|
||
RESULT_VARIABLE _pip_result
|
||
)
|
||
if(_pip_result EQUAL 0)
|
||
execute_process(
|
||
COMMAND "${Python3_EXECUTABLE}" -c
|
||
"import thrift.python.types; import thrift, os; print(os.path.dirname(os.path.dirname(thrift.__file__)))"
|
||
OUTPUT_VARIABLE THRIFT_PYTHON_SITE_PACKAGES
|
||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||
ERROR_QUIET
|
||
RESULT_VARIABLE _thrift_result
|
||
)
|
||
endif()
|
||
endif()
|
||
endif()
|
||
|
||
if(THRIFT_PYTHON_SITE_PACKAGES)
|
||
message(STATUS "Found thrift-python runtime: ${THRIFT_PYTHON_SITE_PACKAGES}")
|
||
endif()
|
||
if(NOT THRIFT_PYTHON_SITE_PACKAGES)
|
||
message(WARNING
|
||
"thrift-python runtime not found. "
|
||
"Searched: ${_getdeps_root}/fbthrift-python/share/thrift/wheels/*.whl "
|
||
"pip install the fbthrift-python wheel before configuring the project.")
|
||
endif()
|
||
|
||
# --- folly (from folly-python site-packages) ---
|
||
# folly-python doesn't produce a wheel; it installs directly to
|
||
# a site-packages directory under its getdeps prefix.
|
||
execute_process(
|
||
COMMAND "${Python3_EXECUTABLE}" -c
|
||
"import folly, os; print(os.path.dirname(os.path.dirname(folly.__file__)))"
|
||
OUTPUT_VARIABLE FOLLY_PYTHON_SITE_PACKAGES
|
||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||
ERROR_QUIET
|
||
RESULT_VARIABLE _folly_result
|
||
)
|
||
if(NOT _folly_result EQUAL 0)
|
||
# Search the getdeps install prefix for folly-python site-packages
|
||
file(GLOB _folly_sp_dirs
|
||
"${_getdeps_root}/folly-python/lib64/python*/site-packages"
|
||
"${_getdeps_root}/folly-python/lib/python*/site-packages"
|
||
)
|
||
foreach(_sp IN LISTS _folly_sp_dirs)
|
||
if(EXISTS "${_sp}/folly/__init__.py")
|
||
set(FOLLY_PYTHON_SITE_PACKAGES "${_sp}")
|
||
break()
|
||
endif()
|
||
endforeach()
|
||
if(FOLLY_PYTHON_SITE_PACKAGES)
|
||
message(STATUS "Found folly-python runtime (via prefix): ${FOLLY_PYTHON_SITE_PACKAGES}")
|
||
else()
|
||
message(WARNING
|
||
"folly-python runtime not found. "
|
||
"Searched: ${_getdeps_root}/folly-python/lib*/python*/site-packages "
|
||
"Ensure folly-python is built.")
|
||
endif()
|
||
else()
|
||
message(STATUS "Found folly-python runtime: ${FOLLY_PYTHON_SITE_PACKAGES}")
|
||
endif()
|
||
|
||
set(_FB_THRIFT_PYTHON_RUNTIME_FOUND TRUE CACHE INTERNAL "thrift-python runtime discovery completed")
|
||
set(THRIFT_PYTHON_SITE_PACKAGES "${THRIFT_PYTHON_SITE_PACKAGES}" CACHE INTERNAL "thrift-python site-packages path")
|
||
set(FOLLY_PYTHON_SITE_PACKAGES "${FOLLY_PYTHON_SITE_PACKAGES}" CACHE INTERNAL "folly-python site-packages path")
|
||
endif()
|
||
endmacro()
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# add_fbthrift_python_library()
|
||
# ---------------------------------------------------------------------------
|
||
# Generate a thrift-python library from a thrift file.
|
||
# Analogous to add_fbthrift_py_library() but uses the mstch_python generator
|
||
# (--gen mstch_python) which produces thrift_types.py instead of ttypes.py.
|
||
#
|
||
# Unlike add_fbthrift_py_library(), this does NOT depend on FBThrift::thrift_py
|
||
# (the legacy pure-Python runtime). The thrift-python runtime (thrift.python
|
||
# and folly) are C extensions resolved at runtime via symlinks — see
|
||
# add_fb_thrift_python_executable().
|
||
# ---------------------------------------------------------------------------
|
||
function(add_fbthrift_python_library LIB_NAME THRIFT_FILE)
|
||
# Parse the arguments
|
||
set(one_value_args NAMESPACE THRIFT_INCLUDE_DIR)
|
||
set(multi_value_args SERVICES DEPENDS OPTIONS)
|
||
fb_cmake_parse_args(
|
||
ARG "" "${one_value_args}" "${multi_value_args}" "${ARGN}"
|
||
)
|
||
|
||
if(NOT DEFINED ARG_THRIFT_INCLUDE_DIR)
|
||
set(ARG_THRIFT_INCLUDE_DIR "include/thrift-files")
|
||
endif()
|
||
|
||
get_filename_component(base ${THRIFT_FILE} NAME_WE)
|
||
set(output_dir "${CMAKE_CURRENT_BINARY_DIR}/${THRIFT_FILE}-python")
|
||
|
||
# Parse the namespace value
|
||
if (NOT DEFINED ARG_NAMESPACE)
|
||
set(ARG_NAMESPACE "")
|
||
endif()
|
||
|
||
# mstch_python outputs to gen-python/<namespace_py3>/<basename>/
|
||
# NAMESPACE should match the "namespace py3" value in the thrift file
|
||
# (consistent with BUCK's py3_namespace). The basename is appended
|
||
# automatically by this function, just as the mstch_python generator does.
|
||
string(REPLACE "." "/" namespace_dir "${ARG_NAMESPACE}")
|
||
if(namespace_dir STREQUAL "")
|
||
set(py_output_dir "${output_dir}/gen-python/${base}")
|
||
else()
|
||
set(py_output_dir "${output_dir}/gen-python/${namespace_dir}/${base}")
|
||
endif()
|
||
list(APPEND generated_sources
|
||
"${py_output_dir}/thrift_types.py"
|
||
"${py_output_dir}/thrift_enums.py"
|
||
"${py_output_dir}/thrift_metadata.py"
|
||
"${py_output_dir}/thrift_abstract_types.py"
|
||
"${py_output_dir}/thrift_mutable_types.py"
|
||
)
|
||
foreach(service IN LISTS ARG_SERVICES)
|
||
list(APPEND generated_sources
|
||
"${py_output_dir}/thrift_clients.py"
|
||
"${py_output_dir}/thrift_mutable_clients.py"
|
||
"${py_output_dir}/thrift_services.py"
|
||
"${py_output_dir}/thrift_mutable_services.py"
|
||
)
|
||
break() # Service files are per-module, not per-service
|
||
endforeach()
|
||
|
||
# Define a dummy interface library to help propagate the thrift include
|
||
# directories between dependencies.
|
||
add_library("${LIB_NAME}.thrift_includes" INTERFACE)
|
||
target_include_directories(
|
||
"${LIB_NAME}.thrift_includes"
|
||
INTERFACE
|
||
"$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>"
|
||
"$<INSTALL_INTERFACE:${ARG_THRIFT_INCLUDE_DIR}>"
|
||
)
|
||
foreach(dep IN LISTS ARG_DEPENDS)
|
||
target_link_libraries(
|
||
"${LIB_NAME}.thrift_includes"
|
||
INTERFACE "${dep}.thrift_includes"
|
||
)
|
||
endforeach()
|
||
|
||
# This generator expression gets the list of include directories required
|
||
# for all of our dependencies.
|
||
if (NOT POLICY CMP0067)
|
||
message(FATAL_ERROR "add_fbthrift_python_library() requires CMake 3.8+")
|
||
endif()
|
||
set(
|
||
thrift_include_options
|
||
"-I;$<JOIN:$<TARGET_PROPERTY:${LIB_NAME}.thrift_includes,INTERFACE_INCLUDE_DIRECTORIES>,;-I;>"
|
||
)
|
||
|
||
string(REPLACE ";" "," GEN_ARG_STR "${ARG_OPTIONS}")
|
||
|
||
# mstch_python generates output at gen-python/<namespace_py3>/<basename>/
|
||
# The CMake NAMESPACE parameter should match the "namespace py3" directive
|
||
# in the thrift file (consistent with BUCK's py3_namespace). The basename
|
||
# is appended automatically by this function.
|
||
|
||
# Emit the rule to run the thrift compiler
|
||
add_custom_command(
|
||
OUTPUT
|
||
${generated_sources}
|
||
COMMAND_EXPAND_LISTS
|
||
COMMAND
|
||
"${CMAKE_COMMAND}" -E make_directory "${output_dir}"
|
||
COMMAND
|
||
"${FBTHRIFT_COMPILER}"
|
||
--gen "mstch_python:${GEN_ARG_STR}"
|
||
"${thrift_include_options}"
|
||
-I "${FBTHRIFT_INCLUDE_DIR}"
|
||
-o "${output_dir}"
|
||
"${CMAKE_CURRENT_SOURCE_DIR}/${THRIFT_FILE}"
|
||
WORKING_DIRECTORY
|
||
"${CMAKE_BINARY_DIR}"
|
||
MAIN_DEPENDENCY
|
||
"${THRIFT_FILE}"
|
||
DEPENDS
|
||
"${FBTHRIFT_COMPILER}"
|
||
)
|
||
|
||
# Register as a python library.
|
||
# No FBThrift::thrift_py here — thrift-python does not use the legacy
|
||
# pure-Python thrift runtime. The C-extension runtime (thrift.python,
|
||
# folly) is resolved at runtime by add_fb_thrift_python_executable().
|
||
add_fb_python_library(
|
||
"${LIB_NAME}"
|
||
BASE_DIR "${output_dir}/gen-python"
|
||
NAMESPACE ""
|
||
SOURCES ${generated_sources}
|
||
DEPENDS ${ARG_DEPENDS}
|
||
)
|
||
endfunction()
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# add_fb_thrift_python_executable()
|
||
# ---------------------------------------------------------------------------
|
||
# Drop-in replacement for add_fb_python_executable() for targets that
|
||
# transitively import thrift_types.py.
|
||
#
|
||
# Differences from add_fb_python_executable():
|
||
# 1. Forces TYPE dir (C extensions cannot load from zip archives)
|
||
# 2. Post-build: symlinks thrift/python/ from the pip-installed
|
||
# fbthrift-python wheel into the bundled thrift/ directory so that
|
||
# both thrift.Thrift (legacy) and thrift.python (new) coexist
|
||
# 3. Post-build: symlinks folly/ from folly-python site-packages
|
||
#
|
||
# Usage is identical to add_fb_python_executable():
|
||
# add_fb_thrift_python_executable(
|
||
# my_target
|
||
# MAIN_MODULE my.module:main
|
||
# SOURCES ${SRCS}
|
||
# DEPENDS some_py_lib FBThrift::thrift_py
|
||
# )
|
||
# ---------------------------------------------------------------------------
|
||
function(add_fb_thrift_python_executable TARGET)
|
||
fb_find_thrift_python_runtime()
|
||
|
||
# Forward all arguments, injecting TYPE dir
|
||
add_fb_python_executable(
|
||
${TARGET}
|
||
TYPE dir
|
||
${ARGN}
|
||
)
|
||
|
||
set(target_dir "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}")
|
||
|
||
# Post-build symlinks resolve C extension imports at runtime.
|
||
# Expected directory layout after build:
|
||
# <target>/
|
||
# ├── __main__.py
|
||
# ├── thrift/
|
||
# │ ├── __init__.py
|
||
# │ └── python/ → <pip-site-packages>/thrift/python/
|
||
# ├── folly/ → <getdeps-site-packages>/folly/
|
||
# ├── <your_module>/... (Python sources)
|
||
# └── <namespace>/<module>/thrift_types.py (generated thrift-python)
|
||
#
|
||
# Since we no longer depend on FBThrift::thrift_py (the legacy pure-Python
|
||
# runtime), there may be no bundled thrift/ directory yet. Create it
|
||
# with an __init__.py so that "import thrift.python" works.
|
||
if(THRIFT_PYTHON_SITE_PACKAGES AND EXISTS "${THRIFT_PYTHON_SITE_PACKAGES}/thrift/python")
|
||
add_custom_command(
|
||
TARGET ${TARGET}.GEN_PY_EXE POST_BUILD
|
||
COMMAND ${CMAKE_COMMAND} -E make_directory "${target_dir}/thrift"
|
||
COMMAND ${CMAKE_COMMAND} -E touch "${target_dir}/thrift/__init__.py"
|
||
COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||
"${THRIFT_PYTHON_SITE_PACKAGES}/thrift/python"
|
||
"${target_dir}/thrift/python"
|
||
COMMENT "Symlinking thrift.python C extensions into ${TARGET}"
|
||
)
|
||
else()
|
||
message(WARNING
|
||
"${TARGET}: thrift.python not found at "
|
||
"${THRIFT_PYTHON_SITE_PACKAGES}/thrift/python — "
|
||
"thrift_types.py imports will fail at runtime")
|
||
endif()
|
||
|
||
# Symlink folly C extensions (folly.iobuf etc.)
|
||
if(FOLLY_PYTHON_SITE_PACKAGES AND EXISTS "${FOLLY_PYTHON_SITE_PACKAGES}/folly")
|
||
add_custom_command(
|
||
TARGET ${TARGET}.GEN_PY_EXE POST_BUILD
|
||
COMMAND ${CMAKE_COMMAND} -E create_symlink
|
||
"${FOLLY_PYTHON_SITE_PACKAGES}/folly"
|
||
"${target_dir}/folly"
|
||
COMMENT "Symlinking folly-python C extensions into ${TARGET}"
|
||
)
|
||
else()
|
||
message(WARNING
|
||
"${TARGET}: folly-python not found — "
|
||
"thrift_types.py imports will fail at runtime")
|
||
endif()
|
||
endfunction()
|