Skip to content

Commit

Permalink
Use a virtual environment for Python packages by default (#261)
Browse files Browse the repository at this point in the history
* Use a virtual environment for Python packages by default

* Install python3-venv in CI

* Don't use sudo

* Oops missed a "STATUS"

* Fix second build dir not using venv
  • Loading branch information
multiplemonomials authored Mar 14, 2024
1 parent b219302 commit 862f462
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 30 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/basic_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@ jobs:
name: Checkout repo
uses: actions/checkout@v3


- name: Install Python packages
- name: Install python3-venv
run: |
python3 -m pip install -r tools/requirements.txt
apt-get update
apt-get install -y python3-venv
-
name: cmake build
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/greentea_cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ jobs:
- name: Checkout
uses: actions/checkout@v3

- name: Install Python packages
- name: Install python3-venv
run: |
python3 -m pip install -r tools/requirements.txt
apt-get update
apt-get install -y python3-venv
- name: Build NUCLEO_G031K8 with baremetal profile
run: |
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/test_building_multiple_executables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,19 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3

- name: Install Python packages
run: |
python3 -m pip install -r tools/requirements.txt
python3 -m pip install -r tools/requirements.txt
# Note: For this CI job we use MBED_CREATE_PYTHON_VENV=FALSE so that we can make sure
# this mode works.
- name: Build the multiple_executables example
run: |
cd tools/cmake/tests/multiple_executables/
mkdir cmake_build
cd cmake_build
cmake -DMBED_TARGET=ARM_MUSCA_S1 ..
cmake -DMBED_TARGET=ARM_MUSCA_S1 -DMBED_CREATE_PYTHON_VENV=FALSE ..
cmake --build .
- name: Verify the post-build command has run successfully on each image
Expand Down
23 changes: 1 addition & 22 deletions tools/cmake/app.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,7 @@ if(CCACHE)
endif()

# Find Python (needed to generate configurations)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
include(CheckPythonPackage)

# Check python packages
set(PYTHON_PACKAGES_TO_CHECK intelhex prettytable future jinja2)
foreach(PACKAGE_NAME ${PYTHON_PACKAGES_TO_CHECK})
string(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UCASE) # Ucase name needed for CMake variable
string(TOLOWER ${PACKAGE_NAME} PACKAGE_NAME_LCASE) # Lcase name needed for import statement

check_python_package(${PACKAGE_NAME_LCASE} HAVE_PYTHON_${PACKAGE_NAME_UCASE})
if(NOT HAVE_PYTHON_${PACKAGE_NAME_UCASE})
message(WARNING "Missing Python dependency ${PACKAGE_NAME}")
endif()
endforeach()

# Check deps for memap
if(Python3_FOUND AND HAVE_PYTHON_INTELHEX AND HAVE_PYTHON_PRETTYTABLE)
set(HAVE_MEMAP_DEPS TRUE)
else()
set(HAVE_MEMAP_DEPS FALSE)
message(STATUS "Missing Python dependencies (at least one of: python3, intelhex, prettytable) so the memory map cannot be printed")
endif()
include(mbed_python_interpreter)

include(mbed_generate_config_header)
include(mbed_target_functions)
Expand Down
7 changes: 7 additions & 0 deletions tools/cmake/mbed_generate_configuration.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ set(MBED_INTERNAL_LAST_MBED_TARGET "${MBED_TARGET}" CACHE INTERNAL "Previous mbe
get_filename_component(MBED_APP_JSON_PATH "${MBED_APP_JSON_PATH}" ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})
get_filename_component(CUSTOM_TARGETS_JSON_PATH "${CUSTOM_TARGETS_JSON_PATH}" ABSOLUTE BASE_DIR ${CMAKE_SOURCE_DIR})

# Make it so that if mbed_app.json or custom_targets.json are modified, CMake is rerun.
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${MBED_APP_JSON_PATH})
if(EXISTS "${CUSTOM_TARGETS_JSON_PATH}" AND (NOT IS_DIRECTORY "${CUSTOM_TARGETS_JSON_PATH}"))
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${CUSTOM_TARGETS_JSON_PATH})
endif()

# Check if mbed_app.json was modified
# Note: if the path is an empty string, get_filename_component(ABSOLUTE) will convert it to a directory,
# so we have to verify that the path we have is a file, not a dir.
Expand Down Expand Up @@ -92,6 +98,7 @@ if(MBED_NEED_TO_RECONFIGURE)

set(MBEDTOOLS_CONFIGURE_COMMAND ${Python3_EXECUTABLE}
-c "import mbed_tools.cli.main\; exit(mbed_tools.cli.main.cli())" # This is used instead of invoking mbed_tools as a script, because it might not be on the user's PATH.
-v # without -v, warnings (e.g. "you have tried to override a nonexistent parameter") do not get printed
configure
-t GCC_ARM # GCC_ARM is currently the only supported toolchain
-m "${MBED_TARGET}"
Expand Down
96 changes: 96 additions & 0 deletions tools/cmake/mbed_python_interpreter.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Copyright (c) 2024 ARM Limited. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# CMake script to find the Python interpreter and either install or find
# Mbed's dependencies.

option(MBED_CREATE_PYTHON_VENV "If true, Mbed OS will create its own virtual environment (venv) and install its Python packages there. This removes the need to manually install Python packages." TRUE)

if(MBED_CREATE_PYTHON_VENV)
# Use the venv.

# Note: venv is stored in the source directory as it can be shared between all the build directories
# (not target specific)
set(MBED_VENV_LOCATION ${CMAKE_SOURCE_DIR}/mbed-os/venv)
set(VENV_STAMP_FILE ${MBED_VENV_LOCATION}/mbed-venv.stamp)
set(MBED_REQUIREMENTS_TXT_LOCATION "${CMAKE_CURRENT_LIST_DIR}/../requirements.txt")

# Find Python3, using the venv if it already exists
set (ENV{VIRTUAL_ENV} ${MBED_VENV_LOCATION})
set (Python3_FIND_VIRTUALENV FIRST)
find_package(Python3 REQUIRED COMPONENTS Interpreter)
include(CheckPythonPackage)

set(NEED_TO_CREATE_VENV FALSE)
set(NEED_TO_INSTALL_PACKAGES FALSE)
if(NOT EXISTS "${VENV_STAMP_FILE}")
set(NEED_TO_CREATE_VENV TRUE)
set(NEED_TO_INSTALL_PACKAGES TRUE)
elseif("${MBED_REQUIREMENTS_TXT_LOCATION}" IS_NEWER_THAN "${VENV_STAMP_FILE}")
set(NEED_TO_INSTALL_PACKAGES TRUE)
endif()

if(NEED_TO_CREATE_VENV)
# Create venv.
# Using approach from here: https://discourse.cmake.org/t/possible-to-create-a-python-virtual-env-from-cmake-and-then-find-it-with-findpython3/1132/2
message(STATUS "Mbed: Creating virtual environment with Python interpreter ${Python3_EXECUTABLE}")
execute_process(
COMMAND ${Python3_EXECUTABLE} -m venv ${MBED_VENV_LOCATION}
COMMAND_ERROR_IS_FATAL ANY
)

## Reset FindPython3 cache variables so it will run again
unset(Python3_EXECUTABLE)
unset(_Python3_EXECUTABLE CACHE)
unset(_Python3_INTERPRETER_PROPERTIES CACHE)
unset(_Python3_INTERPRETER_SIGNATURE CACHE)
## Launch a new search for Python3
find_package (Python3 REQUIRED COMPONENTS Interpreter)
endif()

if(NEED_TO_INSTALL_PACKAGES)
message(STATUS "Mbed: Installing Python requirements for Mbed into venv")
# Upgrade pip first in case it needs an upgrade, to prevent a warning being printed
execute_process(
COMMAND ${Python3_EXECUTABLE} -m pip install --upgrade pip
COMMAND_ERROR_IS_FATAL ANY
)
execute_process(
COMMAND ${Python3_EXECUTABLE} -m pip install -r ${MBED_REQUIREMENTS_TXT_LOCATION}
COMMAND_ERROR_IS_FATAL ANY
)

message(STATUS "Mbed: venv created successfully")
file(TOUCH ${VENV_STAMP_FILE})
endif()

# We always have the memap deps with the venv
set(HAVE_MEMAP_DEPS TRUE)

else()

find_package(Python3 REQUIRED COMPONENTS Interpreter)
include(CheckPythonPackage)


# Check python packages
set(PYTHON_PACKAGES_TO_CHECK intelhex prettytable future jinja2)
foreach(PACKAGE_NAME ${PYTHON_PACKAGES_TO_CHECK})
string(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UCASE) # Ucase name needed for CMake variable
string(TOLOWER ${PACKAGE_NAME} PACKAGE_NAME_LCASE) # Lcase name needed for import statement

check_python_package(${PACKAGE_NAME_LCASE} HAVE_PYTHON_${PACKAGE_NAME_UCASE})
if(NOT HAVE_PYTHON_${PACKAGE_NAME_UCASE})
message(WARNING "Missing Python dependency ${PACKAGE_NAME}")
endif()
endforeach()

# Check deps for memap
if(Python3_FOUND AND HAVE_PYTHON_INTELHEX AND HAVE_PYTHON_PRETTYTABLE)
set(HAVE_MEMAP_DEPS TRUE)
else()
set(HAVE_MEMAP_DEPS FALSE)
message(STATUS "Missing Python dependencies (at least one of: python3, intelhex, prettytable) so the memory map cannot be printed")
endif()

endif()

0 comments on commit 862f462

Please sign in to comment.