You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

310 lines
16 KiB

  1. # Python packages folder
  2. ## Table of contents
  3. 1. [Description](#description)
  4. 2. [Introduction](#introduction)
  5. 3. [Python 2 end-of-life](#python-2-end-of-life)
  6. 4. [Using Python in external/other package feeds](#using-python-in-externalother-package-feeds)
  7. 5. [Build considerations](#build-considerations)
  8. 6. [General folder structure](#general-folder-structure)
  9. 7. [Building a Python package](#building-a-python-package)
  10. 1. [Include python3-package.mk](#include-python3-packagemk)
  11. 2. [Add Package/<PKG_NAME> OpenWrt definitions](#add-packagepkg_name-openwrt-definitions)
  12. 3. [Wrapping things up so that they build](#wrapping-things-up-so-that-they-build)
  13. 4. [Customizing things](#customizing-things)
  14. 5. [Host-side Python packages for build](#host-side-python-packages-for-build)
  15. ## Description
  16. This section describes specifics for the Python packages that are present in this repo, and how things are structured.
  17. In terms of license, contributing guide, etc, all of that information is described in the top [README.md](README.md) file, and it applies here as well. This document attempts to cover only technical aspects of Python packages, and maybe some explanations about how things are (and why they are as they are).
  18. ## Introduction
  19. This sub-tree came to exist after a number of contributions (Python packages) were made to this repo, and the [lang](lang) subtree grew to a point where a decision was made to move all Python packages under [lang/python](lang/python).
  20. It contains the Python 3 interpreter and Python packages. Most of the Python packages are downloaded from [pypi.org](https://pypi.org/). Python packages from [pypi.org](https://pypi.org/) are typically preferred when adding new packages.
  21. If more packages (than the ones packaged here) are needed, they can be downloaded via [pip](https://pip.pypa.io). Note that the versions of `pip` & `setuptools` [available in this repo] are the ones that are packaged inside the Python package (yes, Python comes packaged with `pip` & `setuptools`).
  22. ## Python 2 end-of-life
  23. Python 2 [will not be maintained past 2020](https://www.python.org/dev/peps/pep-0373/). All Python 2 packages have been removed from the packages feed (this repo) and archived in the [abandoned packages feed](https://github.com/openwrt/packages-abandoned).
  24. ## Using Python in external/other package feeds
  25. In the feeds.conf (or feeds.conf.default file, whatever is preferred), the packages repo should be present.
  26. Example
  27. ```
  28. src-git packages https://git.openwrt.org/feed/packages.git
  29. src-git luci https://git.openwrt.org/project/luci.git
  30. src-git routing https://git.openwrt.org/feed/routing.git
  31. src-git telephony https://git.openwrt.org/feed/telephony.git
  32. #
  33. #
  34. src-git someotherfeed https://github.com/<github-user>/<some-other-package>
  35. ```
  36. Assuming that there are Python packages in the `<some-other-package>`, they should include `python3-package.mk` like this:
  37. ```
  38. include $(TOPDIR)/feeds/packages/lang/python/python3-package.mk
  39. ```
  40. Same rules apply for `python3-package.mk` as the Python packages in this repo.
  41. **One important consideration:**: if the local name is not `packages`, it's something else, like `openwrt-packages`. And in `feeds.conf[.default]` it's:
  42. ```
  43. src-git openwrt-packages https://git.openwrt.org/feed/packages.git
  44. ```
  45. Then, the inclusions also change:
  46. ```
  47. include $(TOPDIR)/feeds/openwrt-packages/lang/python/python3-package.mk
  48. ```
  49. Each maintainer[s] of external packages feeds is responsible for the local name, and relative inclusion path back to this feed (which is named `packages` by default).
  50. In case there is a need/requirement such that the local package feed is named something else than `packages`, one approach to make the package flexible to change is:
  51. ```
  52. PYTHON3_PACKAGE_MK:=$(wildcard $(TOPDIR)/feeds/*/lang/python/python3-package.mk)
  53. # verify that there is only one single file returned
  54. ifneq (1,$(words $(PYTHON3_PACKAGE_MK)))
  55. ifeq (0,$(words $(PYTHON3_PACKAGE_MK)))
  56. $(error did not find python3-package.mk in any feed)
  57. else
  58. $(error found multiple python3-package.mk files in the feeds)
  59. endif
  60. else
  61. $(info found python3-package.mk at $(PYTHON3_PACKAGE_MK))
  62. endif
  63. include $(PYTHON3_PACKAGE_MK)
  64. ```
  65. This should solve the corner-case where the `python3-package.mk` can be in some other feed, or if the packages feed will be named something else locally.
  66. ## Build considerations
  67. In order to build the Python interpreter, a host Python interpreter needs to be built, in order to process some of the build for the target Python build. The host Python interpreter is also needed so that Python bytecodes are generated, so the host interpreter needs to be the exact version as on the target. And finally, the host Python interpreter also provides pip, so that it may be used to install some Python packages that are required to build other Python packages.
  68. That's why you'll also see a Python build & staging directories.
  69. As you're probably thinking, this sounds [and is] somewhat too much complication [just for packaging], but the status of things is-as-it-is, and it's probably much worse than what's currently visible on the surface [with respect to packaging Python & packages].
  70. As mentioned earlier, Python packages are shipped with bytecodes, and the reason for this is simply performance & size.
  71. The thought/discussion matrix derives a bit like this:
  72. * shipping both Python source-code & bytecodes takes too much space on some devices ; Python source code & byte-code take about similar disk-size
  73. * shipping only Python source code has a big performance penalty [on some lower end systems] ; something like 500 msecs (Python source-only) -> 70 msecs (Python byte-codes) time reduction for a simple "Hello World" script
  74. * shipping only Python byte-codes seems like a good trade-off, and this means that `python3-src` can be provided for people that want the source code
  75. By default, automatic Python byte-code generation is disabled when running a Python script, in order to prevent a disk from accidentally filling up. Since some disks reside in RAM, this also means not filling up the RAM. If someone wants to convert Python source to byte-code then he/she is free to compile it [directly on the device] manually via the Python interpreter & library.
  76. ## General folder structure
  77. The basis of all these packages is:
  78. * [lang/python/python3](lang/python/python3) - The Python 3.x.y interpreter
  79. This is a normal OpenWrt package, which will build the Python interpreter. This also provides `python3-pip` & `python3-setuptools`. Each Python package is actually split into multiple sub-packages [e.g. python3-email, python3-sqlite3, etc]. This can be viewed inside [lang/python/python3/files](lang/python/python3/files).
  80. The reason for this splitting, is purely to offer a way for some people to package Python in as-minimal-as-possible-and-still-runable way, and also to be somewhat maintainable when packaging. A standard Python installation can take ~20-30 MBs of disk, which can be somewhat big for some people, so there is the `python3-base` package which brings that down to ~5 MBs. This seems to be good enough (and interesting) for a number of people.
  81. The Python interpreter is structured like this:
  82. * `python3-base`, which is just the minimal package to startup Python and run basic commands
  83. * `python3` is a meta-package, which installs almost everything (python3-base [plus] Python library [minus] some unit-tests & some windows-y things)
  84. * `python3-light` is `python3` [minus] packages that are in [lang/python/python3/files](lang/python/python3/files) ; the size of this package may be sensible (and interesting) to another group of people
  85. All other Python packages (aside from the intepreter) typically use these files:
  86. * **python3-host.mk** - this file contains paths and build rules for running the Python interpreter on the host-side; they also provide paths to host interprete, host Python lib-dir & so on
  87. * **python3-package.mk**
  88. * includes **python3-host.mk**
  89. * contains all the default build rules for Python packages; these will be detailed below in the [Building a Python package](#Building a Python package) section
  90. **Note** that Python packages don't need to use these files (i.e. `python3-package.mk` & `python3-host.mk`), but they do provide some ease-of-use & reduction of duplicate code. And they do contain some learned-lessons about packaging Python packages, so it's a good idea to use them.
  91. ## Building a Python package
  92. Packaging for Python uses the `VARIANT` mechanism for packaging inside OpenWrt. (#### FIXME: find a link for this later if it exists)
  93. ### Include python3-package.mk
  94. Add this after `include $(INCLUDE_DIR)/package.mk`
  95. ```
  96. include ../python3-package.mk
  97. ```
  98. This will make sure that build rules for Python can be specified and picked up for build.
  99. ### Include pypi.mk (optional)
  100. If the package source code will be downloaded from [pypi.org](https://pypi.org/), including `pypi.mk` can help simplify the package Makefile.
  101. To use `pypi.mk`, add this **before** `include $(INCLUDE_DIR)/package.mk`:
  102. ```
  103. include ../pypi.mk
  104. ```
  105. `pypi.mk` has several `PYPI_*` variables that must/can be set (see below); these should be set before `pypi.mk` is included, i.e. before the `include ../pypi.mk` line.
  106. `pypi.mk` also provides default values for `PKG_SOURCE` and `PKG_SOURCE_URL`, so these variables may be omitted.
  107. One variable is required:
  108. * `PYPI_NAME`: Package name on pypi.org. This should match the PyPI name exactly.
  109. For example (from the `python-yaml` package):
  110. ```
  111. PYPI_NAME:=PyYAML
  112. ```
  113. These variables are optional:
  114. * `PYPI_SOURCE_NAME`: Package name component of the source tarball filename
  115. Default: Same value as `PYPI_NAME`
  116. * `PYPI_SOURCE_EXT`: File extension of the source tarball filename
  117. Default: `tar.gz`
  118. `pypi.mk` constructs the default `PKG_SOURCE` value from these variables (and `PKG_VERSION`):
  119. ```
  120. PKG_SOURCE?=$(PYPI_SOURCE_NAME)-$(PKG_VERSION).$(PYPI_SOURCE_EXT)
  121. ```
  122. The `PYPI_SOURCE_*` variables allow this default `PKG_SOURCE` value to be customized as necessary.
  123. ### Add Package/<PKG_NAME> OpenWrt definitions
  124. This part is similar to default OpenWrt packages.
  125. Example:
  126. ```
  127. define Package/python3-lxml
  128. SECTION:=lang
  129. CATEGORY:=Languages
  130. SUBMENU:=Python
  131. TITLE:=Pythonic XML processing library
  132. URL:=https://lxml.de
  133. DEPENDS:=+python3-light +libxml2 +libxslt +libexslt
  134. VARIANT:=python3
  135. endef
  136. define Package/python3-lxml/description
  137. The lxml XML toolkit is a Pythonic binding
  138. for the C libraries libxml2 and libxslt.
  139. endef
  140. ```
  141. Some considerations here (based on the example above):
  142. * `VARIANT=python3` must be added
  143. * typically the package is named `Package/python3-<something>` ; this convention makes things easier to follow, though it could work without naming things this way
  144. * `TITLE` can be something a bit more verbose/neat ; typically the name is short as seen above
  145. ### Wrapping things up so that they build
  146. If all the above prerequisites have been met, all that's left is:
  147. ```
  148. $(eval $(call Py3Package,python3-lxml))
  149. $(eval $(call BuildPackage,python3-lxml))
  150. ```
  151. The `$(eval $(call Py3Package,python3-lxml))` part will instantiate all the default Python build rules so that the final Python package is packaged into an OpenWrt.
  152. And `$(eval $(call BuildPackage,python3-lxml))` will bind all the rules generated with `$(eval $(call Py3Package,python3-lxml))` into the OpenWrt build system.
  153. These packages will contain byte-codes and binaries (shared libs & other stuff).
  154. If a user wishes to ship source code, adding one more line creates one more package that ship Python source code:
  155. ```
  156. $(eval $(call Py3Package,python3-lxml))
  157. $(eval $(call BuildPackage,python3-lxml))
  158. $(eval $(call BuildPackage,python3-lxml-src))
  159. ```
  160. The name `*-src` must be the Python package name; so for `python3-lxml-src` a equivalent `python3-lxml` name must exist.
  161. ### Customizing things
  162. Some packages need custom build rules (because they do).
  163. The default package build and install processes are defined in `python3-package.mk`.
  164. #### Building
  165. The default build process calls `setup.py install` inside the directory where the Python source package is extracted (`PKG_BUILD_DIR`). This "installs" the Python package to an intermediate location (`PKG_INSTALL_DIR`) where it is used by the default install process.
  166. There are several Makefile variables that can be used to customize this process (all optional):
  167. * `PYTHON3_PKG_SETUP_DIR`: Path where `setup.py` can be found, relative to the package directory (`PKG_BUILD_DIR`).
  168. Default: empty value (`setup.py` is in the package directory)
  169. * `PYTHON3_PKG_SETUP_VARS`: Additional environment variables to set for the call to `setup.py`. Should be in the form of `VARIABLE1=value VARIABLE2=value ...`.
  170. Default: empty value
  171. * `PYTHON3_PKG_SETUP_GLOBAL_ARGS`: Additional command line arguments to pass to `setup.py`, before / in front of the `install` command.
  172. Default: empty value
  173. * `PYTHON3_PKG_SETUP_ARGS`: Additional command line arguments to pass to `setup.py`, after the `install` command.
  174. Default: `--single-version-externally-managed`
  175. Conceptually, these variables are used in this way:
  176. ```
  177. cd $(PKG_BUILD_DIR)/$(PYTHON3_PKG_SETUP_DIR)
  178. $(PYTHON3_PKG_SETUP_VARS) python3 setup.py $(PYTHON3_PKG_SETUP_GLOBAL_ARGS) install $(PYTHON3_PKG_SETUP_ARGS)
  179. ```
  180. The default build process can be completely overridden by defining a custom `Py3Build/Compile` rule in the package Makefile.
  181. #### Installing
  182. The default install process copies some/all of the files from `PKG_INSTALL_DIR`, placed there by the build process, to a location passed to the install rule as the first argument (`$(1)`). The OpenWrt build system will then take those files and create the actual .ipk package archives.
  183. This default process uses 2 build rules:
  184. * `Py3Package/<package>/filespec` which are Python library files relative to `/usr/lib/pythonX.Y` ; by default this is `/usr/lib/python$(PYTHON3_VERSION)/site-packages` (`PYTHON3_PKG_DIR`) ; most Python packages generate files that get installed in this sub-folder
  185. * `Py3Package/<package>/install` is similar to `Package/<package>/install` ; this allows binary (or other files) to be installed on the target
  186. Both the 2 above rules generate a `Package/<package>/install` build rule, which gets picked up by the build system. Both can be used together (they are not mutually exclusive), and provide a good enough flexibility for specifying Python packages.
  187. The `Py3Package/<package>/filespec` rule contains one or more lines of the following format (whitespace added for clarity):
  188. ```
  189. <one of: +-=> | <file/directory path> | <file permissions>
  190. ```
  191. The initial character controls the action that will be taken:
  192. * `+`: Install the given path. If the path is a directory, all files and subdirectories inside are installed.
  193. * If file permissions is specified (optional), then the file or directory (and all files and subdirectories) are assigned the given permissions; if omitted, then the file or directory retains its original permissions.
  194. * `-`: Remove the given path. Useful when most of a directory should be installed except for a few files or subdirectories.
  195. * File permissions is not used / ignored in this case.
  196. * `=`: Assign the given file permissions to the given path. File permissions is required in this case.
  197. As mentioned, the default `Py3Package/<package>/filespec` installs `PYTHON3_PKG_DIR`:
  198. ```
  199. define Py3Package/python3-example/filespec
  200. +|$(PYTHON3_PKG_DIR)
  201. endef
  202. ```
  203. If the package installs a `example_package` directory inside `PYTHON3_PKG_DIR`, and there is an `examples` directory and `test_*.py` files that can be omitted to save space, this can be specified as:
  204. ```
  205. define Py3Package/python3-example/filespec
  206. +|$(PYTHON3_PKG_DIR)
  207. -|$(PYTHON3_PKG_DIR)/example_package/examples
  208. -|$(PYTHON3_PKG_DIR)/example_package/test_*.py
  209. endef
  210. ```
  211. ### Host-side Python packages for build
  212. These can be installed via pip and ideally they should only be installed like this, because it's a bit simpler than running them through the OpenWrt build system. Build variants on the host-side build are more complicated (and nearly impossible to do sanely) in the current OpenWrt build system.
  213. Which is why [for example] if you need python cffi on the host build, it's easier to just add it via:
  214. ```
  215. HOST_PYTHON3_PACKAGE_BUILD_DEPENDS:="cffi==$(PKG_VERSION)"
  216. ```
  217. [cffi is one of those packages that needs a host-side package installed].
  218. This works reasonably well in the current OpenWrt build system, as binaries get built for this package and get installed in the staging-dir `$(STAGING_DIR)/usr/lib/pythonX.Y/site-packages`.