diff --git a/CMakeLists.txt b/CMakeLists.txt index 1a6b55d3..8a11da1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,8 @@ if(EMSCRIPTEN) ) endif() +include(cmake/detect-system.cmake) +include(cmake/python.cmake) include(cmake/project.cmake) if(APPLE) @@ -222,10 +224,16 @@ export LD_LIBRARY_PATH=${CMAKE_INSTALL_PREFIX}/lib:$LD_LIBRARY_PATH" ) endif() -if(MC_RTC_SUPERBUILD_DEFAULT_PYTHON AND NOT PYTHON_BINDING_USER_INSTALL) +if(DISTRO STREQUAL "noble") set(FINAL_COMMAND "${FINAL_COMMAND} -export PYTHONPATH=${EXTRA_PYTHONPATH}:$PYTHONPATH" + source ${CMAKE_INSTALL_PREFIX}/${MC_RTC_SUPERBUILD_VENV_NAME}/bin/activate" ) +else() + if(MC_RTC_SUPERBUILD_DEFAULT_PYTHON AND NOT PYTHON_BINDING_USER_INSTALL) + set(FINAL_COMMAND "${FINAL_COMMAND} + export PYTHONPATH=${EXTRA_PYTHONPATH}:$PYTHONPATH" + ) + endif() endif() if(WITH_ROS_SUPPORT) diff --git a/CMakePresets.json b/CMakePresets.json index c210d10f..8dc03308 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -26,13 +26,13 @@ }, { "name": "relwithdebinfo-noble", - "displayName": "RelWithDebInfo (noble, no ROS, no Python)", + "displayName": "RelWithDebInfo (noble, ROS, no Python)", "inherits": [ "relwithdebinfo" ], "cacheVariables": { "PYTHON_BINDING": "OFF", - "WITH_ROS_SUPPORT": "OFF" + "WITH_ROS_SUPPORT": "ON" }, "condition": { "type": "equals", diff --git a/cmake/detect-system.cmake b/cmake/detect-system.cmake new file mode 100644 index 00000000..fbff70af --- /dev/null +++ b/cmake/detect-system.cmake @@ -0,0 +1,13 @@ +macro(detect_distro OUT_VAR) + find_program(LSB_RELEASE lsb_release) + if(NOT LSB_RELEASE) + message(FATAL_ERROR "lsb_release must be installed before running this script") + endif() + execute_process( + COMMAND lsb_release -sc + OUTPUT_VARIABLE ${OUT_VAR} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) +endmacro() + +detect_distro(DISTRO) diff --git a/cmake/linux-dependencies.cmake b/cmake/linux-dependencies.cmake index 5a75240a..ca11a18a 100644 --- a/cmake/linux-dependencies.cmake +++ b/cmake/linux-dependencies.cmake @@ -1,16 +1,5 @@ -find_program(LSB_RELEASE lsb_release) - -if(NOT LSB_RELEASE) - message(FATAL_ERROR "lsb_release must be installed before running this script") -endif() - set(ROS_IS_ROS2 OFF) set(APT_HAS_PYTHON2_PACKAGES ON) -execute_process( - COMMAND lsb_release -sc - OUTPUT_VARIABLE DISTRO - OUTPUT_STRIP_TRAILING_WHITESPACE -) if(EXISTS ${PROJECT_SOURCE_DIR}/cmake/linux/${DISTRO}.cmake) include(${PROJECT_SOURCE_DIR}/cmake/linux/${DISTRO}.cmake) diff --git a/cmake/linux/noble.cmake b/cmake/linux/noble.cmake index a5606a68..6466d39a 100644 --- a/cmake/linux/noble.cmake +++ b/cmake/linux/noble.cmake @@ -1,17 +1,14 @@ set(MC_LOG_UI_PYTHON_EXECUTABLE python3) set(APT_HAS_PYTHON2_PACKAGES OFF) set(ROS_IS_ROS2 ON) -set(ROS_DISTRO humble) -set(ROS_WORKSPACE_INSTALL_PYTHON_DESTINATION "lib/python3.10/site-packages") +set(ROS_DISTRO jazzy) +set(ROS_WORKSPACE_INSTALL_PYTHON_DESTINATION "lib/python3.12/site-packages") set(APT_DEPENDENCIES curl wget cmake build-essential gfortran - cython3 - # python3-nose python3-pytest python3-numpy python3-coverage python3-setuptools - # python3-pip libeigen3-dev libboost-all-dev libtinyxml2-dev @@ -26,6 +23,12 @@ set(APT_DEPENDENCIES # python-is-python3 libnotify-dev # python3-git + cython3 + python3-numpy + python3-coverage + python3-setuptools + python3-pytest + pre-commit ) if(BUILD_BENCHMARKS) list(APPEND APT_DEPENDENCIES libbenchmark-dev) diff --git a/cmake/options.cmake b/cmake/options.cmake index 48fceada..9a7713f1 100644 --- a/cmake/options.cmake +++ b/cmake/options.cmake @@ -78,6 +78,16 @@ if(MC_RTC_SUPERBUILD_DEFAULT_PYTHON) "${MC_RTC_SUPERBUILD_DEFAULT_PYTHON_USER_BASE}/bin" ) endif() + if(DISTRO STREQUAL "noble") + # on ubuntu noble onwards, pip requires a virtualenv + # detect if we are already in one and if not create one for mc-rtc + # we should add options to options.cmake to specify a custom name for the venv + set(MC_RTC_SUPERBUILD_VENV_NAME + "mc-rtc-venv" + CACHE STRING "Name of the Python virtualenv to create/use" + ) + #handle_noble_virtualenv(${MC_RTC_SUPERBUILD_DEFAULT_PYTHON} ${DISTRO}) + endif() find_program( MC_RTC_SUPERBUILD_PRE_COMMIT NAMES pre-commit diff --git a/cmake/python.cmake b/cmake/python.cmake new file mode 100644 index 00000000..406accd4 --- /dev/null +++ b/cmake/python.cmake @@ -0,0 +1,56 @@ +# Usage example (after DISTRO and MC_RTC_SUPERBUILD_DEFAULT_PYTHON are set): +# handle_noble_virtualenv(${MC_RTC_SUPERBUILD_DEFAULT_PYTHON} ${DISTRO}) +macro(handle_noble_virtualenv PYTHON_EXEC DISTRO) + if(${DISTRO} STREQUAL "noble") + # Check if we are already in a virtualenv + execute_process( + COMMAND + ${PYTHON_EXEC} -c + "import sys; exit(0) if (hasattr(sys, 'real_prefix') or (getattr(sys, 'base_prefix', sys.prefix) != sys.prefix)) else exit(1)" + RESULT_VARIABLE IN_VENV # 0 if in venv, 1 otherwise + ) + if(IN_VENV EQUAL 0 # we are in a venv + AND ENV{VIRTUAL_ENV} STREQUAL + ${MC_RTC_SUPERBUILD_VENV_NAME} # and the active venv matches the expected one + ) + message( + STATUS + "Already in the expected Python virtualenv: ${MC_RTC_SUPERBUILD_VENV_NAME}" + ) + else() + set(VENV_PATH "${CMAKE_INSTALL_PREFIX}/${MC_RTC_SUPERBUILD_VENV_NAME}") + message(STATUS "Creating Python virtualenv at ${VENV_PATH} for Ubuntu Noble") + execute_process( + COMMAND ${PYTHON_EXEC} -m venv "${VENV_PATH}" RESULT_VARIABLE VENV_RESULT + ) + if(NOT VENV_RESULT EQUAL 0) + message(FATAL_ERROR "Failed to create Python virtualenv at ${VENV_PATH}") + endif() + # Re-execute python from the venv for subsequent pip installs + set(MC_RTC_SUPERBUILD_DEFAULT_PYTHON + "${VENV_PATH}/bin/python" + CACHE INTERNAL "" + ) + # "Activate" the venv for subsequent commands by setting Python and pip paths + set(MC_RTC_SUPERBUILD_DEFAULT_PIP + "${VENV_PATH}/bin/pip" + CACHE INTERNAL "" + ) + # set environment variables for subprocesses + set(ENV{VIRTUAL_ENV} "${VENV_PATH}") + set(ENV{PATH} "${VENV_PATH}/bin:$ENV{PATH}") + endif() + endif() +endmacro() + +execute_process( + COMMAND + ${MC_RTC_SUPERBUILD_DEFAULT_PYTHON} -c + "import sys; print(\"python{}.{}\".format(sys.version_info.major, sys.version_info.minor));" + OUTPUT_VARIABLE PYTHON_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE +) + +set(ENV{PYTHONPATH} + "${CMAKE_INSTALL_PREFIX}/lib/${PYTHON_VERSION}/site-packages:$ENV{PYTHONPATH}" +) diff --git a/cmake/ros.cmake b/cmake/ros.cmake index 8553e83c..ba261d54 100644 --- a/cmake/ros.cmake +++ b/cmake/ros.cmake @@ -18,7 +18,7 @@ function(AppendROSWorkspace DEV_DIR SRC_DIR) set(ENV{AMENT_PREFIX_PATH} "${DEV_DIR}:$ENV{AMENT_PREFIX_PATH}") set(ENV{COLCON_PREFIX_PATH} "${DEV_DIR}:$ENV{COLCON_PREFIX_PATH}") set(ENV{PYTHONPATH} - "${DEV_DIR}/local/lib/python3.10/dist-packages:$ENV{PYTHONPATH}" + "${DEV_DIR}/local/lib/${PYTHON_VERSION}/dist-packages:$ENV{PYTHONPATH}" ) else() set(ENV{ROS_VERSION} "1") diff --git a/mc_rtc.cmake b/mc_rtc.cmake index 7bd96f4a..714adcac 100644 --- a/mc_rtc.cmake +++ b/mc_rtc.cmake @@ -45,8 +45,10 @@ AddProject( if(PYTHON_BINDING) AddProject( Eigen3ToPython - GITHUB jrl-umi3218/Eigen3ToPython - GIT_TAG origin/master + # GITHUB jrl-umi3218/Eigen3ToPython + # GIT_TAG origin/master + GITHUB arntanguy/Eigen3ToPython + GIT_TAG origin/topic/noble CMAKE_ARGS -DPIP_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} APT_PACKAGES python-eigen python3-eigen ) @@ -228,8 +230,10 @@ else() endif() AddProject( mc_rtc - GITHUB jrl-umi3218/mc_rtc - GIT_TAG origin/master + # GITHUB jrl-umi3218/mc_rtc + # GIT_TAG origin/master + GITHUB mathieu-celerier/mc_rtc + GIT_TAG origin/topic/fixing-fmt CMAKE_ARGS -DMC_LOG_UI_PYTHON_EXECUTABLE=${MC_LOG_UI_PYTHON_EXECUTABLE} ${MC_RTC_ROS_OPTION} ${MC_RTC_EXTRA_OPTIONS} DEPENDS ${mc_rtc_DEPENDS}