cmake: fix issue #25048 have cmake fail when pivy and swig use different API versions, update status messages

This commit is contained in:
chris
2025-11-08 15:57:08 -06:00
committed by Chris Hennes
parent 9beca4363a
commit 1f213dd498

View File

@@ -1,12 +1,160 @@
macro(SetupSwig)
#-------------------------------- Swig ----------------------------------
find_package(SWIG)
# force cmake to re-search for SWIG when CMAKE_PREFIX_PATH changes
unset(SWIG_EXECUTABLE CACHE)
unset(SWIG_DIR CACHE)
unset(SWIG_VERSION CACHE)
unset(SWIG_FOUND CACHE)
if(BUILD_SKETCHER)
# SWIG is required for sketcher WB (use QUIET to provide custom error message)
find_package(SWIG QUIET)
if(NOT SWIG_FOUND)
message("=====================================================\n"
"SWIG not found, will not build SWIG binding for pivy.\n"
"=====================================================\n")
endif(NOT SWIG_FOUND)
message(FATAL_ERROR
"-----------------------------------------------------\n"
"SWIG not found, swig & pivy required for sketcher WB.\n"
"-----------------------------------------------------\n")
# do not continue with check if swig not found
return()
endif()
endmacro(SetupSwig)
# check swig/pivy runtime compatibility
message(STATUS "checking SWIG/Pivy runtime compatibility...")
# get SWIG's runtime version using -external-runtime flag
execute_process(
COMMAND ${SWIG_EXECUTABLE} -python -external-runtime "${CMAKE_BINARY_DIR}/swig_runtime_check.h"
RESULT_VARIABLE SWIG_EXTERNAL_RUNTIME_RESULT
ERROR_VARIABLE SWIG_EXTERNAL_RUNTIME_ERROR
ERROR_QUIET
)
# NOTE: only print the below output if using `cmake --log-level=DEBUG`
message(DEBUG "SWIG external-runtime result: ${SWIG_EXTERNAL_RUNTIME_RESULT}")
message(DEBUG "SWIG external-runtime error: ${SWIG_EXTERNAL_RUNTIME_ERROR}")
message(STATUS "Looking for: ${CMAKE_BINARY_DIR}/swig_runtime_check.h")
if(EXISTS "${CMAKE_BINARY_DIR}/swig_runtime_check.h")
message(STATUS "File exists: YES")
else()
message(STATUS "File exists: NO")
endif()
if(EXISTS "${CMAKE_BINARY_DIR}/swig_runtime_check.h")
file(STRINGS "${CMAKE_BINARY_DIR}/swig_runtime_check.h"
SWIG_RUNTIME_VERSION_LINE
REGEX "^#define SWIG_RUNTIME_VERSION")
message(STATUS "SWIG_RUNTIME_VERSION_LINE: ${SWIG_RUNTIME_VERSION_LINE}")
if(SWIG_RUNTIME_VERSION_LINE)
# extract the version number (it's in quotes: "5")
string(REGEX MATCH "\"([0-9]+)\"" _ "${SWIG_RUNTIME_VERSION_LINE}")
set(SWIG_RUNTIME_VERSION "${CMAKE_MATCH_1}")
message(STATUS "Extracted SWIG_RUNTIME_VERSION: ${SWIG_RUNTIME_VERSION}")
endif()
file(REMOVE "${CMAKE_BINARY_DIR}/swig_runtime_check.h")
else()
message(STATUS "swig_runtime_check.h not found!")
endif()
# extract pivy's SWIG runtime version from the compiled module
# NOTE: python code can not be indented
set(PYTHON_CHECK_PIVY_RUNTIME [=[
import sys
import os
import re
try:
import pivy
pivy_dir = os.path.dirname(pivy.__file__)
print(f'DEBUG:pivy_dir={pivy_dir}', file=sys.stderr)
print(f'DEBUG:files={os.listdir(pivy_dir)}', file=sys.stderr)
pivy_path = None
# Look for _coin module with any extension (.so on Unix, .pyd on Windows)
for f in os.listdir(pivy_dir):
print(f'DEBUG:checking={f}', file=sys.stderr)
if f.startswith('_coin') and (f.endswith('.so') or f.endswith('.pyd')):
pivy_path = os.path.join(pivy_dir, f)
break
print(f'DEBUG:pivy_path={pivy_path}', file=sys.stderr)
if pivy_path and os.path.exists(pivy_path):
with open(pivy_path, 'rb') as f:
content = f.read().decode('latin-1', errors='ignore')
print(f'DEBUG:content_len={len(content)}', file=sys.stderr)
# Use regex to find swig_runtime_data followed by a number
match = re.search(r'swig_runtime_data(\d+)', content)
print(f'DEBUG:match={match}', file=sys.stderr)
if match:
print(match.group(1))
except ImportError as e:
print(f'DEBUG:import_error={e}', file=sys.stderr)
print('ERROR_IMPORT')
except Exception as e:
print(f'DEBUG:exception={e}', file=sys.stderr)
]=])
execute_process(
COMMAND ${Python3_EXECUTABLE} -c "${PYTHON_CHECK_PIVY_RUNTIME}"
OUTPUT_VARIABLE PIVY_RUNTIME_VERSION
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_VARIABLE PIVY_DEBUG_OUTPUT
TIMEOUT 10
)
message(DEBUG "Pivy debug output: ${PIVY_DEBUG_OUTPUT}")
# Handle errors and compare versions
if(PIVY_RUNTIME_VERSION STREQUAL "ERROR_IMPORT")
message(WARNING
"Could not import pivy to check SWIG compatibility.\n"
"Proceeding without SWIG version check."
)
elseif(SWIG_RUNTIME_VERSION AND PIVY_RUNTIME_VERSION)
if(NOT SWIG_RUNTIME_VERSION STREQUAL PIVY_RUNTIME_VERSION)
message(FATAL_ERROR
" --------------------------------------------------------
SWIG / PIVY RUNTIME VERSION MISMATCH DETECTED!
SWIG runtime API version: ${SWIG_RUNTIME_VERSION}
Pivy runtime API version: ${PIVY_RUNTIME_VERSION}
These must match for compatibility.
This will cause runtime errors: 'No SWIG wrapped library loaded'
swig v4.4.x is not compatible with pivy built with swig <=4.3.x
FIX: Install a SWIG version that uses runtime ${PIVY_RUNTIME_VERSION}
or rebuild Pivy with your current SWIG ${SWIG_VERSION}.
--------------------------------------------------------"
)
else()
message(STATUS "SWIG/Pivy runtime compatibility: PASSED")
message(STATUS "swig runtime API version: ${SWIG_RUNTIME_VERSION}")
message(STATUS "pivy runtime API version: ${PIVY_RUNTIME_VERSION}")
message(STATUS "swig binary version building freecad: ${SWIG_VERSION}")
endif()
else()
if(NOT SWIG_RUNTIME_VERSION)
message(WARNING "Could not determine SWIG runtime version")
endif()
if(NOT PIVY_RUNTIME_VERSION)
message(WARNING "Could not determine Pivy runtime version")
endif()
message(WARNING "Proceeding without SWIG/Pivy compatibility check.")
endif()
endif()
endmacro()