1################################################################################ 2# Python package infrastructure 3# 4# This file implements an infrastructure that eases development of 5# package .mk files for Python packages. It should be used for all 6# packages that use Python setup.py/setuptools as their build system. 7# 8# See the Buildroot documentation for details on the usage of this 9# infrastructure 10# 11# In terms of implementation, this Python infrastructure requires the 12# .mk file to only specify metadata information about the package: 13# name, version, download URL, etc. 14# 15# We still allow the package .mk file to override what the different 16# steps are doing, if needed. For example, if <PKG>_BUILD_CMDS is 17# already defined, it is used as the list of commands to perform to 18# build the package, instead of the default Python behaviour. The 19# package can also define some post operation hooks. 20# 21################################################################################ 22 23ifeq ($$($(2)_NEEDS_HOST_PYTHON),python2) 24$$(error "$(1): python2 is no longer supported!") 25endif 26 27ifeq ($(BR2_arm)$(BR2_armeb),y) 28PKG_PYTHON_ARCH = arm 29else 30PKG_PYTHON_ARCH = $(ARCH) 31endif 32PKG_PYTHON_HOST_PLATFORM = linux-$(PKG_PYTHON_ARCH) 33 34# basename does not evaluate if a file exists, so we must check to ensure 35# the _sysconfigdata__linux_*.py file exists. The "|| true" is added to return 36# an empty string if the file does not exist. 37PKG_PYTHON_SYSCONFIGDATA_PATH = $(PYTHON3_PATH)/_sysconfigdata__linux_*.py 38PKG_PYTHON_SYSCONFIGDATA_NAME = `{ [ -e $(PKG_PYTHON_SYSCONFIGDATA_PATH) ] && basename $(PKG_PYTHON_SYSCONFIGDATA_PATH) .py; } || true` 39 40# Target python packages 41PKG_PYTHON_ENV = \ 42 _PYTHON_HOST_PLATFORM="$(PKG_PYTHON_HOST_PLATFORM)" \ 43 _PYTHON_PROJECT_BASE="$(PYTHON3_DIR)" \ 44 _PYTHON_SYSCONFIGDATA_NAME="$(PKG_PYTHON_SYSCONFIGDATA_NAME)" \ 45 PATH=$(BR_PATH) \ 46 $(TARGET_CONFIGURE_OPTS) \ 47 PYTHONPATH="$(PYTHON3_PATH)" \ 48 PYTHONNOUSERSITE=1 \ 49 _python_sysroot=$(STAGING_DIR) \ 50 _python_prefix=/usr \ 51 _python_exec_prefix=/usr 52 53# Host python packages 54HOST_PKG_PYTHON_ENV = \ 55 PATH=$(BR_PATH) \ 56 PYTHONNOUSERSITE=1 \ 57 $(HOST_CONFIGURE_OPTS) 58 59# Target distutils-based packages 60PKG_PYTHON_DISTUTILS_ENV = \ 61 $(PKG_PYTHON_ENV) \ 62 LDSHARED="$(TARGET_CROSS)gcc -shared" \ 63 SETUPTOOLS_USE_DISTUTILS=stdlib \ 64 65PKG_PYTHON_DISTUTILS_BUILD_OPTS = \ 66 --executable=/usr/bin/python 67 68PKG_PYTHON_DISTUTILS_INSTALL_OPTS = \ 69 --install-headers=/usr/include/python$(PYTHON3_VERSION_MAJOR) \ 70 --prefix=/usr 71 72PKG_PYTHON_DISTUTILS_INSTALL_TARGET_OPTS = \ 73 $(PKG_PYTHON_DISTUTILS_INSTALL_OPTS) \ 74 --root=$(TARGET_DIR) 75 76PKG_PYTHON_DISTUTILS_INSTALL_STAGING_OPTS = \ 77 $(PKG_PYTHON_DISTUTILS_INSTALL_OPTS) \ 78 --root=$(STAGING_DIR) 79 80# Host distutils-based packages 81HOST_PKG_PYTHON_DISTUTILS_ENV = \ 82 $(HOST_PKG_PYTHON_ENV) \ 83 SETUPTOOLS_USE_DISTUTILS=stdlib 84 85HOST_PKG_PYTHON_DISTUTILS_INSTALL_OPTS = \ 86 --prefix=$(HOST_DIR) 87 88# Target setuptools-based packages 89PKG_PYTHON_SETUPTOOLS_ENV = \ 90 $(PKG_PYTHON_ENV) \ 91 SETUPTOOLS_USE_DISTUTILS=stdlib 92 93PKG_PYTHON_SETUPTOOLS_CMD = \ 94 $(if $(wildcard $($(PKG)_BUILDDIR)/setup.py),setup.py,-c 'from setuptools import setup;setup()') 95 96PKG_PYTHON_SETUPTOOLS_INSTALL_OPTS = \ 97 --install-headers=/usr/include/python$(PYTHON3_VERSION_MAJOR) \ 98 --prefix=/usr \ 99 --executable=/usr/bin/python \ 100 --single-version-externally-managed 101 102PKG_PYTHON_SETUPTOOLS_INSTALL_TARGET_OPTS = \ 103 $(PKG_PYTHON_SETUPTOOLS_INSTALL_OPTS) \ 104 --root=$(TARGET_DIR) 105 106PKG_PYTHON_SETUPTOOLS_INSTALL_STAGING_OPTS = \ 107 $(PKG_PYTHON_SETUPTOOLS_INSTALL_OPTS) \ 108 --root=$(STAGING_DIR) 109 110# Host setuptools-based packages 111HOST_PKG_PYTHON_SETUPTOOLS_ENV = \ 112 $(HOST_PKG_PYTHON_ENV) \ 113 SETUPTOOLS_USE_DISTUTILS=stdlib 114 115HOST_PKG_PYTHON_SETUPTOOLS_INSTALL_OPTS = \ 116 --prefix=$(HOST_DIR) \ 117 --root=/ \ 118 --single-version-externally-managed 119 120# Target pep517-based packages 121PKG_PYTHON_PEP517_ENV = \ 122 $(PKG_PYTHON_ENV) 123 124PKG_PYTHON_PEP517_INSTALL_OPTS = \ 125 --interpreter=/usr/bin/python \ 126 --script-kind=posix 127 128PKG_PYTHON_PEP517_INSTALL_TARGET_OPTS = \ 129 $(PKG_PYTHON_PEP517_INSTALL_OPTS) \ 130 --purelib=$(TARGET_DIR)/usr/lib/python$(PYTHON3_VERSION_MAJOR)/site-packages \ 131 --headers=$(TARGET_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \ 132 --scripts=$(TARGET_DIR)/usr/bin \ 133 --data=$(TARGET_DIR)/usr 134 135PKG_PYTHON_PEP517_INSTALL_STAGING_OPTS = \ 136 $(PKG_PYTHON_PEP517_INSTALL_OPTS) \ 137 --purelib=$(STAGING_DIR)/usr/lib/python$(PYTHON3_VERSION_MAJOR)/site-packages \ 138 --headers=$(STAGING_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \ 139 --scripts=$(STAGING_DIR)/usr/bin \ 140 --data=$(STAGING_DIR)/usr 141 142# Host pep517-based packages 143HOST_PKG_PYTHON_PEP517_ENV = \ 144 $(HOST_PKG_PYTHON_ENV) 145 146HOST_PKG_PYTHON_PEP517_BOOTSTRAP_INSTALL_OPTS = \ 147 --installdir=$(HOST_DIR)/lib/python$(PYTHON3_VERSION_MAJOR)/site-packages 148 149################################################################################ 150# inner-python-package -- defines how the configuration, compilation 151# and installation of a Python package should be done, implements a 152# few hooks to tune the build process and calls the generic package 153# infrastructure to generate the necessary make targets 154# 155# argument 1 is the lowercase package name 156# argument 2 is the uppercase package name, including a HOST_ prefix 157# for host packages 158# argument 3 is the uppercase package name, without the HOST_ prefix 159# for host packages 160# argument 4 is the type (target or host) 161################################################################################ 162 163define inner-python-package 164 165ifndef $(2)_SETUP_TYPE 166 ifdef $(3)_SETUP_TYPE 167 $(2)_SETUP_TYPE = $$($(3)_SETUP_TYPE) 168 else 169 $$(error "$(2)_SETUP_TYPE must be set") 170 endif 171endif 172 173# Distutils 174ifeq ($$($(2)_SETUP_TYPE),distutils) 175ifeq ($(4),target) 176$(2)_BASE_ENV = $$(PKG_PYTHON_DISTUTILS_ENV) 177$(2)_BASE_BUILD_CMD = setup.py build 178$(2)_BASE_BUILD_OPTS = $$(PKG_PYTHON_DISTUTILS_BUILD_OPTS) 179$(2)_BASE_INSTALL_TARGET_CMD = setup.py install --no-compile $$(PKG_PYTHON_DISTUTILS_INSTALL_TARGET_OPTS) 180$(2)_BASE_INSTALL_STAGING_CMD = setup.py install $$(PKG_PYTHON_DISTUTILS_INSTALL_STAGING_OPTS) 181else 182$(2)_BASE_ENV = $$(HOST_PKG_PYTHON_DISTUTILS_ENV) 183$(2)_BASE_BUILD_CMD = setup.py build 184$(2)_BASE_INSTALL_CMD = setup.py install $$(HOST_PKG_PYTHON_DISTUTILS_INSTALL_OPTS) 185endif 186# Setuptools 187else ifeq ($$($(2)_SETUP_TYPE),setuptools) 188ifeq ($(4),target) 189$(2)_BASE_ENV = $$(PKG_PYTHON_SETUPTOOLS_ENV) 190$(2)_BASE_BUILD_CMD = $$(PKG_PYTHON_SETUPTOOLS_CMD) build 191$(2)_BASE_INSTALL_TARGET_CMD = $$(PKG_PYTHON_SETUPTOOLS_CMD) install --no-compile $$(PKG_PYTHON_SETUPTOOLS_INSTALL_TARGET_OPTS) 192$(2)_BASE_INSTALL_STAGING_CMD = $$(PKG_PYTHON_SETUPTOOLS_CMD) install $$(PKG_PYTHON_SETUPTOOLS_INSTALL_STAGING_OPTS) 193else 194$(2)_BASE_ENV = $$(HOST_PKG_PYTHON_SETUPTOOLS_ENV) 195$(2)_BASE_BUILD_CMD = $$(PKG_PYTHON_SETUPTOOLS_CMD) build 196$(2)_BASE_INSTALL_CMD = $$(PKG_PYTHON_SETUPTOOLS_CMD) install $$(HOST_PKG_PYTHON_SETUPTOOLS_INSTALL_OPTS) 197endif 198else ifneq ($$(filter flit pep517,$$($(2)_SETUP_TYPE)),) 199ifeq ($(4),target) 200$(2)_BASE_ENV = $$(PKG_PYTHON_PEP517_ENV) 201$(2)_BASE_BUILD_CMD = -m build -n -w 202$(2)_BASE_INSTALL_TARGET_CMD = $(TOPDIR)/support/scripts/pyinstaller.py dist/* $$(PKG_PYTHON_PEP517_INSTALL_TARGET_OPTS) 203$(2)_BASE_INSTALL_STAGING_CMD = $(TOPDIR)/support/scripts/pyinstaller.py dist/* $$(PKG_PYTHON_PEP517_INSTALL_STAGING_OPTS) 204else 205$(2)_BASE_ENV = $$(HOST_PKG_PYTHON_PEP517_ENV) 206$(2)_BASE_BUILD_CMD = -m build -n -w 207$(2)_BASE_INSTALL_CMD = -m installer dist/* 208endif 209else ifeq ($$($(2)_SETUP_TYPE),flit-bootstrap) 210ifeq ($(4),target) 211$$(error flit-bootstrap setup type only supported for host packages) 212else 213$(2)_BASE_ENV = $$(HOST_PKG_PYTHON_PEP517_ENV) 214$(2)_BASE_BUILD_CMD = -m flit_core.wheel 215$(2)_BASE_INSTALL_CMD ?= -m installer dist/* 216endif 217else 218$$(error "Invalid $(2)_SETUP_TYPE. Valid options are 'distutils', 'setuptools', 'pep517' or 'flit'.") 219endif 220 221# Target packages need both the python interpreter on the target (for 222# runtime) and the python interpreter on the host (for 223# compilation). However, host packages only need the python 224# interpreter on the host. 225# 226ifeq ($(4),target) 227$(2)_DEPENDENCIES += host-python3 python3 228else 229$(2)_DEPENDENCIES += host-python3 230endif # ($(4),target) 231 232# Setuptools based packages will need setuptools for the host Python 233# interpreter (both host and target). 234# 235ifeq ($$($(2)_SETUP_TYPE),setuptools) 236$(2)_DEPENDENCIES += $$(if $$(filter host-python-setuptools,$(1)),,host-python-setuptools) 237else ifneq ($$(filter flit pep517,$$($(2)_SETUP_TYPE)),) 238$(2)_DEPENDENCIES += host-python-pypa-build host-python-installer 239ifeq ($$($(2)_SETUP_TYPE),flit) 240$(2)_DEPENDENCIES += host-python-flit-core 241endif 242else ifeq ($$($(2)_SETUP_TYPE),flit-bootstrap) 243# Don't add dependency on host-python-installer for 244# host-python-installer itself, and its dependencies. 245ifeq ($$(filter host-python-flit-core host-python-installer,$(1)),) 246$(2)_DEPENDENCIES += host-python-installer 247endif 248endif # SETUP_TYPE 249 250# Python interpreter to use for building the package. 251# 252$(2)_PYTHON_INTERPRETER = $$(HOST_DIR)/bin/python 253 254# 255# Build step. Only define it if not already defined by the package .mk 256# file. 257# 258ifndef $(2)_BUILD_CMDS 259define $(2)_BUILD_CMDS 260 (cd $$($$(PKG)_BUILDDIR)/; \ 261 $$($$(PKG)_BASE_ENV) $$($$(PKG)_ENV) \ 262 $$($(2)_PYTHON_INTERPRETER) \ 263 $$($$(PKG)_BASE_BUILD_CMD) \ 264 $$($$(PKG)_BASE_BUILD_OPTS) $$($$(PKG)_BUILD_OPTS)) 265endef 266endif 267 268# 269# Host installation step. Only define it if not already defined by the 270# package .mk file. 271# 272ifndef $(2)_INSTALL_CMDS 273define $(2)_INSTALL_CMDS 274 (cd $$($$(PKG)_BUILDDIR)/; \ 275 $$($$(PKG)_BASE_ENV) $$($$(PKG)_ENV) \ 276 $$($(2)_PYTHON_INTERPRETER) \ 277 $$($$(PKG)_BASE_INSTALL_CMD) \ 278 $$($$(PKG)_INSTALL_OPTS)) 279endef 280endif 281 282# 283# Target installation step. Only define it if not already defined by 284# the package .mk file. 285# 286ifndef $(2)_INSTALL_TARGET_CMDS 287define $(2)_INSTALL_TARGET_CMDS 288 (cd $$($$(PKG)_BUILDDIR)/; \ 289 $$($$(PKG)_BASE_ENV) $$($$(PKG)_ENV) \ 290 $$($(2)_PYTHON_INTERPRETER) \ 291 $$($$(PKG)_BASE_INSTALL_TARGET_CMD) \ 292 $$($$(PKG)_INSTALL_TARGET_OPTS)) 293endef 294endif 295 296# 297# Staging installation step. Only define it if not already defined by 298# the package .mk file. 299# 300ifndef $(2)_INSTALL_STAGING_CMDS 301define $(2)_INSTALL_STAGING_CMDS 302 (cd $$($$(PKG)_BUILDDIR)/; \ 303 $$($$(PKG)_BASE_ENV) $$($$(PKG)_ENV) \ 304 $$($(2)_PYTHON_INTERPRETER) \ 305 $$($$(PKG)_BASE_INSTALL_STAGING_CMD) \ 306 $$($$(PKG)_INSTALL_STAGING_OPTS)) 307endef 308endif 309 310# Call the generic package infrastructure to generate the necessary 311# make targets 312$(call inner-generic-package,$(1),$(2),$(3),$(4)) 313 314endef 315 316################################################################################ 317# python-package -- the target generator macro for Python packages 318################################################################################ 319 320python-package = $(call inner-python-package,$(pkgname),$(call UPPERCASE,$(pkgname)),$(call UPPERCASE,$(pkgname)),target) 321host-python-package = $(call inner-python-package,host-$(pkgname),$(call UPPERCASE,host-$(pkgname)),$(call UPPERCASE,$(pkgname)),host) 322