1
0
mirror of https://github.com/facebook/proxygen.git synced 2026-10-30 05:48:31 +03:00
Files
proxygen/build/fbcode_builder/CMake/FBThriftPythonLibrary.cmake
Arjun Chaturvedi 8e8bd960e9 CMake and Docker changes for thrift-python migration.
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
2026-04-06 16:24:49 -07:00

333 lines
13 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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()