Browse Source

fix compile issues

yanhe 1 year ago
parent
commit
fee071e6b3
100 changed files with 14597 additions and 43 deletions
  1. 1 1
      build/light-fm/conf/auto.conf
  2. 1 1
      meta-light/recipes-ai/npu/npu-ax3386-gpl.bb
  3. 1 1
      meta-light/recipes-bsp/opensbi/opensbi_0.9.bb
  4. 1 1
      meta-light/recipes-bsp/u-boot/u-boot_2020.10.bbappend
  5. 0 11
      meta-light/recipes-core/images/light-fm-image-ant.bb
  6. 1 1
      meta-light/recipes-extended/efuse-light/efuse-light.bb
  7. 1 1
      meta-light/recipes-extended/image-proprietary/image-proprietary.bb
  8. 1 1
      meta-light/recipes-extended/iso7816-card/iso7816-card.bb
  9. 1 1
      meta-light/recipes-graphics/gfx-examples/gfx-examples.bb
  10. 1 1
      meta-light/recipes-graphics/mesa/mesa.inc
  11. 0 1
      meta-light/recipes-graphics/mesa/mesa_21.0.1.bb
  12. 1 1
      meta-light/recipes-graphics/recipes-gpu/gpu-bxm-4-64-gpl-nulldrmws.bb
  13. 1 1
      meta-light/recipes-graphics/recipes-gpu/gpu-bxm-4-64-gpl.bb
  14. 1 1
      meta-light/recipes-graphics/skia/skia.bb
  15. 1 1
      meta-light/recipes-kernel/linux/linux-thead_5.10.y.bb
  16. 5 5
      meta-light/recipes-multimedia/dsp/xtensa-dsp.bb
  17. 1 1
      meta-light/recipes-multimedia/vi/csi-camera-hal.bb
  18. 1 1
      meta-light/recipes-multimedia/vi/vi-bt.bb
  19. 1 1
      meta-light/recipes-multimedia/vi/vi-kernel.bb
  20. 1 1
      meta-light/recipes-multimedia/vpu/isp-venc-shake.bb
  21. 1 1
      meta-light/recipes-multimedia/vpu/process-linker.bb
  22. 1 1
      meta-light/recipes-multimedia/vpu/video-memory.bb
  23. 1 1
      meta-light/recipes-multimedia/vpu/vpu-omxil-client.bb
  24. 1 1
      meta-light/recipes-multimedia/vpu/vpu-vc8000d-kernel.bb
  25. 1 1
      meta-light/recipes-multimedia/vpu/vpu-vc8000e-kernel.bb
  26. 1 1
      meta-light/recipes-security/rambus/rambus-os-ik-150.bb
  27. 2 1
      meta-openembedded/meta-oe/recipes-devtools/android-tools/android-tools_10.bb
  28. 1 1
      meta-thead/recipes-devtools/fota/fota_1.0.0.bb
  29. 1 1
      meta-thead/recipes-security/op-tee/op-tee_0.1.bb
  30. 2 0
      openembedded-core/bitbake/.gitattributes
  31. 17 0
      openembedded-core/bitbake/.gitignore
  32. 10 0
      openembedded-core/bitbake/AUTHORS
  33. 317 0
      openembedded-core/bitbake/ChangeLog
  34. 29 0
      openembedded-core/bitbake/LICENSE
  35. 288 0
      openembedded-core/bitbake/LICENSE.GPL-2.0-only
  36. 25 0
      openembedded-core/bitbake/LICENSE.MIT
  37. 12 0
      openembedded-core/bitbake/MANIFEST.in
  38. 35 0
      openembedded-core/bitbake/README
  39. 62 0
      openembedded-core/bitbake/TODO
  40. 44 0
      openembedded-core/bitbake/bin/bitbake
  41. 198 0
      openembedded-core/bitbake/bin/bitbake-diffsigs
  42. 1 0
      openembedded-core/bitbake/bin/bitbake-dumpsig
  43. 170 0
      openembedded-core/bitbake/bin/bitbake-hashclient
  44. 62 0
      openembedded-core/bitbake/bin/bitbake-hashserv
  45. 100 0
      openembedded-core/bitbake/bin/bitbake-layers
  46. 59 0
      openembedded-core/bitbake/bin/bitbake-prserv
  47. 74 0
      openembedded-core/bitbake/bin/bitbake-selftest
  48. 54 0
      openembedded-core/bitbake/bin/bitbake-server
  49. 513 0
      openembedded-core/bitbake/bin/bitbake-worker
  50. 169 0
      openembedded-core/bitbake/bin/git-make-shallow
  51. 324 0
      openembedded-core/bitbake/bin/toaster
  52. 113 0
      openembedded-core/bitbake/bin/toaster-eventreplay
  53. 67 0
      openembedded-core/bitbake/classes/base.bbclass
  54. 46 0
      openembedded-core/bitbake/conf/bitbake.conf
  55. 1 0
      openembedded-core/bitbake/contrib/README
  56. 13 0
      openembedded-core/bitbake/contrib/autobuilderlog.json
  57. 31 0
      openembedded-core/bitbake/contrib/bbdev.sh
  58. 89 0
      openembedded-core/bitbake/contrib/bbparse-torture.py
  59. 83 0
      openembedded-core/bitbake/contrib/dump_cache.py
  60. 18 0
      openembedded-core/bitbake/contrib/vim/LICENSE.txt
  61. 24 0
      openembedded-core/bitbake/contrib/vim/ftdetect/bitbake.vim
  62. 13 0
      openembedded-core/bitbake/contrib/vim/ftplugin/bitbake.vim
  63. 343 0
      openembedded-core/bitbake/contrib/vim/indent/bitbake.vim
  64. 88 0
      openembedded-core/bitbake/contrib/vim/plugin/newbb.vim
  65. 46 0
      openembedded-core/bitbake/contrib/vim/plugin/newbbappend.vim
  66. 126 0
      openembedded-core/bitbake/contrib/vim/syntax/bitbake.vim
  67. 1 0
      openembedded-core/bitbake/doc/.gitignore
  68. 339 0
      openembedded-core/bitbake/doc/COPYING.GPL
  69. 17 0
      openembedded-core/bitbake/doc/COPYING.MIT
  70. 35 0
      openembedded-core/bitbake/doc/Makefile
  71. 55 0
      openembedded-core/bitbake/doc/README
  72. 14 0
      openembedded-core/bitbake/doc/_templates/breadcrumbs.html
  73. 7 0
      openembedded-core/bitbake/doc/_templates/layout.html
  74. 733 0
      openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-execution.rst
  75. 652 0
      openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.rst
  76. 415 0
      openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-hello.rst
  77. 651 0
      openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-intro.rst
  78. 1969 0
      openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.rst
  79. 1372 0
      openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-ref-variables.rst
  80. BIN
      openembedded-core/bitbake/doc/bitbake-user-manual/figures/bb_multiconfig_files.png
  81. BIN
      openembedded-core/bitbake/doc/bitbake-user-manual/figures/bitbake-title.png
  82. 142 0
      openembedded-core/bitbake/doc/bitbake.1
  83. 100 0
      openembedded-core/bitbake/doc/conf.py
  84. 3 0
      openembedded-core/bitbake/doc/genindex.rst
  85. 38 0
      openembedded-core/bitbake/doc/index.rst
  86. 130 0
      openembedded-core/bitbake/doc/releases.rst
  87. 233 0
      openembedded-core/bitbake/doc/sphinx-static/switchers.js
  88. 162 0
      openembedded-core/bitbake/doc/sphinx-static/theme_overrides.css
  89. BIN
      openembedded-core/bitbake/doc/template/Vera.ttf
  90. BIN
      openembedded-core/bitbake/doc/template/VeraMoBd.ttf
  91. BIN
      openembedded-core/bitbake/doc/template/VeraMono.ttf
  92. BIN
      openembedded-core/bitbake/doc/template/draft.png
  93. 195 0
      openembedded-core/bitbake/lib/bb/COW.py
  94. 196 0
      openembedded-core/bitbake/lib/bb/__init__.py
  95. 1025 0
      openembedded-core/bitbake/lib/bb/build.py
  96. 1023 0
      openembedded-core/bitbake/lib/bb/cache.py
  97. 63 0
      openembedded-core/bitbake/lib/bb/cache_extra.py
  98. 126 0
      openembedded-core/bitbake/lib/bb/checksum.py
  99. 459 0
      openembedded-core/bitbake/lib/bb/codeparser.py
  100. 744 0
      openembedded-core/bitbake/lib/bb/command.py

+ 1 - 1
build/light-fm/conf/auto.conf

@@ -1,5 +1,5 @@
 # MACHINE ?= "qemuriscv64"
-MACHINE ?= "light-a-val"
+MACHINE ?= "light-a-public-release"
 #IMAGE_FEATURES += "tools-debug"
 #IMAGE_FEATURES += "tools-tweaks"
 #IMAGE_FEATURES += "dbg-pkgs"

+ 1 - 1
meta-light/recipes-ai/npu/npu-ax3386-gpl.bb

@@ -8,7 +8,7 @@ DEPENDS = " linux-thead "
 RDEPENDS_${PN} += " bash "
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/npu-ax3386-kernel.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/npu-ax3386-kernel.git;branch=master;protocol=http \
             file://npu-ax3386.service \
             file://98-npu-ax3386.preset \
           "

+ 1 - 1
meta-light/recipes-bsp/opensbi/opensbi_0.9.bb

@@ -7,7 +7,7 @@ DEPENDS = "e2fsprogs-native"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/opensbi.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/opensbi.git;branch=master;protocol=http \
             file://light_aon_fpga.bin;md5=eb0b2fc3765b2a8771b53915487d8a75 \
             file://light_aon_fpga.elf;md5=09dab875b6bbbbde6b2eeef126f11c8e \
             file://light_c906_audio.bin;md5=d11d1c42e6cbe432279286eac1eae940 \

+ 1 - 1
meta-light/recipes-bsp/u-boot/u-boot_2020.10.bbappend

@@ -1,7 +1,7 @@
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-     git://git@gitee.com/thead-yocto/u-boot.git;branch=master;protocol=ssh \ 
+     git://git@gitee.com/thead-yocto/u-boot.git;branch=master;protocol=http \ 
      file://fw_env.config \
      file://0001-no-strip-fw_printenv.patch \
      file://0002-Add-factory-reset-env-to-uboot.patch \

+ 0 - 11
meta-light/recipes-core/images/light-fm-image-ant.bb

@@ -1,11 +0,0 @@
-DESCRIPTION = "A demo image for light fm commerical image"
-
-require light-fm-image-bsp.bb
-require light-fm-image-security.bb
-
-# // for public release only, disabled by default for internal release
-IMAGE_INSTALL += " image-proprietary "
-IMAGE_INSTALL_remove += "csi-hal-vcodec rambus-os-ik-150 gpu-bxm-4-64 npu-ax3386 thead-fce "
-IMAGE_INSTALL_remove += "thead-ddr-pmu isp-isp8000l libgal-viv libcsi-g2d vpu-omxil "
-
-export IMAGE_BASENAME = "light-fm-image-ant"

+ 1 - 1
meta-light/recipes-extended/efuse-light/efuse-light.bb

@@ -4,7 +4,7 @@ LICENSE = "CLOSED"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/light-libs.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/light-libs.git;branch=master;protocol=http \
           "
 THEAD_BSP_TAG ?= "${AUTOREV}"
 SRCREV = "${THEAD_BSP_TAG}"

+ 1 - 1
meta-light/recipes-extended/image-proprietary/image-proprietary.bb

@@ -6,7 +6,7 @@ COMPATIBLE_MACHINE = "light-*"
 DEPENDS += " linux-thead xtensa-dsp "
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/light-images-proprietary.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/light-images-proprietary.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-extended/iso7816-card/iso7816-card.bb

@@ -4,7 +4,7 @@ LICENSE = "CLOSED"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/light-libs.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/light-libs.git;branch=master;protocol=http \
           "
 THEAD_BSP_TAG ?= "${AUTOREV}"
 SRCREV = "${THEAD_BSP_TAG}"

+ 1 - 1
meta-light/recipes-graphics/gfx-examples/gfx-examples.bb

@@ -9,7 +9,7 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=3ec9956c919ff2e84914fcefc443760b"
 THEAD_LINUX_TAG ?= "${AUTOREV}"
 SRCREV = "${THEAD_LINUX_TAG}"
 
-SRC_URI = "git://git@gitee.com/thead-yocto/gfx-examples.git;branch=master;protocol=ssh"
+SRC_URI = "git://git@gitee.com/thead-yocto/gfx-examples.git;branch=master;protocol=http"
 S = "${WORKDIR}/git"
 
 DEPENDS = "gtk+3 wayland wayland-protocols wayland-native libdrm"

+ 1 - 1
meta-light/recipes-graphics/mesa/mesa.inc

@@ -17,7 +17,7 @@ THEAD_LINUX_TAG ?= "${AUTOREV}"
 SRCREV = "${THEAD_LINUX_TAG}"
 # SRCREV = "320f07c9e1aa42ec1d78f52825379b3f0e5fe8da"
 
-SRC_URI = "git://git@gitee.com/thead-yocto/mesa3d.git;branch=master;protocol=ssh"
+SRC_URI = "git://git@gitee.com/thead-yocto/mesa3d-proprietary.git;branch=master;protocol=http"
 S = "${WORKDIR}/git"
 
 UPSTREAM_CHECK_GITTAGREGEX = "mesa-(?P<pver>\d+(\.\d+)+)"

+ 0 - 1
meta-light/recipes-graphics/mesa/mesa_21.0.1.bb

@@ -1 +0,0 @@
-require ${BPN}.inc

+ 1 - 1
meta-light/recipes-graphics/recipes-gpu/gpu-bxm-4-64-gpl-nulldrmws.bb

@@ -16,7 +16,7 @@ DEPENDS += " \
 "
 inherit pkgconfig
 
-SRC_URI = "git://git@gitee.com/thead-yocto/gpu_bxm_4_64-kernel.git;branch=master;protocol=ssh \
+SRC_URI = "git://git@gitee.com/thead-yocto/gpu_bxm_4_64-kernel.git;branch=master;protocol=http \
            file://.param \
            file://0001-delete-um-for-yocto.patch \
            file://0001-support-parallel-make-for-yocto.patch \

+ 1 - 1
meta-light/recipes-graphics/recipes-gpu/gpu-bxm-4-64-gpl.bb

@@ -17,7 +17,7 @@ DEPENDS += " \
 inherit pkgconfig
 
 SRC_URI = " \
-           git://git@gitee.com/thead-yocto/gpu_bxm_4_64-kernel.git;branch=master;protocol=ssh \
+           git://git@gitee.com/thead-yocto/gpu_bxm_4_64-kernel.git;branch=master;protocol=http \
            file://.param \
            file://0001-delete-um-for-yocto.patch \
            file://0001-support-parallel-make-for-yocto.patch \

+ 1 - 1
meta-light/recipes-graphics/skia/skia.bb

@@ -9,7 +9,7 @@ LIC_FILES_CHKSUM = "file://LICENSE;md5=d25bb58a1be2e1af9b58d31565a206dc"
 THEAD_LINUX_TAG ?= "${AUTOREV}"
 SRCREV = "${THEAD_LINUX_TAG}"
 
-SRC_URI = "git://git@gitee.com/thead-yocto/skia.git;branch=master;protocol=ssh;"
+SRC_URI = "git://git@gitee.com/thead-yocto/skia.git;branch=master;protocol=http;"
 S = "${WORKDIR}/git"
 
 DEPENDS = " llvm-native fontconfig freetype zlib libjpeg-turbo icu python3-native libxkbcommon wayland wayland-protocols wayland-native virtual/mesa vulkan-loader vulkan-headers "

+ 1 - 1
meta-light/recipes-kernel/linux/linux-thead_5.10.y.bb

@@ -3,7 +3,7 @@ require recipes-kernel/linux/linux-yocto.inc
 DEPENDS = "e2fsprogs-native opensbi"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/kernel.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/kernel.git;branch=master;protocol=http \
 "
 # crop the kernel based on the defconfig
 # FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"

+ 5 - 5
meta-light/recipes-multimedia/dsp/xtensa-dsp.bb

@@ -7,24 +7,24 @@ DEPENDS = " openssl cmake-native python3 zlib boost linux-thead vi-bt video-memo
 RDEPENDS_${PN} = "video-memory"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=http \
             file://xtensa-dsp.service \
             file://98-xtensa-dsp.preset\
           "
 SRC_URI_light-fm-bsp-v1.0.6 = " \
-            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=http \
             "
 SRC_URI_light-fm-b-bsp-v1.0.6 = " \
-            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=http \
        "
 SRC_URI_light-fm-a-linux = " \
-            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=http \
             file://xtensa-dsp.service \
             file://98-xtensa-dsp.preset\
        "
 
 SRC_URI_light-fm-b-linux = " \
-            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/xtensa_dsp.git;branch=master;protocol=http \
             file://xtensa-dsp.service \
             file://98-xtensa-dsp.preset\
        "

+ 1 - 1
meta-light/recipes-multimedia/vi/csi-camera-hal.bb

@@ -7,7 +7,7 @@ COMPATIBLE_MACHINE = "light-*"
 DEPENDS += " openssl cmake python3 zlib linux-thead process-linker image-proprietary video-memory"
 DEPENDS += "virtual/kernel linux-libc-headers"
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/csi_hal.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/csi_hal.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-multimedia/vi/vi-bt.bb

@@ -8,7 +8,7 @@ COMPATIBLE_MACHINE = "light-*"
 DEPENDS = " openssl cmake-native python3 zlib boost linux-thead"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/baremetal-drivers.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/baremetal-drivers.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-multimedia/vi/vi-kernel.bb

@@ -5,7 +5,7 @@ COMPATIBLE_MACHINE = "light-*"
 DEPENDS = "linux-thead"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/vi-kernel.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/vi-kernel.git;branch=master;protocol=http \
             file://vi-kernel.service \
             file://98-vi-kernel.preset\
             file://0001-fix-isp-ry-not-free-cma-memroy-issue.patch\

+ 1 - 1
meta-light/recipes-multimedia/vpu/isp-venc-shake.bb

@@ -4,7 +4,7 @@ LICENSE = "CLOSED"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/isp_venc_shake.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/isp_venc_shake.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-multimedia/vpu/process-linker.bb

@@ -4,7 +4,7 @@ LICENSE = "CLOSED"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/process-linker.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/process-linker.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-multimedia/vpu/video-memory.bb

@@ -4,7 +4,7 @@ LICENSE = "CLOSED"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/video_memory.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/video_memory.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-multimedia/vpu/vpu-omxil-client.bb

@@ -4,7 +4,7 @@ LICENSE = "CLOSED"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/vpu-omxil-client.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/vpu-omxil-client.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-multimedia/vpu/vpu-vc8000d-kernel.bb

@@ -5,7 +5,7 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/vpu-vc8000d-kernel.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/vpu-vc8000d-kernel.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-multimedia/vpu/vpu-vc8000e-kernel.bb

@@ -5,7 +5,7 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/vpu-vc8000e-kernel.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/vpu-vc8000e-kernel.git;branch=master;protocol=http \
           "
 
 THEAD_BSP_TAG ?= "${AUTOREV}"

+ 1 - 1
meta-light/recipes-security/rambus/rambus-os-ik-150.bb

@@ -7,7 +7,7 @@ PR = "r0"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/light-libs.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/light-libs.git;branch=master;protocol=http \
           "
 THEAD_BSP_TAG ?= "${AUTOREV}"
 SRCREV = "${THEAD_BSP_TAG}"

+ 2 - 1
meta-openembedded/meta-oe/recipes-devtools/android-tools/android-tools_10.bb

@@ -5,6 +5,7 @@ DEPENDS = "libbsd libpcre zlib libcap"
 DEPENDS_append_class-target = " openssl"
 
 SRC_URI = " \
+    git://git@gitee.com/thead-yocto/d1_adbd.git;branch=master;protocol=http \
     file://adbd-new.mk;subdir=${BPN} \
     file://android-tools-adbd.service"
 
@@ -94,4 +95,4 @@ RDEPENDS_${PN}-fstools = "bash"
 #    ${systemd_unitdir}/system/android-tools-adbd.service \
 #"
 
-BBCLASSEXTEND = "cross"
+BBCLASSEXTEND = "cross"

+ 1 - 1
meta-thead/recipes-devtools/fota/fota_1.0.0.bb

@@ -5,7 +5,7 @@ DEPENDS = " dbus update-rc.d-native "
 RDEPENDS_${PN} += " dbus-lib glib-2.0 bluez5 zlib bash u-boot util-linux-blkid e2fsprogs-mke2fs initscripts-readonly-rootfs-overlay "
 
 SRC_URI = " \
-            git://git@gitee.com/thead-yocto/fota.git;branch=master;protocol=ssh \
+            git://git@gitee.com/thead-yocto/fota.git;branch=master;protocol=http \
             file://0001-fota.patch \
             file://thead_fota.service \
             file://thead_fota.sh \

+ 1 - 1
meta-thead/recipes-security/op-tee/op-tee_0.1.bb

@@ -7,7 +7,7 @@ DEPENDS = "e2fsprogs-native linux-thead"
 COMPATIBLE_MACHINE = "light-*"
 
 SRC_URI = " \
-        git://git@gitee.com/thead-yocto/xuantie-secure-system-image-release.git;branch=master;protocol=ssh \
+        git://git@gitee.com/thead-yocto/xuantie-secure-system-image-release.git;branch=master;protocol=http \
           "
 THEAD_LINUX_TAG ?= "${AUTOREV}"
 SRCREV = "${THEAD_LINUX_TAG}"

+ 2 - 0
openembedded-core/bitbake/.gitattributes

@@ -0,0 +1,2 @@
+*min.js binary
+*min.css binary

+ 17 - 0
openembedded-core/bitbake/.gitignore

@@ -0,0 +1,17 @@
+*.pyc
+*.pyo
+*~
+pyshtables.py
+/doc/manual/html/
+/build/
+/bin/bitbakec
+*.swp
+tags
+*.sqlite
+venv/
+doc/bitbake-user-manual/bitbake-user-manual.html
+doc/bitbake-user-manual/bitbake-user-manual.pdf
+doc/bitbake-user-manual/bitbake-user-manual.tgz
+lib/toaster/contrib/tts/backlog.txt
+lib/toaster/contrib/tts/log/*
+lib/toaster/contrib/tts/.cache/*

+ 10 - 0
openembedded-core/bitbake/AUTHORS

@@ -0,0 +1,10 @@
+Tim Ansell <mithro@mithis.net>
+Phil Blundell <pb@handhelds.org>
+Seb Frankengul <seb@frankengul.org>
+Holger Freyther <holger@moiji-mobile.com>
+Marcin Juszkiewicz <marcin@juszkiewicz.com.pl>
+Chris Larson <kergoth@handhelds.org>
+Ulrich Luckas <luckas@musoft.de>
+Mickey Lauer <mickey@Vanille.de>
+Richard Purdie <rpurdie@rpsys.net>
+Holger Schurig <holgerschurig@gmx.de>

+ 317 - 0
openembedded-core/bitbake/ChangeLog

@@ -0,0 +1,317 @@
+Changes in Bitbake 1.9.x:
+	- Add PE (Package Epoch) support from Philipp Zabel (pH5)
+	- Treat python functions the same as shell functions for logging
+	- Use TMPDIR/anonfunc as a __anonfunc temp directory (T)
+	- Catch truncated cache file errors
+	- Allow operations other than assignment on flag variables
+	- Add code to handle inter-task dependencies
+	- Fix cache errors when generation dotGraphs
+	- Make sure __inherit_cache is updated before calling include() (from Michael Krelin)
+	- Fix bug when target was in ASSUME_PROVIDED (#2236)
+	- Raise ParseError for filenames with multiple underscores instead of infinitely looping (#2062)
+	- Fix invalid regexp in BBMASK error handling (missing import) (#1124)
+	- Promote certain warnings from debug to note 2 level
+	- Update manual
+	- Correctly redirect stdin when forking
+	- If parsing errors are found, exit, too many users miss the errors
+	- Remove supriours PREFERRED_PROVIDER warnings
+	- svn fetcher: Add _buildsvncommand function
+	- Improve certain error messages
+	- Rewrite svn fetcher to make adding extra operations easier 
+	  as part of future SRCDATE="now" fixes
+	  (requires new FETCHCMD_svn definition in bitbake.conf)
+	- Change SVNDIR layout to be more unique (fixes #2644 and #2624)
+	- Add ConfigParsed Event after configuration parsing is complete
+	- Add SRCREV support for svn fetcher
+	- data.emit_var() - only call getVar if we need the variable
+	- Stop generating the A variable (seems to be legacy code)
+	- Make sure intertask depends get processed correcting in recursive depends
+	- Add pn-PN to overrides when evaluating PREFERRED_VERSION
+	- Improve the progress indicator by skipping tasks that have 
+	  already run before starting the build rather than during it
+	- Add profiling option (-P)
+	- Add BB_SRCREV_POLICY variable (clear or cache) to control SRCREV cache
+	- Add SRCREV_FORMAT support
+	- Fix local fetcher's localpath return values
+	- Apply OVERRIDES before performing immediate expansions
+	- Allow the -b -e option combination to take regular expressions
+	- Fix handling of variables with expansion in the name using _append/_prepend
+	  e.g. RRECOMMENDS_${PN}_append_xyz = "abc"
+	- Add plain message function to bb.msg
+	- Sort the list of providers before processing so dependency problems are 
+	  reproducible rather than effectively random
+	- Fix/improve bitbake -s output
+	- Add locking for fetchers so only one tries to fetch a given file at a given time
+	- Fix int(0)/None confusion in runqueue.py which causes random gaps in dependency chains	  
+	- Expand data in addtasks
+	- Print the list of missing DEPENDS,RDEPENDS for the "No buildable providers available for required...."
+	  error message.
+	- Rework add_task to be more efficient (6% speedup, 7% number of function calls reduction)
+	- Sort digraph output to make builds more reproducible
+	- Split expandKeys into two for loops to benefit from the expand_cache (12% speedup)
+	- runqueue.py: Fix idepends handling to avoid dependency errors
+	- Clear the terminal TOSTOP flag if set (and warn the user)
+	- Fix regression from r653 and make SRCDATE/CVSDATE work for packages again
+	- Fix a bug in bb.decodeurl where http://some.where.com/somefile.tgz decoded to host="" (#1530)
+	- Warn about malformed PREFERRED_PROVIDERS (#1072)
+	- Add support for BB_NICE_LEVEL option (#1627)
+	- Psyco is used only on x86 as there is no support for other architectures.
+	- Sort initial providers list by default preference (#1145, #2024)
+	- Improve provider sorting so prefered versions have preference over latest versions (#768)
+	- Detect builds of tasks with overlapping providers and warn (will become a fatal error) (#1359)
+	- Add MULTI_PROVIDER_WHITELIST variable to allow known safe multiple providers to be listed
+	- Handle paths in svn fetcher module parameter
+	- Support the syntax "export VARIABLE"
+	- Add bzr fetcher
+	- Add support for cleaning directories before a task in the form:
+	  do_taskname[cleandirs] = "dir"
+	- bzr fetcher tweaks from Robert Schuster (#2913)
+	- Add mercurial (hg) fetcher from Robert Schuster (#2913)
+	- Don't add duplicates to BBPATH
+	- Fix preferred_version return values (providers.py)
+	- Fix 'depends' flag splitting
+	- Fix unexport handling (#3135)
+	- Add bb.copyfile function similar to bb.movefile (and improve movefile error reporting)
+	- Allow multiple options for deptask flag
+	- Use git-fetch instead of git-pull removing any need for merges when 
+	  fetching (we don't care about the index). Fixes fetch errors.
+	- Add BB_GENERATE_MIRROR_TARBALLS option, set to 0 to make git fetches 
+	  faster at the expense of not creating mirror tarballs.
+	- SRCREV handling updates, improvements and fixes from Poky
+	- Add bb.utils.lockfile() and bb.utils.unlockfile() from Poky
+	- Add support for task selfstamp and lockfiles flags
+	- Disable task number acceleration since it can allow the tasks to run 
+	  out of sequence
+	- Improve runqueue code comments
+	- Add task scheduler abstraction and some example schedulers
+	- Improve circular dependency chain debugging code and user feedback
+	- Don't give a stacktrace for invalid tasks, have a user friendly message (#3431)
+	- Add support for "-e target" (#3432)
+	- Fix shell showdata command (#3259)
+	- Fix shell data updating problems (#1880)
+	- Properly raise errors for invalid source URI protocols
+	- Change the wget fetcher failure handling to avoid lockfile problems
+	- Add support for branches in git fetcher (Otavio Salvador, Michael Lauer)
+	- Make taskdata and runqueue errors more user friendly
+	- Add norecurse and fullpath options to cvs fetcher
+	- Fix exit code for build failures in --continue mode
+	- Fix git branch tags fetching
+	- Change parseConfigurationFile so it works on real data, not a copy
+	- Handle 'base' inherit and all other INHERITs from parseConfigurationFile 
+	  instead of BBHandler
+	- Fix getVarFlags bug in data_smart
+	- Optmise cache handling by more quickly detecting an invalid cache, only 
+	  saving the cache when its changed, moving the cache validity check into
+	  the parsing loop and factoring some getVar calls outside a for loop
+	- Cooker: Remove a debug message from the parsing loop to lower overhead
+	- Convert build.py exec_task to use getVarFlags
+	- Update shell to use cooker.buildFile
+	- Add StampUpdate event
+	- Convert -b option to use taskdata/runqueue
+	- Remove digraph and switch to new stamp checking code. exec_task no longer
+	  honours dependencies
+	- Make fetcher timestamp updating non-fatal when permissions don't allow 
+	  updates
+	- Add BB_SCHEDULER variable/option ("completion" or "speed") controlling
+	  the way bitbake schedules tasks
+	- Add BB_STAMP_POLICY variable/option ("perfile" or "full") controlling
+	  how extensively stamps are looked at for validity
+	- When handling build target failures make sure idepends are checked and
+	  failed where needed. Fixes --continue mode crashes.
+	- Fix -f (force) in conjunction with -b
+	- Fix problems with recrdeptask handling where some idepends weren't handled
+	  correctly.
+	- Handle exit codes correctly (from pH5)
+	- Work around refs/HEAD issues with git over http (#3410)
+	- Add proxy support to the CVS fetcher (from Cyril Chemparathy)
+	- Improve runfetchcmd so errors are seen and various GIT variables are exported
+	- Add ability to fetchers to check URL validity without downloading
+	- Improve runtime PREFERRED_PROVIDERS warning message
+	- Add BB_STAMP_WHITELIST option which contains a list of stamps to ignore when
+	  checking stamp dependencies and using a BB_STAMP_POLICY of "whitelist"
+	- No longer weight providers on the basis of a package being "already staged". This
+	  leads to builds being non-deterministic.
+	- Flush stdout/stderr before forking to fix duplicate console output
+	- Make sure recrdeps tasks include all inter-task dependencies of a given fn
+	- Add bb.runqueue.check_stamp_fn() for use by packaged-staging
+	- Add PERSISTENT_DIR to store the PersistData in a persistent
+	  directory != the cache dir.
+	- Add md5 and sha256 checksum generation functions to utils.py
+	- Correctly handle '-' characters in class names (#2958)
+	- Make sure expandKeys has been called on the data dictionary before running tasks
+	- Correctly add a task override in the form task-TASKNAME.
+	- Revert the '-' character fix in class names since it breaks things
+	- When a regexp fails to compile for PACKAGES_DYNAMIC, print a more useful error (#4444)
+	- Allow to checkout CVS by Date and Time. Just add HHmm to the SRCDATE.
+	- Move prunedir function to utils.py and add explode_dep_versions function
+	- Raise an exception if SRCREV == 'INVALID'
+	- Fix hg fetcher username/password handling and fix crash
+	- Fix PACKAGES_DYNAMIC handling of packages with '++' in the name
+	- Rename __depends to __base_depends after configuration parsing so we don't
+	  recheck the validity of the config files time after time
+	- Add better environmental variable handling. By default it will now only pass certain 
+	  whitelisted variables into the data store. If BB_PRESERVE_ENV is set bitbake will use
+	  all variable from the environment. If BB_ENV_WHITELIST is set, that whitelist will be
+	  used instead of the internal bitbake one. Alternatively, BB_ENV_EXTRAWHITE can be used
+	  to extend the internal whitelist.
+	- Perforce fetcher fix to use commandline options instead of being overriden by the environment
+	- bb.utils.prunedir can cope with symlinks to directoriees without exceptions
+	- use @rev when doing a svn checkout
+	- Add osc fetcher (from Joshua Lock in Poky)
+	- When SRCREV autorevisioning for a recipe is in use, don't cache the recipe
+	- Add tryaltconfigs option to control whether bitbake trys using alternative providers
+	  to fulfil failed dependencies. It defaults to off, changing the default since this
+	  behaviour confuses many users and isn't often useful.
+	- Improve lock file function error handling
+	- Add username handling to the git fetcher (Robert Bragg)
+	- Add support for HTTP_PROXY and HTTP_PROXY_IGNORE variables to the wget fetcher
+	- Export more variables to the fetcher commands to allow ssh checkouts and checkouts through 
+	  proxies to work better. (from Poky)
+	- Also allow user and pswd options in SRC_URIs globally (from Poky)
+	- Improve proxy handling when using mirrors (from Poky)
+	- Add bb.utils.prune_suffix function
+	- Fix hg checkouts of specific revisions (from Poky)
+	- Fix wget fetching of urls with parameters specified (from Poky)
+	- Add username handling to git fetcher (from Poky)
+	- Set HOME environmental variable when running fetcher commands (from Poky)
+	- Make sure allowed variables inherited from the environment are exported again (from Poky)
+	- When running a stage task in bbshell, run populate_staging, not the stage task (from Poky)
+	- Fix + character escaping from PACKAGES_DYNAMIC (thanks Otavio Salvador)
+	- Addition of BBCLASSEXTEND support for allowing one recipe to provide multiple targets (from Poky)
+
+Changes in Bitbake 1.8.0:
+	- Release 1.7.x as a stable series
+
+Changes in BitBake 1.7.x:
+	- Major updates of the dependency handling and execution
+	  of tasks. Code from bin/bitbake replaced with runqueue.py
+	  and taskdata.py
+	- New task execution code supports multithreading with a simplistic
+	  threading algorithm controlled by BB_NUMBER_THREADS
+	- Change of the SVN Fetcher to keep the checkout around
+	  courtsey of Paul Sokolovsky (#1367)
+	- PATH fix to bbimage (#1108)
+	- Allow debug domains to be specified on the commandline (-l)
+	- Allow 'interactive' tasks
+	- Logging message improvements
+	- Drop now uneeded BUILD_ALL_DEPS variable
+	- Add support for wildcards to -b option
+	- Major overhaul of the fetchers making a large amount of code common
+	  including mirroring code
+	- Fetchers now touch md5 stamps upon access (to show activity)
+	- Fix -f force option when used without -b (long standing bug)
+	- Add expand_cache to data_cache.py, caching expanded data (speedup)
+	- Allow version field in DEPENDS (ignored for now)
+	- Add abort flag support to the shell
+	- Make inherit fail if the class doesn't exist (#1478)
+	- Fix data.emit_env() to expand keynames as well as values
+	- Add ssh fetcher
+	- Add perforce fetcher
+	- Make PREFERRED_PROVIDER_foobar defaults to foobar if available
+	- Share the parser's mtime_cache, reducing the number of stat syscalls
+	- Compile all anonfuncs at once! 
+	  *** Anonfuncs must now use common spacing format ***
+	- Memorise the list of handlers in __BBHANDLERS and tasks in __BBTASKS
+	  This removes 2 million function calls resulting in a 5-10% speedup
+	- Add manpage
+	- Update generateDotGraph to use taskData/runQueue improving accuracy
+	  and also adding a task dependency graph
+	- Fix/standardise on GPLv2 licence
+	- Move most functionality from bin/bitbake to cooker.py and split into
+	  separate funcitons
+	- CVS fetcher: Added support for non-default port
+	- Add BBINCLUDELOGS_LINES, the number of lines to read from any logfile
+	- Drop shebangs from lib/bb scripts
+
+Changes in Bitbake 1.6.0:
+	- Better msg handling
+	- COW dict implementation from Tim Ansell (mithro) leading
+	  to better performance
+	- Speed up of -s
+
+Changes in Bitbake 1.4.4:
+	- SRCDATE now handling courtsey Justin Patrin
+	- #1017 fix to work with rm_work
+
+Changes in BitBake 1.4.2:
+	- Send logs to oe.pastebin.com instead of pastebin.com
+	  fixes #856
+	- Copy the internal bitbake data before building the
+	  dependency graph. This fixes nano not having a
+	  virtual/libc dependency
+	- Allow multiple TARBALL_STASH entries
+	- Cache, check if the directory exists before changing
+	  into it
+	- git speedup cloning by not doing a checkout
+	- allow to have spaces in filenames (.conf, .bb, .bbclass)
+
+Changes in BitBake 1.4.0:
+	- Fix to check both RDEPENDS and RDEPENDS_${PN}
+	- Fix a RDEPENDS parsing bug in utils:explode_deps()
+	- Update git fetcher behaviour to match git changes
+	- ASSUME_PROVIDED allowed to include runtime packages
+	- git fetcher cleanup and efficency improvements
+	- Change the format of the cache
+	- Update usermanual to document the Fetchers
+	- Major changes to caching with a new strategy
+	  giving a major performance increase when reparsing
+	  with few data changes
+
+Changes in BitBake 1.3.3:
+	- Create a new Fetcher module to ease the
+	  development of new Fetchers.
+	  Issue #438 fixed by rpurdie@openedhand.com
+	- Make the Subversion fetcher honor the SRC Date
+	  (CVSDATE).
+	  Issue #555 fixed by chris@openedhand.com
+	- Expand PREFERRED_PROVIDER properly
+	  Issue #436 fixed by rprudie@openedhand.com
+	- Typo fix for Issue #531 by Philipp Zabel for the
+	  BitBake Shell
+	- Introduce a new special variable SRCDATE as
+	  a generic naming to replace CVSDATE.
+	- Introduce a new keyword 'required'. In contrast
+	  to 'include' parsing will fail if a to be included
+	  file can not be found.
+	- Remove hardcoding of the STAMP directory. Patch
+	  courtsey pHilipp Zabel
+	- Track the RDEPENDS of each package (rpurdie@openedhand.com)
+	- Introduce BUILD_ALL_DEPS to build all RDEPENDS. E.g
+	  this is used by the OpenEmbedded Meta Packages.
+	  (rpurdie@openedhand.com).
+
+Changes in BitBake 1.3.2:
+	- reintegration of make.py into BitBake
+	- bbread is gone, use bitbake -e
+	- lots of shell updates and bugfixes
+	- Introduction of the .= and =. operator
+	- Sort variables, keys and groups in bitdoc
+	- Fix regression in the handling of BBCOLLECTIONS
+	- Update the bitbake usermanual
+
+Changes in BitBake 1.3.0:
+	- add bitbake interactive shell (bitbake -i)
+	- refactor bitbake utility in OO style
+	- kill default arguments in methods in the bb.data module
+	- kill default arguments in methods in the bb.fetch module
+	- the http/https/ftp fetcher will fail if the to be 
+	  downloaded file was not found in DL_DIR (this is needed
+	  to avoid unpacking the sourceforge mirror page)
+	- Switch to a cow like data instance for persistent and non
+	  persisting mode (called data_smart.py)
+	- Changed the callback of bb.make.collect_bbfiles to carry
+	  additional parameters
+	- Drastically reduced the amount of needed RAM by not holding
+	  each data instance in memory when using a cache/persistent
+	  storage
+
+Changes in BitBake 1.2.1:
+	The 1.2.1 release is meant as a intermediate release to lay the
+	ground for more radical changes. The most notable changes are:
+
+	- Do not hardcode {}, use bb.data.init() instead if you want to
+	  get a instance of a data class
+	- bb.data.init() is a factory and the old bb.data methods are delegates
+	- Do not use deepcopy use bb.data.createCopy() instead.
+	- Removed default arguments in bb.fetch
+

+ 29 - 0
openembedded-core/bitbake/LICENSE

@@ -0,0 +1,29 @@
+BitBake is licensed under the GNU General Public License version 2.0. See 
+LICENSE.GPL-2.0-only for further details.
+
+Individual files contain the following style tags instead of the full license text:
+
+    SPDX-License-Identifier:	GPL-2.0-only
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/
+
+
+The following external components are distributed with this software:
+
+* The Toaster Simple UI application is based upon the Django project template, the files of which are covered by the BSD license and are copyright (c) Django Software
+Foundation and individual contributors.
+
+* Twitter Bootstrap (including Glyphicons), redistributed under the MIT license
+* jQuery is redistributed under the MIT license.
+
+* Twitter typeahead.js redistributed under the MIT license. Note that the JS source has one small modification, so the full unminified file is currently included to make it obvious where this is.
+
+* jsrender is redistributed under the MIT license.
+
+* QUnit is redistributed under the MIT license.
+
+* Font Awesome fonts redistributed under the SIL Open Font License 1.1
+
+* simplediff is distributed under the zlib license.
+

+ 288 - 0
openembedded-core/bitbake/LICENSE.GPL-2.0-only

@@ -0,0 +1,288 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+Note:
+Individual files contain the following tag instead of the full license text.
+
+    SPDX-License-Identifier: GPL-2.0-only
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/

+ 25 - 0
openembedded-core/bitbake/LICENSE.MIT

@@ -0,0 +1,25 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+Note:
+Individual files contain the following tag instead of the full license text.
+
+    SPDX-License-Identifier: MIT
+
+This enables machine processing of license information based on the SPDX
+License Identifiers that are here available: http://spdx.org/licenses/

+ 12 - 0
openembedded-core/bitbake/MANIFEST.in

@@ -0,0 +1,12 @@
+include ChangeLog
+include AUTHORS
+include LICENSE
+include LICENSE.GPL-2.0-only
+include LICENSE.MIT
+include contrib/*
+include contrib/vim/*/*
+include conf/*
+include classes/*
+include doc/*
+include doc/manual/*
+include ez_setup.py

+ 35 - 0
openembedded-core/bitbake/README

@@ -0,0 +1,35 @@
+Bitbake
+=======
+
+BitBake is a generic task execution engine that allows shell and Python tasks to be run
+efficiently and in parallel while working within complex inter-task dependency constraints.
+One of BitBake's main users, OpenEmbedded, takes this core and builds embedded Linux software
+stacks using a task-oriented approach.
+
+For information about Bitbake, see the OpenEmbedded website:
+    http://www.openembedded.org/
+
+Bitbake plain documentation can be found under the doc directory or its integrated
+html version at the Yocto Project website:
+    http://yoctoproject.org/documentation
+
+Contributing
+------------
+
+Please refer to
+http://www.openembedded.org/wiki/How_to_submit_a_patch_to_OpenEmbedded
+for guidelines on how to submit patches, just note that the latter documentation is intended
+for OpenEmbedded (and its core) not bitbake patches (bitbake-devel@lists.openembedded.org)
+but in general main guidelines apply. Once the commit(s) have been created, the way to send
+the patch is through git-send-email. For example, to send the last commit (HEAD) on current
+branch, type:
+
+    git send-email -M -1 --to bitbake-devel@lists.openembedded.org
+
+Mailing list:
+
+    http://lists.openembedded.org/mailman/listinfo/bitbake-devel
+
+Source code:
+
+    http://git.openembedded.org/bitbake/

+ 62 - 0
openembedded-core/bitbake/TODO

@@ -0,0 +1,62 @@
+- Reimplement the interactive mode as a proper ui
+- Continue dropping fatal/SystemExit/sys.exit usage in favor of raising
+  appropriate exceptions
+- Continue pylint / pyflakes / pychecker / pep8 fixups
+- Drop os.system usage in favor of direct subprocess usage or a subprocess
+  wrapper
+- Kill the execution of 'tee' for the task log file in build.py
+- Fix up the exception handling
+
+  - Kill exec_task's catch of FuncFailed, instead catch it in the other
+    callers of exec_task/exec_func
+  - What exactly is the purpose of the "EventException"?  I can see using an
+    exception like that, *perhaps*, to abstract away exceptions raised by
+    event handlers, but it has no place in bb.build.exec_task
+
+- BUG: if you chmod 000 local.conf, it silently doesn't parse it, when it
+  should really fail, so the user can fix the problem.
+
+- Audit bb.fatal usage - these should all be able to be replaced with
+  exceptions
+- Figure out how to handle the ncurses UI.  Should some of our logging
+  formatting stuff be made common to all of bitbake, or perhaps all UIs via
+  the UIHelper?
+
+Long term, high impact:
+
+  - Change override application to actually *move* it over -- so the original
+    override specific version of the variable goes away, rather than sticking
+    around as a duplicate.
+  - Change the behavior when a variable is referenced and is unset.  Today, it
+    evaluates to ${FOO} and then shell has a chance to expand it, but this is
+    far from ideal.  We had considered evaluating it to the empty string, but
+    that has other potential problems.  Frans Meulenbroeks has proposed just
+    erroring when this occurs, as we can always define default values for the
+    variables in bitbake.conf.  This seems reasonable.  My only concern with
+    that is the case where you want to reference a shell variable with odd
+    characters in it -- where you'd have to use ${} style shell variable
+    expansion rather than normal $.  To handle that case, we'd really need a
+    way to escape / disable bitbake variable expansion, \${} perhaps.
+
+Uncertain:
+
+  - Leverage the python 2.6 multiprocessing module
+
+    - Worker processes for bb.cooker
+    - Server / UI processes
+
+  - Create a bitbake configuration class which is utilized by the library, not
+    just bin/bitbake.  This class should be responsible for extracting
+    configuration parameters from the metadata for bitbake internal use, as well
+    as pulling specific items like BBDEBUG, and importing settings from an
+    optparse options object.
+
+  - Python version bits
+
+    - Utilize the new string formatting where appropriate
+    - Do we need to take into account the bytes literals changes?
+    - Do we have any file-like objects that would benefit from using the "io"
+      module?
+    - Do we want to leverage the abstract base classes in collections?
+    - Aside: Set methods now accept multiple iterables
+

+ 44 - 0
openembedded-core/bitbake/bin/bitbake

@@ -0,0 +1,44 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2003, 2004  Chris Larson
+# Copyright (C) 2003, 2004  Phil Blundell
+# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
+# Copyright (C) 2005        Holger Hans Peter Freyther
+# Copyright (C) 2005        ROAD GmbH
+# Copyright (C) 2006        Richard Purdie
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os
+import sys
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),
+                                'lib'))
+try:
+    import bb
+except RuntimeError as exc:
+    sys.exit(str(exc))
+
+from bb import cookerdata
+from bb.main import bitbake_main, BitBakeConfigParameters, BBMainException
+
+if sys.getfilesystemencoding() != "utf-8":
+    sys.exit("Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).\nPython can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.")
+
+__version__ = "1.48.0"
+
+if __name__ == "__main__":
+    if __version__ != bb.__version__:
+        sys.exit("Bitbake core version and program version mismatch!")
+    try:
+        sys.exit(bitbake_main(BitBakeConfigParameters(sys.argv),
+                              cookerdata.CookerConfiguration()))
+    except BBMainException as err:
+        sys.exit(err)
+    except bb.BBHandledException:
+        sys.exit(1)
+    except Exception:
+        import traceback
+        traceback.print_exc()
+        sys.exit(1)

+ 198 - 0
openembedded-core/bitbake/bin/bitbake-diffsigs

@@ -0,0 +1,198 @@
+#!/usr/bin/env python3
+
+# bitbake-diffsigs / bitbake-dumpsig
+# BitBake task signature data dump and comparison utility
+#
+# Copyright (C) 2012-2013, 2017 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os
+import sys
+import warnings
+import argparse
+import logging
+import pickle
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+
+import bb.tinfoil
+import bb.siggen
+import bb.msg
+
+myname = os.path.basename(sys.argv[0])
+logger = bb.msg.logger_create(myname)
+
+is_dump = myname == 'bitbake-dumpsig'
+
+def find_siginfo(tinfoil, pn, taskname, sigs=None):
+    result = None
+    tinfoil.set_event_mask(['bb.event.FindSigInfoResult',
+                            'logging.LogRecord',
+                            'bb.command.CommandCompleted',
+                            'bb.command.CommandFailed'])
+    ret = tinfoil.run_command('findSigInfo', pn, taskname, sigs)
+    if ret:
+        while True:
+            event = tinfoil.wait_event(1)
+            if event:
+                if isinstance(event, bb.command.CommandCompleted):
+                    break
+                elif isinstance(event, bb.command.CommandFailed):
+                    logger.error(str(event))
+                    sys.exit(2)
+                elif isinstance(event, bb.event.FindSigInfoResult):
+                    result = event.result
+                elif isinstance(event, logging.LogRecord):
+                    logger.handle(event)
+    else:
+        logger.error('No result returned from findSigInfo command')
+        sys.exit(2)
+    return result
+
+def find_siginfo_task(bbhandler, pn, taskname, sig1=None, sig2=None):
+    """ Find the most recent signature files for the specified PN/task """
+
+    if not taskname.startswith('do_'):
+        taskname = 'do_%s' % taskname
+
+    if sig1 and sig2:
+        sigfiles = find_siginfo(bbhandler, pn, taskname, [sig1, sig2])
+        if len(sigfiles) == 0:
+            logger.error('No sigdata files found matching %s %s matching either %s or %s' % (pn, taskname, sig1, sig2))
+            sys.exit(1)
+        elif not sig1 in sigfiles:
+            logger.error('No sigdata files found matching %s %s with signature %s' % (pn, taskname, sig1))
+            sys.exit(1)
+        elif not sig2 in sigfiles:
+            logger.error('No sigdata files found matching %s %s with signature %s' % (pn, taskname, sig2))
+            sys.exit(1)
+        latestfiles = [sigfiles[sig1], sigfiles[sig2]]
+    else:
+        filedates = find_siginfo(bbhandler, pn, taskname)
+        latestfiles = sorted(filedates.keys(), key=lambda f: filedates[f])[-2:]
+        if not latestfiles:
+            logger.error('No sigdata files found matching %s %s' % (pn, taskname))
+            sys.exit(1)
+
+    return latestfiles
+
+
+# Define recursion callback
+def recursecb(key, hash1, hash2):
+    hashes = [hash1, hash2]
+    hashfiles = find_siginfo(tinfoil, key, None, hashes)
+
+    recout = []
+    if len(hashfiles) == 0:
+        recout.append("Unable to find matching sigdata for %s with hashes %s or %s" % (key, hash1, hash2))
+    elif not hash1 in hashfiles:
+        recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash1))
+    elif not hash2 in hashfiles:
+        recout.append("Unable to find matching sigdata for %s with hash %s" % (key, hash2))
+    else:
+        out2 = bb.siggen.compare_sigfiles(hashfiles[hash1], hashfiles[hash2], recursecb, color=color)
+        for change in out2:
+            for line in change.splitlines():
+                recout.append('    ' + line)
+
+    return recout
+
+
+parser = argparse.ArgumentParser(
+    description=("Dumps" if is_dump else "Compares") + " siginfo/sigdata files written out by BitBake")
+
+parser.add_argument('-D', '--debug',
+                    help='Enable debug output',
+                    action='store_true')
+
+if is_dump:
+    parser.add_argument("-t", "--task",
+            help="find the signature data file for the last run of the specified task",
+            action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
+
+    parser.add_argument("sigdatafile1",
+            help="Signature file to dump. Not used when using -t/--task.",
+            action="store", nargs='?', metavar="sigdatafile")
+else:
+    parser.add_argument('-c', '--color',
+            help='Colorize the output (where %(metavar)s is %(choices)s)',
+            choices=['auto', 'always', 'never'], default='auto', metavar='color')
+
+    parser.add_argument('-d', '--dump',
+            help='Dump the last signature data instead of comparing (equivalent to using bitbake-dumpsig)',
+            action='store_true')
+
+    parser.add_argument("-t", "--task",
+            help="find the signature data files for the last two runs of the specified task and compare them",
+            action="store", dest="taskargs", nargs=2, metavar=('recipename', 'taskname'))
+
+    parser.add_argument("-s", "--signature",
+            help="With -t/--task, specify the signatures to look for instead of taking the last two",
+            action="store", dest="sigargs", nargs=2, metavar=('fromsig', 'tosig'))
+
+    parser.add_argument("sigdatafile1",
+            help="First signature file to compare (or signature file to dump, if second not specified). Not used when using -t/--task.",
+            action="store", nargs='?')
+
+    parser.add_argument("sigdatafile2",
+            help="Second signature file to compare",
+            action="store", nargs='?')
+
+options = parser.parse_args()
+if is_dump:
+    options.color = 'never'
+    options.dump = True
+    options.sigdatafile2 = None
+    options.sigargs = None
+
+if options.debug:
+    logger.setLevel(logging.DEBUG)
+
+color = (options.color == 'always' or (options.color == 'auto' and sys.stdout.isatty()))
+
+if options.taskargs:
+    with bb.tinfoil.Tinfoil() as tinfoil:
+        tinfoil.prepare(config_only=True)
+        if not options.dump and options.sigargs:
+            files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1], options.sigargs[0], options.sigargs[1])
+        else:
+            files = find_siginfo_task(tinfoil, options.taskargs[0], options.taskargs[1])
+
+        if options.dump:
+            logger.debug("Signature file: %s" % files[-1])
+            output = bb.siggen.dump_sigfile(files[-1])
+        else:
+            if len(files) < 2:
+                logger.error('Only one matching sigdata file found for the specified task (%s %s)' % (options.taskargs[0], options.taskargs[1]))
+                sys.exit(1)
+
+            # Recurse into signature comparison
+            logger.debug("Signature file (previous): %s" % files[-2])
+            logger.debug("Signature file (latest): %s" % files[-1])
+            output = bb.siggen.compare_sigfiles(files[-2], files[-1], recursecb, color=color)
+else:
+    if options.sigargs:
+        logger.error('-s/--signature can only be used together with -t/--task')
+        sys.exit(1)
+    try:
+        if not options.dump and options.sigdatafile1 and options.sigdatafile2:
+            with bb.tinfoil.Tinfoil() as tinfoil:
+                tinfoil.prepare(config_only=True)
+                output = bb.siggen.compare_sigfiles(options.sigdatafile1, options.sigdatafile2, recursecb, color=color)
+        elif options.sigdatafile1:
+            output = bb.siggen.dump_sigfile(options.sigdatafile1)
+        else:
+            logger.error('Must specify signature file(s) or -t/--task')
+            parser.print_help()
+            sys.exit(1)
+    except IOError as e:
+        logger.error(str(e))
+        sys.exit(1)
+    except (pickle.UnpicklingError, EOFError):
+        logger.error('Invalid signature data - ensure you are specifying sigdata/siginfo files')
+        sys.exit(1)
+
+if output:
+    print('\n'.join(output))

+ 1 - 0
openembedded-core/bitbake/bin/bitbake-dumpsig

@@ -0,0 +1 @@
+bitbake-diffsigs

+ 170 - 0
openembedded-core/bitbake/bin/bitbake-hashclient

@@ -0,0 +1,170 @@
+#! /usr/bin/env python3
+#
+# Copyright (C) 2019 Garmin Ltd.
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import argparse
+import hashlib
+import logging
+import os
+import pprint
+import sys
+import threading
+import time
+
+try:
+    import tqdm
+    ProgressBar = tqdm.tqdm
+except ImportError:
+    class ProgressBar(object):
+        def __init__(self, *args, **kwargs):
+            pass
+
+        def __enter__(self):
+            return self
+
+        def __exit__(self, *args, **kwargs):
+            pass
+
+        def update(self):
+            pass
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib'))
+
+import hashserv
+
+DEFAULT_ADDRESS = 'unix://./hashserve.sock'
+METHOD = 'stress.test.method'
+
+
+def main():
+    def handle_stats(args, client):
+        if args.reset:
+            s = client.reset_stats()
+        else:
+            s = client.get_stats()
+        pprint.pprint(s)
+        return 0
+
+    def handle_stress(args, client):
+        def thread_main(pbar, lock):
+            nonlocal found_hashes
+            nonlocal missed_hashes
+            nonlocal max_time
+
+            client = hashserv.create_client(args.address)
+
+            for i in range(args.requests):
+                taskhash = hashlib.sha256()
+                taskhash.update(args.taskhash_seed.encode('utf-8'))
+                taskhash.update(str(i).encode('utf-8'))
+
+                start_time = time.perf_counter()
+                l = client.get_unihash(METHOD, taskhash.hexdigest())
+                elapsed = time.perf_counter() - start_time
+
+                with lock:
+                    if l:
+                        found_hashes += 1
+                    else:
+                        missed_hashes += 1
+
+                    max_time = max(elapsed, max_time)
+                    pbar.update()
+
+        max_time = 0
+        found_hashes = 0
+        missed_hashes = 0
+        lock = threading.Lock()
+        total_requests = args.clients * args.requests
+        start_time = time.perf_counter()
+        with ProgressBar(total=total_requests) as pbar:
+            threads = [threading.Thread(target=thread_main, args=(pbar, lock), daemon=False) for _ in range(args.clients)]
+            for t in threads:
+                t.start()
+
+            for t in threads:
+                t.join()
+
+        elapsed = time.perf_counter() - start_time
+        with lock:
+            print("%d requests in %.1fs. %.1f requests per second" % (total_requests, elapsed, total_requests / elapsed))
+            print("Average request time %.8fs" % (elapsed / total_requests))
+            print("Max request time was %.8fs" % max_time)
+            print("Found %d hashes, missed %d" % (found_hashes, missed_hashes))
+
+        if args.report:
+            with ProgressBar(total=args.requests) as pbar:
+                for i in range(args.requests):
+                    taskhash = hashlib.sha256()
+                    taskhash.update(args.taskhash_seed.encode('utf-8'))
+                    taskhash.update(str(i).encode('utf-8'))
+
+                    outhash = hashlib.sha256()
+                    outhash.update(args.outhash_seed.encode('utf-8'))
+                    outhash.update(str(i).encode('utf-8'))
+
+                    client.report_unihash(taskhash.hexdigest(), METHOD, outhash.hexdigest(), taskhash.hexdigest())
+
+                    with lock:
+                        pbar.update()
+
+    parser = argparse.ArgumentParser(description='Hash Equivalence Client')
+    parser.add_argument('--address', default=DEFAULT_ADDRESS, help='Server address (default "%(default)s")')
+    parser.add_argument('--log', default='WARNING', help='Set logging level')
+
+    subparsers = parser.add_subparsers()
+
+    stats_parser = subparsers.add_parser('stats', help='Show server stats')
+    stats_parser.add_argument('--reset', action='store_true',
+                              help='Reset server stats')
+    stats_parser.set_defaults(func=handle_stats)
+
+    stress_parser = subparsers.add_parser('stress', help='Run stress test')
+    stress_parser.add_argument('--clients', type=int, default=10,
+                               help='Number of simultaneous clients')
+    stress_parser.add_argument('--requests', type=int, default=1000,
+                               help='Number of requests each client will perform')
+    stress_parser.add_argument('--report', action='store_true',
+                               help='Report new hashes')
+    stress_parser.add_argument('--taskhash-seed', default='',
+                               help='Include string in taskhash')
+    stress_parser.add_argument('--outhash-seed', default='',
+                               help='Include string in outhash')
+    stress_parser.set_defaults(func=handle_stress)
+
+    args = parser.parse_args()
+
+    logger = logging.getLogger('hashserv')
+
+    level = getattr(logging, args.log.upper(), None)
+    if not isinstance(level, int):
+        raise ValueError('Invalid log level: %s' % args.log)
+
+    logger.setLevel(level)
+    console = logging.StreamHandler()
+    console.setLevel(level)
+    logger.addHandler(console)
+
+    func = getattr(args, 'func', None)
+    if func:
+        client = hashserv.create_client(args.address)
+        # Try to establish a connection to the server now to detect failures
+        # early
+        client.connect()
+
+        return func(args, client)
+
+    return 0
+
+
+if __name__ == '__main__':
+    try:
+        ret = main()
+    except Exception:
+        ret = 1
+        import traceback
+        traceback.print_exc()
+    sys.exit(ret)

+ 62 - 0
openembedded-core/bitbake/bin/bitbake-hashserv

@@ -0,0 +1,62 @@
+#! /usr/bin/env python3
+#
+# Copyright (C) 2018 Garmin Ltd.
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os
+import sys
+import logging
+import argparse
+import sqlite3
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib'))
+
+import hashserv
+
+VERSION = "1.0.0"
+
+DEFAULT_BIND = 'unix://./hashserve.sock'
+
+
+def main():
+    parser = argparse.ArgumentParser(description='Hash Equivalence Reference Server. Version=%s' % VERSION,
+                                     epilog='''The bind address is the path to a unix domain socket if it is
+                                               prefixed with "unix://". Otherwise, it is an IP address
+                                               and port in form ADDRESS:PORT. To bind to all addresses, leave
+                                               the ADDRESS empty, e.g. "--bind :8686". To bind to a specific
+                                               IPv6 address, enclose the address in "[]", e.g.
+                                               "--bind [::1]:8686"'''
+                                     )
+
+    parser.add_argument('--bind', default=DEFAULT_BIND, help='Bind address (default "%(default)s")')
+    parser.add_argument('--database', default='./hashserv.db', help='Database file (default "%(default)s")')
+    parser.add_argument('--log', default='WARNING', help='Set logging level')
+
+    args = parser.parse_args()
+
+    logger = logging.getLogger('hashserv')
+
+    level = getattr(logging, args.log.upper(), None)
+    if not isinstance(level, int):
+        raise ValueError('Invalid log level: %s' % args.log)
+
+    logger.setLevel(level)
+    console = logging.StreamHandler()
+    console.setLevel(level)
+    logger.addHandler(console)
+
+    server = hashserv.create_server(args.bind, args.database)
+    server.serve_forever()
+    return 0
+
+
+if __name__ == '__main__':
+    try:
+        ret = main()
+    except Exception:
+        ret = 1
+        import traceback
+        traceback.print_exc()
+    sys.exit(ret)

+ 100 - 0
openembedded-core/bitbake/bin/bitbake-layers

@@ -0,0 +1,100 @@
+#!/usr/bin/env python3
+
+# This script has subcommands which operate against your bitbake layers, either
+# displaying useful information, or acting against them.
+# See the help output for details on available commands.
+
+# Copyright (C) 2011 Mentor Graphics Corporation
+# Copyright (C) 2011-2015 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import logging
+import os
+import sys
+import argparse
+
+bindir = os.path.dirname(__file__)
+topdir = os.path.dirname(bindir)
+sys.path[0:0] = [os.path.join(topdir, 'lib')]
+
+import bb.tinfoil
+import bb.msg
+
+logger = bb.msg.logger_create('bitbake-layers', sys.stdout)
+
+def main():
+    parser = argparse.ArgumentParser(
+        description="BitBake layers utility",
+        epilog="Use %(prog)s <subcommand> --help to get help on a specific command",
+        add_help=False)
+    parser.add_argument('-d', '--debug', help='Enable debug output', action='store_true')
+    parser.add_argument('-q', '--quiet', help='Print only errors', action='store_true')
+    parser.add_argument('-F', '--force', help='Force add without recipe parse verification', action='store_true')
+    parser.add_argument('--color', choices=['auto', 'always', 'never'], default='auto', help='Colorize output (where %(metavar)s is %(choices)s)', metavar='COLOR')
+
+    global_args, unparsed_args = parser.parse_known_args()
+
+    # Help is added here rather than via add_help=True, as we don't want it to
+    # be handled by parse_known_args()
+    parser.add_argument('-h', '--help', action='help', default=argparse.SUPPRESS,
+                        help='show this help message and exit')
+    subparsers = parser.add_subparsers(title='subcommands', metavar='<subcommand>')
+    subparsers.required = True
+
+    if global_args.debug:
+        logger.setLevel(logging.DEBUG)
+    elif global_args.quiet:
+        logger.setLevel(logging.ERROR)
+
+    # Need to re-run logger_create with color argument
+    # (will be the same logger since it has the same name)
+    bb.msg.logger_create('bitbake-layers', output=sys.stdout,
+                         color=global_args.color,
+                         level=logger.getEffectiveLevel())
+
+    plugins = []
+    tinfoil = bb.tinfoil.Tinfoil(tracking=True)
+    tinfoil.logger.setLevel(logger.getEffectiveLevel())
+    try:
+        tinfoil.prepare(True)
+        for path in ([topdir] +
+                    tinfoil.config_data.getVar('BBPATH').split(':')):
+            pluginpath = os.path.join(path, 'lib', 'bblayers')
+            bb.utils.load_plugins(logger, plugins, pluginpath)
+
+        registered = False
+        for plugin in plugins:
+            if hasattr(plugin, 'register_commands'):
+                registered = True
+                plugin.register_commands(subparsers)
+            if hasattr(plugin, 'tinfoil_init'):
+                plugin.tinfoil_init(tinfoil)
+
+        if not registered:
+            logger.error("No commands registered - missing plugins?")
+            sys.exit(1)
+
+        args = parser.parse_args(unparsed_args, namespace=global_args)
+
+        if getattr(args, 'parserecipes', False):
+            tinfoil.config_data.disableTracking()
+            tinfoil.parse_recipes()
+            tinfoil.config_data.enableTracking()
+
+        return args.func(args)
+    finally:
+        tinfoil.shutdown()
+
+
+if __name__ == "__main__":
+    try:
+        ret = main()
+    except bb.BBHandledException:
+        ret = 1
+    except Exception:
+        ret = 1
+        import traceback
+        traceback.print_exc()
+    sys.exit(ret)

+ 59 - 0
openembedded-core/bitbake/bin/bitbake-prserv

@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os
+import sys,logging
+import optparse
+
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)),'lib'))
+
+import prserv
+import prserv.serv
+
+__version__="1.0.0"
+
+PRHOST_DEFAULT='0.0.0.0'
+PRPORT_DEFAULT=8585
+
+def main():
+    parser = optparse.OptionParser(
+        version="Bitbake PR Service Core version %s, %%prog version %s" % (prserv.__version__, __version__),
+        usage = "%prog < --start | --stop > [options]")
+
+    parser.add_option("-f", "--file", help="database filename(default: prserv.sqlite3)", action="store",
+                      dest="dbfile", type="string", default="prserv.sqlite3")
+    parser.add_option("-l", "--log", help="log filename(default: prserv.log)", action="store",
+                      dest="logfile", type="string", default="prserv.log")
+    parser.add_option("--loglevel", help="logging level, i.e. CRITICAL, ERROR, WARNING, INFO, DEBUG",
+                      action = "store", type="string", dest="loglevel", default = "INFO")
+    parser.add_option("--start", help="start daemon",
+                      action="store_true", dest="start")
+    parser.add_option("--stop", help="stop daemon",
+                      action="store_true", dest="stop")
+    parser.add_option("--host", help="ip address to bind", action="store",
+                      dest="host", type="string", default=PRHOST_DEFAULT)
+    parser.add_option("--port", help="port number(default: 8585)", action="store",
+                      dest="port", type="int", default=PRPORT_DEFAULT)
+
+    options, args = parser.parse_args(sys.argv)
+    prserv.init_logger(os.path.abspath(options.logfile),options.loglevel)
+
+    if options.start:
+        ret=prserv.serv.start_daemon(options.dbfile, options.host, options.port,os.path.abspath(options.logfile))
+    elif options.stop:
+        ret=prserv.serv.stop_daemon(options.host, options.port)
+    else:
+        ret=parser.print_help()
+    return ret
+
+if __name__ == "__main__":
+    try:
+        ret = main()
+    except Exception:
+        ret = 1
+        import traceback
+        traceback.print_exc()
+    sys.exit(ret)
+

+ 74 - 0
openembedded-core/bitbake/bin/bitbake-selftest

@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2012 Richard Purdie
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os
+import sys, logging
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib'))
+
+import unittest
+try:
+    import bb
+    import hashserv
+    import layerindexlib
+except RuntimeError as exc:
+    sys.exit(str(exc))
+
+tests = ["bb.tests.codeparser",
+         "bb.tests.color",
+         "bb.tests.cooker",
+         "bb.tests.cow",
+         "bb.tests.data",
+         "bb.tests.event",
+         "bb.tests.fetch",
+         "bb.tests.parse",
+         "bb.tests.persist_data",
+         "bb.tests.runqueue",
+         "bb.tests.siggen",
+         "bb.tests.utils",
+         "hashserv.tests",
+         "layerindexlib.tests.layerindexobj",
+         "layerindexlib.tests.restapi",
+         "layerindexlib.tests.cooker"]
+
+for t in tests:
+    t = '.'.join(t.split('.')[:3])
+    __import__(t)
+
+
+# Set-up logging
+class StdoutStreamHandler(logging.StreamHandler):
+    """Special handler so that unittest is able to capture stdout"""
+    def __init__(self):
+        # Override __init__() because we don't want to set self.stream here
+        logging.Handler.__init__(self)
+
+    @property
+    def stream(self):
+        # We want to dynamically write wherever sys.stdout is pointing to
+        return sys.stdout
+
+
+handler = StdoutStreamHandler()
+bb.logger.addHandler(handler)
+bb.logger.setLevel(logging.DEBUG)
+
+
+ENV_HELP = """\
+Environment variables:
+  BB_SKIP_NETTESTS      set to 'yes' in order to skip tests using network
+                        connection
+  BB_TMPDIR_NOCLEAN     set to 'yes' to preserve test tmp directories
+"""
+
+class main(unittest.main):
+    def _print_help(self, *args, **kwargs):
+        super(main, self)._print_help(*args, **kwargs)
+        print(ENV_HELP)
+
+
+if __name__ == '__main__':
+        main(defaultTest=tests, buffer=True)

+ 54 - 0
openembedded-core/bitbake/bin/bitbake-server

@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Copyright (C) 2020        Richard Purdie
+#
+
+import os
+import sys
+import warnings
+import logging
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+
+if sys.getfilesystemencoding() != "utf-8":
+    sys.exit("Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).\nPython can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.")
+
+# Users shouldn't be running this code directly
+if len(sys.argv) != 10 or not sys.argv[1].startswith("decafbad"):
+    print("bitbake-server is meant for internal execution by bitbake itself, please don't use it standalone.")
+    sys.exit(1)
+
+import bb.server.process
+
+lockfd = int(sys.argv[2])
+readypipeinfd = int(sys.argv[3])
+logfile = sys.argv[4]
+lockname = sys.argv[5]
+sockname = sys.argv[6]
+timeout = sys.argv[7]
+xmlrpcinterface = (sys.argv[8], int(sys.argv[9]))
+if xmlrpcinterface[0] == "None":
+    xmlrpcinterface = (None, xmlrpcinterface[1])
+if timeout == "None":
+    timeout = None
+
+# Replace standard fds with our own
+with open('/dev/null', 'r') as si:
+    os.dup2(si.fileno(), sys.stdin.fileno())
+
+so = open(logfile, 'a+')
+os.dup2(so.fileno(), sys.stdout.fileno())
+os.dup2(so.fileno(), sys.stderr.fileno())
+
+# Have stdout and stderr be the same so log output matches chronologically
+# and there aren't two seperate buffers
+sys.stderr = sys.stdout
+
+logger = logging.getLogger("BitBake")
+# Ensure logging messages get sent to the UI as events
+handler = bb.event.LogHandler()
+logger.addHandler(handler)
+
+bb.server.process.execServer(lockfd, readypipeinfd, lockname, sockname, timeout, xmlrpcinterface)
+

+ 513 - 0
openembedded-core/bitbake/bin/bitbake-worker

@@ -0,0 +1,513 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os
+import sys
+import warnings
+sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(sys.argv[0])), 'lib'))
+from bb import fetch2
+import logging
+import bb
+import select
+import errno
+import signal
+import pickle
+import traceback
+import queue
+from multiprocessing import Lock
+from threading import Thread
+
+if sys.getfilesystemencoding() != "utf-8":
+    sys.exit("Please use a locale setting which supports UTF-8 (such as LANG=en_US.UTF-8).\nPython can't change the filesystem locale after loading so we need a UTF-8 when Python starts or things won't work.")
+
+# Users shouldn't be running this code directly
+if len(sys.argv) != 2 or not sys.argv[1].startswith("decafbad"):
+    print("bitbake-worker is meant for internal execution by bitbake itself, please don't use it standalone.")
+    sys.exit(1)
+
+profiling = False
+if sys.argv[1].startswith("decafbadbad"):
+    profiling = True
+    try:
+        import cProfile as profile
+    except:
+        import profile
+
+# Unbuffer stdout to avoid log truncation in the event
+# of an unorderly exit as well as to provide timely
+# updates to log files for use with tail
+try:
+    if sys.stdout.name == '<stdout>':
+        import fcntl
+        fl = fcntl.fcntl(sys.stdout.fileno(), fcntl.F_GETFL)
+        fl |= os.O_SYNC 
+        fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, fl)
+        #sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+except:
+    pass
+
+logger = logging.getLogger("BitBake")
+
+worker_pipe = sys.stdout.fileno()
+bb.utils.nonblockingfd(worker_pipe)
+# Need to guard against multiprocessing being used in child processes
+# and multiple processes trying to write to the parent at the same time
+worker_pipe_lock = None
+
+handler = bb.event.LogHandler()
+logger.addHandler(handler)
+
+if 0:
+    # Code to write out a log file of all events passing through the worker
+    logfilename = "/tmp/workerlogfile"
+    format_str = "%(levelname)s: %(message)s"
+    conlogformat = bb.msg.BBLogFormatter(format_str)
+    consolelog = logging.FileHandler(logfilename)
+    consolelog.setFormatter(conlogformat)
+    logger.addHandler(consolelog)
+
+worker_queue = queue.Queue()
+
+def worker_fire(event, d):
+    data = b"<event>" + pickle.dumps(event) + b"</event>"
+    worker_fire_prepickled(data)
+
+def worker_fire_prepickled(event):
+    global worker_queue
+
+    worker_queue.put(event)
+
+#
+# We can end up with write contention with the cooker, it can be trying to send commands
+# and we can be trying to send event data back. Therefore use a separate thread for writing 
+# back data to cooker.
+#
+worker_thread_exit = False
+
+def worker_flush(worker_queue):
+    worker_queue_int = b""
+    global worker_pipe, worker_thread_exit
+
+    while True:
+        try:
+            worker_queue_int = worker_queue_int + worker_queue.get(True, 1)
+        except queue.Empty:
+            pass
+        while (worker_queue_int or not worker_queue.empty()):
+            try:
+                (_, ready, _) = select.select([], [worker_pipe], [], 1)
+                if not worker_queue.empty():
+                    worker_queue_int = worker_queue_int + worker_queue.get()
+                written = os.write(worker_pipe, worker_queue_int)
+                worker_queue_int = worker_queue_int[written:]
+            except (IOError, OSError) as e:
+                if e.errno != errno.EAGAIN and e.errno != errno.EPIPE:
+                    raise
+        if worker_thread_exit and worker_queue.empty() and not worker_queue_int:
+            return
+
+worker_thread = Thread(target=worker_flush, args=(worker_queue,))
+worker_thread.start()
+
+def worker_child_fire(event, d):
+    global worker_pipe
+    global worker_pipe_lock
+
+    data = b"<event>" + pickle.dumps(event) + b"</event>"
+    try:
+        worker_pipe_lock.acquire()
+        worker_pipe.write(data)
+        worker_pipe_lock.release()
+    except IOError:
+        sigterm_handler(None, None)
+        raise
+
+bb.event.worker_fire = worker_fire
+
+lf = None
+#lf = open("/tmp/workercommandlog", "w+")
+def workerlog_write(msg):
+    if lf:
+        lf.write(msg)
+        lf.flush()
+
+def sigterm_handler(signum, frame):
+    signal.signal(signal.SIGTERM, signal.SIG_DFL)
+    os.killpg(0, signal.SIGTERM)
+    sys.exit()
+
+def fork_off_task(cfg, data, databuilder, workerdata, fn, task, taskname, taskhash, unihash, appends, taskdepdata, extraconfigdata, quieterrors=False, dry_run_exec=False):
+    # We need to setup the environment BEFORE the fork, since
+    # a fork() or exec*() activates PSEUDO...
+
+    envbackup = {}
+    fakeenv = {}
+    umask = None
+
+    taskdep = workerdata["taskdeps"][fn]
+    if 'umask' in taskdep and taskname in taskdep['umask']:
+        # umask might come in as a number or text string..
+        try:
+             umask = int(taskdep['umask'][taskname],8)
+        except TypeError:
+             umask = taskdep['umask'][taskname]
+
+    dry_run = cfg.dry_run or dry_run_exec
+
+    # We can't use the fakeroot environment in a dry run as it possibly hasn't been built
+    if 'fakeroot' in taskdep and taskname in taskdep['fakeroot'] and not dry_run:
+        envvars = (workerdata["fakerootenv"][fn] or "").split()
+        for key, value in (var.split('=') for var in envvars):
+            envbackup[key] = os.environ.get(key)
+            os.environ[key] = value
+            fakeenv[key] = value
+
+        fakedirs = (workerdata["fakerootdirs"][fn] or "").split()
+        for p in fakedirs:
+            bb.utils.mkdirhier(p)
+        logger.debug(2, 'Running %s:%s under fakeroot, fakedirs: %s' %
+                        (fn, taskname, ', '.join(fakedirs)))
+    else:
+        envvars = (workerdata["fakerootnoenv"][fn] or "").split()
+        for key, value in (var.split('=') for var in envvars):
+            envbackup[key] = os.environ.get(key)
+            os.environ[key] = value
+            fakeenv[key] = value
+
+    sys.stdout.flush()
+    sys.stderr.flush()
+
+    try:
+        pipein, pipeout = os.pipe()
+        pipein = os.fdopen(pipein, 'rb', 4096)
+        pipeout = os.fdopen(pipeout, 'wb', 0)
+        pid = os.fork()
+    except OSError as e:
+        logger.critical("fork failed: %d (%s)" % (e.errno, e.strerror))
+        sys.exit(1)
+
+    if pid == 0:
+        def child():
+            global worker_pipe
+            global worker_pipe_lock
+            pipein.close()
+
+            bb.utils.signal_on_parent_exit("SIGTERM")
+
+            # Save out the PID so that the event can include it the
+            # events
+            bb.event.worker_pid = os.getpid()
+            bb.event.worker_fire = worker_child_fire
+            worker_pipe = pipeout
+            worker_pipe_lock = Lock()
+
+            # Make the child the process group leader and ensure no
+            # child process will be controlled by the current terminal
+            # This ensures signals sent to the controlling terminal like Ctrl+C
+            # don't stop the child processes.
+            os.setsid()
+
+            signal.signal(signal.SIGTERM, sigterm_handler)
+            # Let SIGHUP exit as SIGTERM
+            signal.signal(signal.SIGHUP, sigterm_handler)
+
+            # No stdin
+            newsi = os.open(os.devnull, os.O_RDWR)
+            os.dup2(newsi, sys.stdin.fileno())
+
+            if umask:
+                os.umask(umask)
+
+            try:
+                bb_cache = bb.cache.NoCache(databuilder)
+                (realfn, virtual, mc) = bb.cache.virtualfn2realfn(fn)
+                the_data = databuilder.mcdata[mc]
+                the_data.setVar("BB_WORKERCONTEXT", "1")
+                the_data.setVar("BB_TASKDEPDATA", taskdepdata)
+                if cfg.limited_deps:
+                    the_data.setVar("BB_LIMITEDDEPS", "1")
+                the_data.setVar("BUILDNAME", workerdata["buildname"])
+                the_data.setVar("DATE", workerdata["date"])
+                the_data.setVar("TIME", workerdata["time"])
+                for varname, value in extraconfigdata.items():
+                    the_data.setVar(varname, value)
+
+                bb.parse.siggen.set_taskdata(workerdata["sigdata"])
+                if "newhashes" in workerdata:
+                    bb.parse.siggen.set_taskhashes(workerdata["newhashes"])
+                ret = 0
+
+                the_data = bb_cache.loadDataFull(fn, appends)
+                the_data.setVar('BB_TASKHASH', taskhash)
+                the_data.setVar('BB_UNIHASH', unihash)
+
+                bb.utils.set_process_name("%s:%s" % (the_data.getVar("PN"), taskname.replace("do_", "")))
+
+                # exported_vars() returns a generator which *cannot* be passed to os.environ.update() 
+                # successfully. We also need to unset anything from the environment which shouldn't be there 
+                exports = bb.data.exported_vars(the_data)
+
+                bb.utils.empty_environment()
+                for e, v in exports:
+                    os.environ[e] = v
+
+                for e in fakeenv:
+                    os.environ[e] = fakeenv[e]
+                    the_data.setVar(e, fakeenv[e])
+                    the_data.setVarFlag(e, 'export', "1")
+
+                task_exports = the_data.getVarFlag(taskname, 'exports')
+                if task_exports:
+                    for e in task_exports.split():
+                        the_data.setVarFlag(e, 'export', '1')
+                        v = the_data.getVar(e)
+                        if v is not None:
+                            os.environ[e] = v
+
+                if quieterrors:
+                    the_data.setVarFlag(taskname, "quieterrors", "1")
+
+            except Exception:
+                if not quieterrors:
+                    logger.critical(traceback.format_exc())
+                os._exit(1)
+            try:
+                if dry_run:
+                    return 0
+                return bb.build.exec_task(fn, taskname, the_data, cfg.profile)
+            except:
+                os._exit(1)
+        if not profiling:
+            os._exit(child())
+        else:
+            profname = "profile-%s.log" % (fn.replace("/", "-") + "-" + taskname)
+            prof = profile.Profile()
+            try: 
+                ret = profile.Profile.runcall(prof, child)
+            finally:
+                prof.dump_stats(profname)
+                bb.utils.process_profilelog(profname)
+                os._exit(ret)
+    else:
+        for key, value in iter(envbackup.items()):
+            if value is None:
+                del os.environ[key]
+            else:
+                os.environ[key] = value
+
+    return pid, pipein, pipeout
+
+class runQueueWorkerPipe():
+    """
+    Abstraction for a pipe between a worker thread and the worker server
+    """
+    def __init__(self, pipein, pipeout):
+        self.input = pipein
+        if pipeout:
+            pipeout.close()
+        bb.utils.nonblockingfd(self.input)
+        self.queue = b""
+
+    def read(self):
+        start = len(self.queue)
+        try:
+            self.queue = self.queue + (self.input.read(102400) or b"")
+        except (OSError, IOError) as e:
+            if e.errno != errno.EAGAIN:
+                raise
+
+        end = len(self.queue)
+        index = self.queue.find(b"</event>")
+        while index != -1:
+            worker_fire_prepickled(self.queue[:index+8])
+            self.queue = self.queue[index+8:]
+            index = self.queue.find(b"</event>")
+        return (end > start)
+
+    def close(self):
+        while self.read():
+            continue
+        if len(self.queue) > 0:
+            print("Warning, worker child left partial message: %s" % self.queue)
+        self.input.close()
+
+normalexit = False
+
+class BitbakeWorker(object):
+    def __init__(self, din):
+        self.input = din
+        bb.utils.nonblockingfd(self.input)
+        self.queue = b""
+        self.cookercfg = None
+        self.databuilder = None
+        self.data = None
+        self.extraconfigdata = None
+        self.build_pids = {}
+        self.build_pipes = {}
+    
+        signal.signal(signal.SIGTERM, self.sigterm_exception)
+        # Let SIGHUP exit as SIGTERM
+        signal.signal(signal.SIGHUP, self.sigterm_exception)
+        if "beef" in sys.argv[1]:
+            bb.utils.set_process_name("Worker (Fakeroot)")
+        else:
+            bb.utils.set_process_name("Worker")
+
+    def sigterm_exception(self, signum, stackframe):
+        if signum == signal.SIGTERM:
+            bb.warn("Worker received SIGTERM, shutting down...")
+        elif signum == signal.SIGHUP:
+            bb.warn("Worker received SIGHUP, shutting down...")
+        self.handle_finishnow(None)
+        signal.signal(signal.SIGTERM, signal.SIG_DFL)
+        os.kill(os.getpid(), signal.SIGTERM)
+
+    def serve(self):        
+        while True:
+            (ready, _, _) = select.select([self.input] + [i.input for i in self.build_pipes.values()], [] , [], 1)
+            if self.input in ready:
+                try:
+                    r = self.input.read()
+                    if len(r) == 0:
+                        # EOF on pipe, server must have terminated
+                        self.sigterm_exception(signal.SIGTERM, None)
+                    self.queue = self.queue + r
+                except (OSError, IOError):
+                    pass
+            if len(self.queue):
+                self.handle_item(b"cookerconfig", self.handle_cookercfg)
+                self.handle_item(b"extraconfigdata", self.handle_extraconfigdata)
+                self.handle_item(b"workerdata", self.handle_workerdata)
+                self.handle_item(b"newtaskhashes", self.handle_newtaskhashes)
+                self.handle_item(b"runtask", self.handle_runtask)
+                self.handle_item(b"finishnow", self.handle_finishnow)
+                self.handle_item(b"ping", self.handle_ping)
+                self.handle_item(b"quit", self.handle_quit)
+
+            for pipe in self.build_pipes:
+                if self.build_pipes[pipe].input in ready:
+                    self.build_pipes[pipe].read()
+            if len(self.build_pids):
+                while self.process_waitpid():
+                    continue
+
+
+    def handle_item(self, item, func):
+        if self.queue.startswith(b"<" + item + b">"):
+            index = self.queue.find(b"</" + item + b">")
+            while index != -1:
+                func(self.queue[(len(item) + 2):index])
+                self.queue = self.queue[(index + len(item) + 3):]
+                index = self.queue.find(b"</" + item + b">")
+
+    def handle_cookercfg(self, data):
+        self.cookercfg = pickle.loads(data)
+        self.databuilder = bb.cookerdata.CookerDataBuilder(self.cookercfg, worker=True)
+        self.databuilder.parseBaseConfiguration()
+        self.data = self.databuilder.data
+
+    def handle_extraconfigdata(self, data):
+        self.extraconfigdata = pickle.loads(data)
+
+    def handle_workerdata(self, data):
+        self.workerdata = pickle.loads(data)
+        bb.build.verboseShellLogging = self.workerdata["build_verbose_shell"]
+        bb.build.verboseStdoutLogging = self.workerdata["build_verbose_stdout"]
+        bb.msg.loggerDefaultLogLevel = self.workerdata["logdefaultlevel"]
+        bb.msg.loggerDefaultDomains = self.workerdata["logdefaultdomain"]
+        for mc in self.databuilder.mcdata:
+            self.databuilder.mcdata[mc].setVar("PRSERV_HOST", self.workerdata["prhost"])
+            self.databuilder.mcdata[mc].setVar("BB_HASHSERVE", self.workerdata["hashservaddr"])
+
+    def handle_newtaskhashes(self, data):
+        self.workerdata["newhashes"] = pickle.loads(data)
+
+    def handle_ping(self, _):
+        workerlog_write("Handling ping\n")
+
+        logger.warning("Pong from bitbake-worker!")
+
+    def handle_quit(self, data):
+        workerlog_write("Handling quit\n")
+
+        global normalexit
+        normalexit = True
+        sys.exit(0)
+
+    def handle_runtask(self, data):
+        fn, task, taskname, taskhash, unihash, quieterrors, appends, taskdepdata, dry_run_exec = pickle.loads(data)
+        workerlog_write("Handling runtask %s %s %s\n" % (task, fn, taskname))
+
+        pid, pipein, pipeout = fork_off_task(self.cookercfg, self.data, self.databuilder, self.workerdata, fn, task, taskname, taskhash, unihash, appends, taskdepdata, self.extraconfigdata, quieterrors, dry_run_exec)
+
+        self.build_pids[pid] = task
+        self.build_pipes[pid] = runQueueWorkerPipe(pipein, pipeout)
+
+    def process_waitpid(self):
+        """
+        Return none is there are no processes awaiting result collection, otherwise
+        collect the process exit codes and close the information pipe.
+        """
+        try:
+            pid, status = os.waitpid(-1, os.WNOHANG)
+            if pid == 0 or os.WIFSTOPPED(status):
+                return False
+        except OSError:
+            return False
+
+        workerlog_write("Exit code of %s for pid %s\n" % (status, pid))
+
+        if os.WIFEXITED(status):
+            status = os.WEXITSTATUS(status)
+        elif os.WIFSIGNALED(status):
+            # Per shell conventions for $?, when a process exits due to
+            # a signal, we return an exit code of 128 + SIGNUM
+            status = 128 + os.WTERMSIG(status)
+
+        task = self.build_pids[pid]
+        del self.build_pids[pid]
+
+        self.build_pipes[pid].close()
+        del self.build_pipes[pid]
+
+        worker_fire_prepickled(b"<exitcode>" + pickle.dumps((task, status)) + b"</exitcode>")
+
+        return True
+
+    def handle_finishnow(self, _):
+        if self.build_pids:
+            logger.info("Sending SIGTERM to remaining %s tasks", len(self.build_pids))
+            for k, v in iter(self.build_pids.items()):
+                try:
+                    os.kill(-k, signal.SIGTERM)
+                    os.waitpid(-1, 0)
+                except:
+                    pass
+        for pipe in self.build_pipes:
+            self.build_pipes[pipe].read()
+
+try:
+    worker = BitbakeWorker(os.fdopen(sys.stdin.fileno(), 'rb'))
+    if not profiling:
+        worker.serve()
+    else:
+        profname = "profile-worker.log"
+        prof = profile.Profile()
+        try:
+            profile.Profile.runcall(prof, worker.serve)
+        finally:
+            prof.dump_stats(profname)
+            bb.utils.process_profilelog(profname)
+except BaseException as e:
+    if not normalexit:
+        import traceback
+        sys.stderr.write(traceback.format_exc())
+        sys.stderr.write(str(e))
+
+worker_thread_exit = True
+worker_thread.join()
+
+workerlog_write("exitting")
+sys.exit(0)

+ 169 - 0
openembedded-core/bitbake/bin/git-make-shallow

@@ -0,0 +1,169 @@
+#!/usr/bin/env python3
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+"""git-make-shallow: make the current git repository shallow
+
+Remove the history of the specified revisions, then optionally filter the
+available refs to those specified.
+"""
+
+import argparse
+import collections
+import errno
+import itertools
+import os
+import subprocess
+import sys
+
+version = 1.0
+
+
+def main():
+    if sys.version_info < (3, 4, 0):
+        sys.exit('Python 3.4 or greater is required')
+
+    git_dir = check_output(['git', 'rev-parse', '--git-dir']).rstrip()
+    shallow_file = os.path.join(git_dir, 'shallow')
+    if os.path.exists(shallow_file):
+        try:
+            check_output(['git', 'fetch', '--unshallow'])
+        except subprocess.CalledProcessError:
+            try:
+                os.unlink(shallow_file)
+            except OSError as exc:
+                if exc.errno != errno.ENOENT:
+                    raise
+
+    args = process_args()
+    revs = check_output(['git', 'rev-list'] + args.revisions).splitlines()
+
+    make_shallow(shallow_file, args.revisions, args.refs)
+
+    ref_revs = check_output(['git', 'rev-list'] + args.refs).splitlines()
+    remaining_history = set(revs) & set(ref_revs)
+    for rev in remaining_history:
+        if check_output(['git', 'rev-parse', '{}^@'.format(rev)]):
+            sys.exit('Error: %s was not made shallow' % rev)
+
+    filter_refs(args.refs)
+
+    if args.shrink:
+        shrink_repo(git_dir)
+        subprocess.check_call(['git', 'fsck', '--unreachable'])
+
+
+def process_args():
+    # TODO: add argument to automatically keep local-only refs, since they
+    # can't be easily restored with a git fetch.
+    parser = argparse.ArgumentParser(description='Remove the history of the specified revisions, then optionally filter the available refs to those specified.')
+    parser.add_argument('--ref', '-r', metavar='REF', action='append', dest='refs', help='remove all but the specified refs (cumulative)')
+    parser.add_argument('--shrink', '-s', action='store_true', help='shrink the git repository by repacking and pruning')
+    parser.add_argument('revisions', metavar='REVISION', nargs='+', help='a git revision/commit')
+    if len(sys.argv) < 2:
+        parser.print_help()
+        sys.exit(2)
+
+    args = parser.parse_args()
+
+    if args.refs:
+        args.refs = check_output(['git', 'rev-parse', '--symbolic-full-name'] + args.refs).splitlines()
+    else:
+        args.refs = get_all_refs(lambda r, t, tt: t == 'commit' or tt == 'commit')
+
+    args.refs = list(filter(lambda r: not r.endswith('/HEAD'), args.refs))
+    args.revisions = check_output(['git', 'rev-parse'] + ['%s^{}' % i for i in args.revisions]).splitlines()
+    return args
+
+
+def check_output(cmd, input=None):
+    return subprocess.check_output(cmd, universal_newlines=True, input=input)
+
+
+def make_shallow(shallow_file, revisions, refs):
+    """Remove the history of the specified revisions."""
+    for rev in follow_history_intersections(revisions, refs):
+        print("Processing %s" % rev)
+        with open(shallow_file, 'a') as f:
+            f.write(rev + '\n')
+
+
+def get_all_refs(ref_filter=None):
+    """Return all the existing refs in this repository, optionally filtering the refs."""
+    ref_output = check_output(['git', 'for-each-ref', '--format=%(refname)\t%(objecttype)\t%(*objecttype)'])
+    ref_split = [tuple(iter_extend(l.rsplit('\t'), 3)) for l in ref_output.splitlines()]
+    if ref_filter:
+        ref_split = (e for e in ref_split if ref_filter(*e))
+    refs = [r[0] for r in ref_split]
+    return refs
+
+
+def iter_extend(iterable, length, obj=None):
+    """Ensure that iterable is the specified length by extending with obj."""
+    return itertools.islice(itertools.chain(iterable, itertools.repeat(obj)), length)
+
+
+def filter_refs(refs):
+    """Remove all but the specified refs from the git repository."""
+    all_refs = get_all_refs()
+    to_remove = set(all_refs) - set(refs)
+    if to_remove:
+        check_output(['xargs', '-0', '-n', '1', 'git', 'update-ref', '-d', '--no-deref'],
+                     input=''.join(l + '\0' for l in to_remove))
+
+
+def follow_history_intersections(revisions, refs):
+    """Determine all the points where the history of the specified revisions intersects the specified refs."""
+    queue = collections.deque(revisions)
+    seen = set()
+
+    for rev in iter_except(queue.popleft, IndexError):
+        if rev in seen:
+            continue
+
+        parents = check_output(['git', 'rev-parse', '%s^@' % rev]).splitlines()
+
+        yield rev
+        seen.add(rev)
+
+        if not parents:
+            continue
+
+        check_refs = check_output(['git', 'merge-base', '--independent'] + sorted(refs)).splitlines()
+        for parent in parents:
+            for ref in check_refs:
+                print("Checking %s vs %s" % (parent, ref))
+                try:
+                    merge_base = check_output(['git', 'merge-base', parent, ref]).rstrip()
+                except subprocess.CalledProcessError:
+                    continue
+                else:
+                    queue.append(merge_base)
+
+
+def iter_except(func, exception, start=None):
+    """Yield a function repeatedly until it raises an exception."""
+    try:
+        if start is not None:
+            yield start()
+        while True:
+            yield func()
+    except exception:
+        pass
+
+
+def shrink_repo(git_dir):
+    """Shrink the newly shallow repository, removing the unreachable objects."""
+    subprocess.check_call(['git', 'reflog', 'expire', '--expire-unreachable=now', '--all'])
+    subprocess.check_call(['git', 'repack', '-ad'])
+    try:
+        os.unlink(os.path.join(git_dir, 'objects', 'info', 'alternates'))
+    except OSError as exc:
+        if exc.errno != errno.ENOENT:
+            raise
+    subprocess.check_call(['git', 'prune', '--expire', 'now'])
+
+
+if __name__ == '__main__':
+    main()

+ 324 - 0
openembedded-core/bitbake/bin/toaster

@@ -0,0 +1,324 @@
+#!/bin/echo ERROR: This script needs to be sourced. Please run as .
+
+# toaster - shell script to start Toaster
+
+# Copyright (C) 2013-2015 Intel Corp.
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+HELP="
+Usage 1: source toaster start|stop [webport=<address:port>] [noweb] [nobuild] [toasterdir]
+    Optional arguments:
+        [nobuild] Setup the environment for capturing builds with toaster but disable managed builds
+        [noweb] Setup the environment for capturing builds with toaster but don't start the web server
+        [webport] Set the development server (default: localhost:8000)
+        [toasterdir] Set absolute path to be used as TOASTER_DIR (default: BUILDDIR/../)
+Usage 2: source toaster manage [createsuperuser|lsupdates|migrate|makemigrations|checksettings|collectstatic|...]
+"
+
+custom_extention()
+{
+    custom_extension=$BBBASEDIR/lib/toaster/orm/fixtures/custom_toaster_append.sh
+    if [ -f $custom_extension ] ; then
+        $custom_extension $*
+    fi
+}
+
+databaseCheck()
+{
+    retval=0
+    # you can always add a superuser later via
+    # ../bitbake/lib/toaster/manage.py createsuperuser --username=<ME>
+    $MANAGE migrate --noinput || retval=1
+
+    if [ $retval -eq 1 ]; then
+        echo "Failed migrations, aborting system start" 1>&2
+        return $retval
+    fi
+    # Make sure that checksettings can pick up any value for TEMPLATECONF
+    export TEMPLATECONF
+    $MANAGE checksettings --traceback || retval=1
+
+    if [ $retval -eq 1 ]; then
+        printf "\nError while checking settings; aborting\n"
+        return $retval
+    fi
+
+    return $retval
+}
+
+webserverKillAll()
+{
+    local pidfile
+    if [ -f ${BUILDDIR}/.toastermain.pid ] ; then
+        custom_extention web_stop_postpend
+    else
+        custom_extention noweb_stop_postpend
+    fi
+    for pidfile in ${BUILDDIR}/.toastermain.pid ${BUILDDIR}/.runbuilds.pid; do
+        if [ -f ${pidfile} ]; then
+            pid=`cat ${pidfile}`
+            while kill -0 $pid 2>/dev/null; do
+                kill -SIGTERM $pid 2>/dev/null
+                sleep 1
+            done
+            rm  ${pidfile}
+        fi
+    done
+}
+
+webserverStartAll()
+{
+    # do not start if toastermain points to a valid process
+    if ! cat "${BUILDDIR}/.toastermain.pid" 2>/dev/null | xargs -I{} kill -0 {} ; then
+        retval=1
+        rm "${BUILDDIR}/.toastermain.pid"
+    fi
+
+    retval=0
+
+    # check the database
+    databaseCheck || return 1
+
+    echo "Starting webserver..."
+
+    $MANAGE runserver --noreload "$ADDR_PORT" \
+           </dev/null >>${BUILDDIR}/toaster_web.log 2>&1 \
+           & echo $! >${BUILDDIR}/.toastermain.pid
+
+    sleep 1
+
+    if ! cat "${BUILDDIR}/.toastermain.pid" | xargs -I{} kill -0 {} ; then
+        retval=1
+        rm "${BUILDDIR}/.toastermain.pid"
+    else
+        echo "Toaster development webserver started at http://$ADDR_PORT"
+        echo -e "\nYou can now run 'bitbake <target>' on the command line and monitor your build in Toaster.\nYou can also use a Toaster project to configure and run a build.\n"
+        custom_extention web_start_postpend $ADDR_PORT
+    fi
+
+    return $retval
+}
+
+INSTOPSYSTEM=0
+
+# define the stop command
+stop_system()
+{
+    # prevent reentry
+    if [ $INSTOPSYSTEM -eq 1 ]; then return; fi
+    INSTOPSYSTEM=1
+    webserverKillAll
+    # unset exported variables
+    unset TOASTER_DIR
+    unset BITBAKE_UI
+    unset BBBASEDIR
+    trap - SIGHUP
+    #trap - SIGCHLD
+    INSTOPSYSTEM=0
+}
+
+verify_prereq() {
+    # Verify Django version
+    reqfile=$(python3 -c "import os; print(os.path.realpath('$BBBASEDIR/toaster-requirements.txt'))")
+    exp='s/Django\([><=]\+\)\([^,]\+\),\([><=]\+\)\(.\+\)/'
+    # expand version parts to 2 digits to support 1.10.x > 1.8
+    # (note:helper functions hard to insert in-line)
+    exp=$exp'import sys,django;'
+    exp=$exp'version=["%02d" % int(n) for n in django.get_version().split(".")];'
+    exp=$exp'vmin=["%02d" % int(n) for n in "\2".split(".")];'
+    exp=$exp'vmax=["%02d" % int(n) for n in "\4".split(".")];'
+    exp=$exp'sys.exit(not (version \1 vmin and version \3 vmax))'
+    exp=$exp'/p'
+    if ! sed -n "$exp" $reqfile | python3 - ; then
+        req=`grep ^Django $reqfile`
+        echo "This program needs $req"
+        echo "Please install with pip3 install -r $reqfile"
+        return 2
+    fi
+
+    return 0
+}
+
+# read command line parameters
+if [ -n "$BASH_SOURCE" ] ; then
+    TOASTER=${BASH_SOURCE}
+elif [ -n "$ZSH_NAME" ] ; then
+    TOASTER=${(%):-%x}
+else
+    TOASTER=$0
+fi
+
+export BBBASEDIR=`dirname $TOASTER`/..
+MANAGE="python3 $BBBASEDIR/lib/toaster/manage.py"
+if [ -z "$OE_ROOT" ]; then
+    OE_ROOT=`dirname $TOASTER`/../..
+fi
+
+# this is the configuraton file we are using for toaster
+# we are using the same logic that oe-setup-builddir uses
+# (based on TEMPLATECONF and .templateconf) to determine
+# which toasterconf.json to use.
+# note: There are a number of relative path assumptions
+# in the local layers that currently make using an arbitrary
+# toasterconf.json difficult.
+
+. $OE_ROOT/.templateconf
+if [ -n "$TEMPLATECONF" ]; then
+    if [ ! -d "$TEMPLATECONF" ]; then
+        # Allow TEMPLATECONF=meta-xyz/conf as a shortcut
+        if [ -d "$OE_ROOT/$TEMPLATECONF" ]; then
+            TEMPLATECONF="$OE_ROOT/$TEMPLATECONF"
+        fi
+    fi
+fi
+
+unset OE_ROOT
+
+
+WEBSERVER=1
+export TOASTER_BUILDSERVER=1
+ADDR_PORT="localhost:8000"
+TOASTERDIR=`dirname $BUILDDIR`
+unset CMD
+for param in $*; do
+    case $param in
+    noweb )
+            WEBSERVER=0
+    ;;
+    nobuild )
+            TOASTER_BUILDSERVER=0
+    ;;
+    start )
+            CMD=$param
+    ;;
+    stop )
+            CMD=$param
+    ;;
+    webport=*)
+            ADDR_PORT="${param#*=}"
+            # Split the addr:port string
+            ADDR=`echo $ADDR_PORT | cut -f 1 -d ':'`
+            PORT=`echo $ADDR_PORT | cut -f 2 -d ':'`
+            # If only a port has been speified then set address to localhost.
+            if [ $ADDR = $PORT ] ; then
+                ADDR_PORT="localhost:$PORT"
+            fi
+    ;;
+    toasterdir=*)
+            TOASTERDIR="${param#*=}"
+    ;;
+    manage )
+            CMD=$param
+            manage_cmd=""
+    ;;
+    --help)
+            echo "$HELP"
+            return 0
+    ;;
+    *)
+            if [ "manage" == "$CMD" ] ; then
+                manage_cmd="$manage_cmd $param"
+            else
+                echo "$HELP"
+                exit 1
+            fi
+    ;;
+
+    esac
+done
+
+if [ `basename \"$0\"` = `basename \"${TOASTER}\"` ]; then
+    echo "Error: This script needs to be sourced. Please run as . $TOASTER"
+    return 1
+fi
+
+verify_prereq || return 1
+
+# We make sure we're running in the current shell and in a good environment
+if [ -z "$BUILDDIR" ] ||  ! which bitbake >/dev/null 2>&1 ; then
+    echo "Error: Build environment is not setup or bitbake is not in path." 1>&2
+    return 2
+fi
+
+# this defines the dir toaster will use for
+# 1) clones of layers (in _toaster_clones )
+# 2) the build dir (in build)
+# 3) the sqlite db if that is being used.
+# 4) pid's we need to clean up on exit/shutdown
+export TOASTER_DIR=$TOASTERDIR
+export BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE TOASTER_DIR"
+
+# Determine the action. If specified by arguments, fine, if not, toggle it
+if [ "$CMD" = "start" ] ; then
+    if [ -n "$BBSERVER" ]; then
+	echo " Toaster is already running. Exiting..."
+	return 1
+fi
+elif [ "$CMD" = "" ]; then
+    echo "No command specified"
+    echo "$HELP"
+    return 1
+fi
+
+echo "The system will $CMD."
+
+# Execute the commands
+custom_extention toaster_prepend $CMD $ADDR_PORT
+
+case $CMD in
+    start )
+        # check if addr:port is not in use
+        if [ "$CMD" == 'start' ]; then
+            if [ $WEBSERVER -gt 0 ]; then
+                $MANAGE checksocket "$ADDR_PORT" || return 1
+            fi
+        fi
+
+        # Create configuration file
+        conf=${BUILDDIR}/conf/local.conf
+        line='INHERIT+="toaster buildhistory"'
+        grep -q "$line" $conf || echo $line >> $conf
+
+        if [ $WEBSERVER -eq 0 ] ; then
+            # Do not update the database for "noweb" unless
+            # it does not yet exist
+            if [ ! -f "$TOASTER_DIR/toaster.sqlite" ] ; then
+                if ! databaseCheck; then
+                    echo "Failed ${CMD}."
+                    return 4
+                fi
+            fi
+            custom_extention noweb_start_postpend $ADDR_PORT
+        fi
+        if [ $WEBSERVER -gt 0 ] && ! webserverStartAll; then
+            echo "Failed ${CMD}."
+            return 4
+        fi
+        export BITBAKE_UI='toasterui'
+        if [ $TOASTER_BUILDSERVER -eq 1 ] ; then
+            $MANAGE runbuilds \
+               </dev/null >>${BUILDDIR}/toaster_runbuilds.log 2>&1 \
+               & echo $! >${BUILDDIR}/.runbuilds.pid
+        else
+            echo "Toaster build server not started."
+        fi
+
+        # set fail safe stop system on terminal exit
+        trap stop_system SIGHUP
+        echo "Successful ${CMD}."
+        custom_extention toaster_postpend $CMD $ADDR_PORT
+        return 0
+    ;;
+    stop )
+        stop_system
+        echo "Successful ${CMD}."
+    ;;
+    manage )
+        cd $BBBASEDIR/lib/toaster
+        $MANAGE $manage_cmd
+    ;;
+esac
+custom_extention toaster_postpend $CMD $ADDR_PORT
+

+ 113 - 0
openembedded-core/bitbake/bin/toaster-eventreplay

@@ -0,0 +1,113 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2014        Alex Damian
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# This file re-uses code spread throughout other Bitbake source files.
+# As such, all other copyrights belong to their own right holders.
+#
+
+"""
+This command takes a filename as a single parameter. The filename is read
+as a build eventlog, and the ToasterUI is used to process events in the file
+and log data in the database
+"""
+
+import os
+import sys
+import json
+import pickle
+import codecs
+
+from collections import namedtuple
+
+# mangle syspath to allow easy import of modules
+from os.path import join, dirname, abspath
+sys.path.insert(0, join(dirname(dirname(abspath(__file__))), 'lib'))
+
+import bb.cooker
+from bb.ui import toasterui
+
+class EventPlayer:
+    """Emulate a connection to a bitbake server."""
+
+    def __init__(self, eventfile, variables):
+        self.eventfile = eventfile
+        self.variables = variables
+        self.eventmask = []
+
+    def waitEvent(self, _timeout):
+        """Read event from the file."""
+        line = self.eventfile.readline().strip()
+        if not line:
+            return
+        try:
+            event_str = json.loads(line)['vars'].encode('utf-8')
+            event = pickle.loads(codecs.decode(event_str, 'base64'))
+            event_name = "%s.%s" % (event.__module__, event.__class__.__name__)
+            if event_name not in self.eventmask:
+                return
+            return event
+        except ValueError as err:
+            print("Failed loading ", line)
+            raise err
+
+    def runCommand(self, command_line):
+        """Emulate running a command on the server."""
+        name = command_line[0]
+
+        if name == "getVariable":
+            var_name = command_line[1]
+            variable = self.variables.get(var_name)
+            if variable:
+                return variable['v'], None
+            return None, "Missing variable %s" % var_name
+
+        elif name == "getAllKeysWithFlags":
+            dump = {}
+            flaglist = command_line[1]
+            for key, val in self.variables.items():
+                try:
+                    if not key.startswith("__"):
+                        dump[key] = {
+                            'v': val['v'],
+                            'history' : val['history'],
+                        }
+                        for flag in flaglist:
+                            dump[key][flag] = val[flag]
+                except Exception as err:
+                    print(err)
+            return (dump, None)
+
+        elif name == 'setEventMask':
+            self.eventmask = command_line[-1]
+            return True, None
+
+        else:
+            raise Exception("Command %s not implemented" % command_line[0])
+
+    def getEventHandle(self):
+        """
+        This method is called by toasterui.
+        The return value is passed to self.runCommand but not used there.
+        """
+        pass
+
+def main(argv):
+    with open(argv[-1]) as eventfile:
+        # load variables from the first line
+        variables = json.loads(eventfile.readline().strip())['allvariables']
+
+        params = namedtuple('ConfigParams', ['observe_only'])(True)
+        player = EventPlayer(eventfile, variables)
+
+        return toasterui.main(player, player, params)
+
+# run toaster ui on our mock bitbake class
+if __name__ == "__main__":
+    if len(sys.argv) != 2:
+        print("Usage: %s <event file>" % os.path.basename(sys.argv[0]))
+        sys.exit(1)
+
+    sys.exit(main(sys.argv))

+ 67 - 0
openembedded-core/bitbake/classes/base.bbclass

@@ -0,0 +1,67 @@
+# Copyright (C) 2003  Chris Larson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+die() {
+	bbfatal "$*"
+}
+
+bbnote() {
+	echo "NOTE:" "$*"
+}
+
+bbwarn() {
+	echo "WARNING:" "$*"
+}
+
+bbfatal() {
+	echo "FATAL:" "$*"
+	exit 1
+}
+
+addtask showdata
+do_showdata[nostamp] = "1"
+python do_showdata() {
+    import sys
+    # emit variables and shell functions
+    bb.data.emit_env(sys.__stdout__, d, True)
+    # emit the metadata which isn't valid shell
+    for e in bb.data.keys(d):
+        if d.getVarFlag(e, 'python', False):
+            bb.plain("\npython %s () {\n%s}" % (e, d.getVar(e)))
+}
+
+addtask listtasks
+do_listtasks[nostamp] = "1"
+python do_listtasks() {
+    import sys
+    for e in bb.data.keys(d):
+        if d.getVarFlag(e, 'task', False):
+            bb.plain("%s" % e)
+}
+
+addtask build
+do_build[dirs] = "${TOPDIR}"
+do_build[nostamp] = "1"
+python base_do_build () {
+    bb.note("The included, default BB base.bbclass does not define a useful default task.")
+    bb.note("Try running the 'listtasks' task against a .bb to see what tasks are defined.")
+}
+
+EXPORT_FUNCTIONS do_clean do_mrproper do_build

+ 46 - 0
openembedded-core/bitbake/conf/bitbake.conf

@@ -0,0 +1,46 @@
+# Copyright (C) 2003  Chris Larson
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+
+B = "${S}"
+DEPENDS = ""
+DEPLOY_DIR = "${TMPDIR}/deploy"
+DEPLOY_DIR_IMAGE = "${DEPLOY_DIR}/images"
+DL_DIR = "${TMPDIR}/downloads"
+FILESPATH = "${FILE_DIRNAME}/${PF}:${FILE_DIRNAME}/${P}:${FILE_DIRNAME}/${PN}:${FILE_DIRNAME}/files:${FILE_DIRNAME}"
+FILE_DIRNAME = "${@os.path.dirname(d.getVar('FILE', False))}"
+IMAGE_CMD = "_NO_DEFINED_IMAGE_TYPES_"
+IMAGE_ROOTFS = "${TMPDIR}/rootfs"
+OVERRIDES = "local:${MACHINE}:${TARGET_OS}:${TARGET_ARCH}"
+P = "${PN}-${PV}"
+PERSISTENT_DIR = "${TMPDIR}/cache"
+PF = "${PN}-${PV}-${PR}"
+PN = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
+PR = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[2] or 'r0'}"
+PROVIDES = ""
+PV = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[1] or '1.0'}"
+S = "${WORKDIR}/${P}"
+SRC_URI = "file://${FILE}"
+STAMP = "${TMPDIR}/stamps/${PF}"
+T = "${WORKDIR}/temp"
+TARGET_ARCH = "${BUILD_ARCH}"
+TMPDIR = "${TOPDIR}/tmp"
+WORKDIR = "${TMPDIR}/work/${PF}"
+PERSISTENT_DIR = "${TMPDIR}/cache"
+GITPKGV = "${@bb.fetch2.get_srcrev(d, 'gitpkgv_revision')}"

+ 1 - 0
openembedded-core/bitbake/contrib/README

@@ -0,0 +1 @@
+This directory is for additional contributed files which may be useful.

+ 13 - 0
openembedded-core/bitbake/contrib/autobuilderlog.json

@@ -0,0 +1,13 @@
+{
+    "version": 1,
+    "loggers": {
+        "BitBake.SigGen.HashEquiv": {
+            "level": "VERBOSE",
+            "handlers": ["BitBake.verbconsole"]
+        },
+        "BitBake.RunQueue.HashEquiv": {
+            "level": "VERBOSE",
+            "handlers": ["BitBake.verbconsole"]
+        }
+    }
+}

+ 31 - 0
openembedded-core/bitbake/contrib/bbdev.sh

@@ -0,0 +1,31 @@
+# This is a shell function to be sourced into your shell or placed in your .profile,
+# which makes setting things up for BitBake a bit easier.
+#
+# The author disclaims copyright to the contents of this file and places it in the
+# public domain.
+
+bbdev () {
+	local BBDIR PKGDIR BUILDDIR
+	if test x"$1" = "x--help"; then echo >&2 "syntax: bbdev [bbdir [pkgdir [builddir]]]"; return 1; fi
+	if test x"$1" = x; then BBDIR=`pwd`; else BBDIR=$1; fi
+	if test x"$2" = x; then PKGDIR=`pwd`; else PKGDIR=$2; fi
+	if test x"$3" = x; then BUILDDIR=`pwd`; else BUILDDIR=$3; fi
+
+	BBDIR=`readlink -f $BBDIR`
+	PKGDIR=`readlink -f $PKGDIR`
+	BUILDDIR=`readlink -f $BUILDDIR`
+	if ! (test -d $BBDIR && test -d $PKGDIR && test -d $BUILDDIR); then
+		echo >&2 "syntax: bbdev [bbdir [pkgdir [builddir]]]"
+		return 1
+	fi
+	
+	PATH=$BBDIR/bin:$PATH
+	BBPATH=$BBDIR
+	if test x"$BBDIR" != x"$PKGDIR"; then
+		BBPATH=$PKGDIR:$BBPATH
+	fi
+	if test x"$PKGDIR" != x"$BUILDDIR"; then
+		BBPATH=$BUILDDIR:$BBPATH
+	fi
+	export BBPATH
+}

+ 89 - 0
openembedded-core/bitbake/contrib/bbparse-torture.py

@@ -0,0 +1,89 @@
+#! /usr/bin/env python3
+#
+# Copyright (C) 2020 Joshua Watt <JPEWhacker@gmail.com>
+#
+# SPDX-License-Identifier: MIT
+
+import argparse
+import os
+import random
+import shutil
+import signal
+import subprocess
+import sys
+import time
+
+
+def try_unlink(path):
+    try:
+        os.unlink(path)
+    except:
+        pass
+
+
+def main():
+    def cleanup():
+        shutil.rmtree("tmp/cache", ignore_errors=True)
+        try_unlink("bitbake-cookerdaemon.log")
+        try_unlink("bitbake.sock")
+        try_unlink("bitbake.lock")
+
+    parser = argparse.ArgumentParser(
+        description="Bitbake parser torture test",
+        epilog="""
+        A torture test for bitbake's parser. Repeatedly interrupts parsing until
+        bitbake decides to deadlock.
+        """,
+    )
+
+    args = parser.parse_args()
+
+    if not "BUILDDIR" in os.environ:
+        print(
+            "'BUILDDIR' not found in the environment. Did you initialize the build environment?"
+        )
+        return 1
+
+    os.chdir(os.environ["BUILDDIR"])
+
+    run_num = 0
+    while True:
+        if run_num % 100 == 0:
+            print("Calibrating wait time...")
+            cleanup()
+
+            start_time = time.monotonic()
+            r = subprocess.run(["bitbake", "-p"])
+            max_wait_time = time.monotonic() - start_time
+
+            if r.returncode != 0:
+                print("Calibration run exited with %d" % r.returncode)
+                return 1
+
+            print("Maximum wait time is %f seconds" % max_wait_time)
+
+        run_num += 1
+        wait_time = random.random() * max_wait_time
+
+        print("Run #%d" % run_num)
+        print("Will sleep for %f seconds" % wait_time)
+
+        cleanup()
+        with subprocess.Popen(["bitbake", "-p"]) as proc:
+            time.sleep(wait_time)
+            proc.send_signal(signal.SIGINT)
+            try:
+                proc.wait(45)
+            except subprocess.TimeoutExpired:
+                print("Run #%d: Waited too long. Possible deadlock!" % run_num)
+                proc.wait()
+                return 1
+
+            if proc.returncode == 0:
+                print("Exited successfully. Timeout too long?")
+            else:
+                print("Exited with %d" % proc.returncode)
+
+
+if __name__ == "__main__":
+    sys.exit(main())

+ 83 - 0
openembedded-core/bitbake/contrib/dump_cache.py

@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2012, 2018 Wind River Systems, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+#
+# Used for dumping the bb_cache.dat
+#
+import os
+import sys
+import argparse
+
+# For importing bb.cache
+sys.path.insert(0, os.path.join(os.path.abspath(os.path.dirname(sys.argv[0])), '../lib'))
+from bb.cache import CoreRecipeInfo
+
+import pickle
+
+class DumpCache(object):
+    def __init__(self):
+        parser = argparse.ArgumentParser(
+            description="bb_cache.dat's dumper",
+            epilog="Use %(prog)s --help to get help")
+        parser.add_argument("-r", "--recipe",
+            help="specify the recipe, default: all recipes", action="store")
+        parser.add_argument("-m", "--members",
+            help = "specify the member, use comma as separator for multiple ones, default: all members", action="store", default="")
+        parser.add_argument("-s", "--skip",
+            help = "skip skipped recipes", action="store_true")
+        parser.add_argument("cachefile",
+            help = "specify bb_cache.dat", nargs = 1, action="store", default="")
+
+        self.args = parser.parse_args()
+
+    def main(self):
+        with open(self.args.cachefile[0], "rb") as cachefile:
+            pickled = pickle.Unpickler(cachefile)
+            while True:
+                try:
+                    key = pickled.load()
+                    val = pickled.load()
+                except Exception:
+                    break
+                if isinstance(val, CoreRecipeInfo):
+                    pn = val.pn
+
+                    if self.args.recipe and self.args.recipe != pn:
+                        continue
+
+                    if self.args.skip and val.skipped:
+                        continue
+
+                    if self.args.members:
+                        out = key
+                        for member in self.args.members.split(','):
+                            out += ": %s" % val.__dict__.get(member)
+                        print("%s" % out)
+                    else:
+                        print("%s: %s" % (key, val.__dict__))
+                elif not self.args.recipe:
+                    print("%s %s" % (key, val))
+
+if __name__ == "__main__":
+    try:
+        dump = DumpCache()
+        ret = dump.main()
+    except Exception as esc:
+        ret = 1
+        import traceback
+        traceback.print_exc()
+    sys.exit(ret)

+ 18 - 0
openembedded-core/bitbake/contrib/vim/LICENSE.txt

@@ -0,0 +1,18 @@
+The MIT License (MIT)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 24 - 0
openembedded-core/bitbake/contrib/vim/ftdetect/bitbake.vim

@@ -0,0 +1,24 @@
+" Vim filetype detection file
+" Language:     BitBake
+" Author:       Ricardo Salveti <rsalveti@rsalveti.net>
+" Copyright:    Copyright (C) 2008  Ricardo Salveti <rsalveti@rsalveti.net>
+" Licence:      You may redistribute this under the same terms as Vim itself
+"
+" This sets up the syntax highlighting for BitBake files, like .bb, .bbclass and .inc
+
+if &compatible || version < 600 || exists("b:loaded_bitbake_plugin")
+    finish
+endif
+
+" .bb, .bbappend and .bbclass
+au BufNewFile,BufRead *.{bb,bbappend,bbclass}  set filetype=bitbake
+
+" .inc
+au BufNewFile,BufRead *.inc		set filetype=bitbake
+
+" .conf
+au BufNewFile,BufRead *.conf
+    \ if (match(expand("%:p:h"), "conf") > 0) |
+    \     set filetype=bitbake |
+    \ endif
+

+ 13 - 0
openembedded-core/bitbake/contrib/vim/ftplugin/bitbake.vim

@@ -0,0 +1,13 @@
+" Only do this when not done yet for this buffer
+if exists("b:did_ftplugin")
+  finish
+endif
+
+" Don't load another plugin for this buffer
+let b:did_ftplugin = 1
+
+let b:undo_ftplugin = "setl cms< sts< sw< et< sua<"
+
+setlocal commentstring=#\ %s
+setlocal softtabstop=4 shiftwidth=4 expandtab
+setlocal suffixesadd+=.bb,.bbclass

+ 343 - 0
openembedded-core/bitbake/contrib/vim/indent/bitbake.vim

@@ -0,0 +1,343 @@
+" Vim indent file
+" Language:             BitBake
+" Copyright:            Copyright (C) 2019 Agilent Technologies, Inc.
+" Maintainer:           Chris Laplante <chris.laplante@agilent.com>
+" License:              You may redistribute this under the same terms as Vim itself
+
+
+if exists("b:did_indent")
+    finish
+endif
+
+if exists("*BitbakeIndent")
+    finish
+endif
+
+runtime! indent/sh.vim
+unlet b:did_indent
+
+setlocal indentexpr=BitbakeIndent(v:lnum)
+setlocal autoindent nolisp
+
+function s:is_bb_python_func_def(lnum)
+    let stack = synstack(a:lnum, 1)
+    if len(stack) == 0
+        return 0
+    endif
+
+    let top = synIDattr(stack[0], "name")
+    echo top
+
+    return synIDattr(stack[0], "name") == "bbPyFuncDef"
+endfunction
+
+"""" begin modified from indent/python.vim, upstream commit 7a9bd7c1e0ce1baf5a02daf36eeae3638aa315c7
+"""" This copied code is licensed the same as Vim itself.
+setlocal indentkeys+=<:>,=elif,=except
+
+let s:keepcpo= &cpo
+set cpo&vim
+
+let s:maxoff = 50	" maximum number of lines to look backwards for ()
+
+function GetPythonIndent(lnum)
+
+  " If this line is explicitly joined: If the previous line was also joined,
+  " line it up with that one, otherwise add two 'shiftwidth'
+  if getline(a:lnum - 1) =~ '\\$'
+    if a:lnum > 1 && getline(a:lnum - 2) =~ '\\$'
+      return indent(a:lnum - 1)
+    endif
+    return indent(a:lnum - 1) + (exists("g:pyindent_continue") ? eval(g:pyindent_continue) : (shiftwidth() * 2))
+  endif
+
+  " If the start of the line is in a string don't change the indent.
+  if has('syntax_items')
+	\ && synIDattr(synID(a:lnum, 1, 1), "name") =~ "String$"
+    return -1
+  endif
+
+  " Search backwards for the previous non-empty line.
+  let plnum = prevnonblank(v:lnum - 1)
+
+  if plnum == 0
+    " This is the first non-empty line, use zero indent.
+    return 0
+  endif
+
+  call cursor(plnum, 1)
+
+  " Identing inside parentheses can be very slow, regardless of the searchpair()
+  " timeout, so let the user disable this feature if he doesn't need it
+  let disable_parentheses_indenting = get(g:, "pyindent_disable_parentheses_indenting", 0)
+
+  if disable_parentheses_indenting == 1
+    let plindent = indent(plnum)
+    let plnumstart = plnum
+  else
+    " searchpair() can be slow sometimes, limit the time to 150 msec or what is
+    " put in g:pyindent_searchpair_timeout
+    let searchpair_stopline = 0
+    let searchpair_timeout = get(g:, 'pyindent_searchpair_timeout', 150)
+
+    " If the previous line is inside parenthesis, use the indent of the starting
+    " line.
+    " Trick: use the non-existing "dummy" variable to break out of the loop when
+    " going too far back.
+    let parlnum = searchpair('(\|{\|\[', '', ')\|}\|\]', 'nbW',
+            \ "line('.') < " . (plnum - s:maxoff) . " ? dummy :"
+            \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
+            \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
+            \ searchpair_stopline, searchpair_timeout)
+    if parlnum > 0
+      " We may have found the opening brace of a BitBake Python task, e.g. 'python do_task {'
+      " If so, ignore it here - it will be handled later.
+      if s:is_bb_python_func_def(parlnum)
+        let parlnum = 0
+        let plindent = indent(plnum)
+        let plnumstart = plnum
+      else
+        let plindent = indent(parlnum)
+        let plnumstart = parlnum
+      endif
+    else
+      let plindent = indent(plnum)
+      let plnumstart = plnum
+    endif
+
+    " When inside parenthesis: If at the first line below the parenthesis add
+    " two 'shiftwidth', otherwise same as previous line.
+    " i = (a
+    "       + b
+    "       + c)
+    call cursor(a:lnum, 1)
+    let p = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW',
+            \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
+            \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
+            \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
+            \ searchpair_stopline, searchpair_timeout)
+    if p > 0
+        if s:is_bb_python_func_def(p)
+          " Handle first non-empty line inside a BB Python task
+          if p == plnum
+              return shiftwidth()
+          endif
+
+          " Handle the user actually trying to close a BitBake Python task
+          let line = getline(a:lnum)
+          if line =~ '^\s*}'
+              return -2
+          endif
+
+          " Otherwise ignore the brace
+          let p = 0
+        else
+          if p == plnum
+            " When the start is inside parenthesis, only indent one 'shiftwidth'.
+            let pp = searchpair('(\|{\|\[', '', ')\|}\|\]', 'bW',
+                \ "line('.') < " . (a:lnum - s:maxoff) . " ? dummy :"
+                \ . " synIDattr(synID(line('.'), col('.'), 1), 'name')"
+                \ . " =~ '\\(Comment\\|Todo\\|String\\)$'",
+                \ searchpair_stopline, searchpair_timeout)
+            if pp > 0
+              return indent(plnum) + (exists("g:pyindent_nested_paren") ? eval(g:pyindent_nested_paren) : shiftwidth())
+            endif
+            return indent(plnum) + (exists("g:pyindent_open_paren") ? eval(g:pyindent_open_paren) : (shiftwidth() * 2))
+          endif
+          if plnumstart == p
+            return indent(plnum)
+          endif
+          return plindent
+        endif
+    endif
+
+  endif
+
+
+  " Get the line and remove a trailing comment.
+  " Use syntax highlighting attributes when possible.
+  let pline = getline(plnum)
+  let pline_len = strlen(pline)
+  if has('syntax_items')
+    " If the last character in the line is a comment, do a binary search for
+    " the start of the comment.  synID() is slow, a linear search would take
+    " too long on a long line.
+    if synIDattr(synID(plnum, pline_len, 1), "name") =~ "\\(Comment\\|Todo\\)$"
+      let min = 1
+      let max = pline_len
+      while min < max
+	let col = (min + max) / 2
+	if synIDattr(synID(plnum, col, 1), "name") =~ "\\(Comment\\|Todo\\)$"
+	  let max = col
+	else
+	  let min = col + 1
+	endif
+      endwhile
+      let pline = strpart(pline, 0, min - 1)
+    endif
+  else
+    let col = 0
+    while col < pline_len
+      if pline[col] == '#'
+	let pline = strpart(pline, 0, col)
+	break
+      endif
+      let col = col + 1
+    endwhile
+  endif
+
+  " If the previous line ended with a colon, indent this line
+  if pline =~ ':\s*$'
+    return plindent + shiftwidth()
+  endif
+
+  " If the previous line was a stop-execution statement...
+  " TODO: utilize this logic to deindent when ending a bbPyDefRegion
+  if getline(plnum) =~ '^\s*\(break\|continue\|raise\|return\|pass\|bb\.fatal\)\>'
+    " See if the user has already dedented
+    if indent(a:lnum) > indent(plnum) - shiftwidth()
+      " If not, recommend one dedent
+      return indent(plnum) - shiftwidth()
+    endif
+    " Otherwise, trust the user
+    return -1
+  endif
+
+  " If the current line begins with a keyword that lines up with "try"
+  if getline(a:lnum) =~ '^\s*\(except\|finally\)\>'
+    let lnum = a:lnum - 1
+    while lnum >= 1
+      if getline(lnum) =~ '^\s*\(try\|except\)\>'
+	let ind = indent(lnum)
+	if ind >= indent(a:lnum)
+	  return -1	" indent is already less than this
+	endif
+	return ind	" line up with previous try or except
+      endif
+      let lnum = lnum - 1
+    endwhile
+    return -1		" no matching "try"!
+  endif
+
+  " If the current line begins with a header keyword, dedent
+  if getline(a:lnum) =~ '^\s*\(elif\|else\)\>'
+
+    " Unless the previous line was a one-liner
+    if getline(plnumstart) =~ '^\s*\(for\|if\|try\)\>'
+      return plindent
+    endif
+
+    " Or the user has already dedented
+    if indent(a:lnum) <= plindent - shiftwidth()
+      return -1
+    endif
+
+    return plindent - shiftwidth()
+  endif
+
+  " When after a () construct we probably want to go back to the start line.
+  " a = (b
+  "       + c)
+  " here
+  if parlnum > 0
+    return plindent
+  endif
+
+  return -1
+
+endfunction
+
+let &cpo = s:keepcpo
+unlet s:keepcpo
+
+""" end of stuff from indent/python.vim
+
+
+let b:did_indent = 1
+setlocal indentkeys+=0\"
+
+
+function BitbakeIndent(lnum)
+    if !has('syntax_items')
+        return -1
+    endif
+
+    let stack = synstack(a:lnum, 1)
+    if len(stack) == 0
+        return -1
+    endif
+
+    let name = synIDattr(stack[0], "name")
+
+    " TODO: support different styles of indentation for assignments. For now,
+    " we only support like this:
+    " VAR = " \
+    "     value1 \
+    "     value2 \
+    " "
+    "
+    " i.e. each value indented by shiftwidth(), with the final quote " completely unindented.
+    if name == "bbVarValue"
+        " Quote handling is tricky. kernel.bbclass has this line for instance:
+        "     EXTRA_OEMAKE = " HOSTCC="${BUILD_CC} ${BUILD_CFLAGS} ${BUILD_LDFLAGS}" " HOSTCPP="${BUILD_CPP}""
+        " Instead of trying to handle crazy cases like that, just assume that a
+        " double-quote on a line by itself (following an assignment) means the
+        " user is closing the assignment, and de-dent.
+        if getline(a:lnum) =~ '^\s*"$'
+            return 0
+        endif
+
+        let prevstack = synstack(a:lnum - 1, 1)
+        if len(prevstack) == 0
+            return -1
+        endif
+
+        let prevname = synIDattr(prevstack[0], "name")
+
+        " Only indent if there was actually a continuation character on
+        " the previous line, to avoid misleading indentation.
+        let prevlinelastchar = synIDattr(synID(a:lnum - 1, col([a:lnum - 1, "$"]) - 1, 1), "name")
+        let prev_continued = prevlinelastchar == "bbContinue"
+
+        " Did the previous line introduce an assignment?
+        if index(["bbVarDef", "bbVarFlagDef"], prevname) != -1
+            if prev_continued
+                return shiftwidth()
+            endif
+        endif
+
+        if !prev_continued
+            return 0
+        endif
+
+        " Autoindent can take it from here
+        return -1
+    endif
+
+    if index(["bbPyDefRegion", "bbPyFuncRegion"], name) != -1
+        let ret = GetPythonIndent(a:lnum)
+        " Should normally always be indented by at least one shiftwidth; but allow
+        " return of -1 (defer to autoindent) or -2 (force indent to 0)
+        if ret == 0
+            return shiftwidth()
+        elseif ret == -2
+            return 0
+        endif
+        return ret
+    endif
+
+    " TODO: GetShIndent doesn't detect tasks prepended with 'fakeroot'
+    " Need to submit a patch upstream to Vim to provide an extension point.
+    " Unlike the Python indenter, the Sh indenter is way too large to copy and
+    " modify here.
+    if name == "bbShFuncRegion"
+        return GetShIndent()
+    endif
+
+    " TODO:
+    "   + heuristics for de-denting out of a bbPyDefRegion? e.g. when the user
+    "       types an obvious BB keyword like addhandler or addtask, or starts
+    "       writing a shell task. Maybe too hard to implement...
+
+    return -1
+endfunction

+ 88 - 0
openembedded-core/bitbake/contrib/vim/plugin/newbb.vim

@@ -0,0 +1,88 @@
+" Vim plugin file
+" Purpose:	Create a template for new bb files
+" Author:	Ricardo Salveti <rsalveti@gmail.com>
+" Copyright:	Copyright (C) 2008 Ricardo Salveti <rsalveti@gmail.com>
+"
+" This file is licensed under the MIT license, see COPYING.MIT in
+" this source distribution for the terms.
+"
+" Based on the gentoo-syntax package
+"
+" Will try to use git to find the user name and email
+
+if &compatible || v:version < 600 || exists("b:loaded_bitbake_plugin")
+    finish
+endif
+
+fun! <SID>GetUserName()
+    let l:user_name = system("git config --get user.name")
+    if v:shell_error
+        return "Unknown User"
+    else
+        return substitute(l:user_name, "\n", "", "")
+endfun
+
+fun! <SID>GetUserEmail()
+    let l:user_email = system("git config --get user.email")
+    if v:shell_error
+        return "unknown@user.org"
+    else
+        return substitute(l:user_email, "\n", "", "")
+endfun
+
+fun! BBHeader()
+    let l:current_year = strftime("%Y")
+    let l:user_name = <SID>GetUserName()
+    let l:user_email = <SID>GetUserEmail()
+    0 put ='# Copyright (C) ' . l:current_year .
+                \ ' ' . l:user_name . ' <' . l:user_email . '>'
+    put ='# Released under the MIT license (see COPYING.MIT for the terms)'
+    $
+endfun
+
+fun! NewBBTemplate()
+    if line2byte(line('$') + 1) != -1
+        return
+    endif
+
+    let l:paste = &paste
+    set nopaste
+    
+    " Get the header
+    call BBHeader()
+
+    " New the bb template
+    put ='SUMMARY = \"\"'
+    put ='HOMEPAGE = \"\"'
+    put ='LICENSE = \"\"' 
+    put ='SECTION = \"\"'
+    put ='DEPENDS = \"\"'
+    put =''
+    put ='SRC_URI = \"\"'
+
+    " Go to the first place to edit
+    0
+    /^SUMMARY =/
+    exec "normal 2f\""
+
+    if paste == 1
+        set paste
+    endif
+endfun
+
+if !exists("g:bb_create_on_empty")
+    let g:bb_create_on_empty = 1
+endif
+
+" disable in case of vimdiff
+if v:progname =~ "vimdiff"
+    let g:bb_create_on_empty = 0
+endif
+
+augroup NewBB
+    au BufNewFile,BufReadPost *.bb
+                \ if g:bb_create_on_empty |
+                \    call NewBBTemplate() |
+                \ endif
+augroup END
+

+ 46 - 0
openembedded-core/bitbake/contrib/vim/plugin/newbbappend.vim

@@ -0,0 +1,46 @@
+" Vim plugin file
+" Purpose:	Create a template for new bbappend file
+" Author:	Joshua Watt <JPEWhacker@gmail.com>
+" Copyright:	Copyright (C) 2017 Joshua Watt <JPEWhacker@gmail.com>
+"
+" This file is licensed under the MIT license, see COPYING.MIT in
+" this source distribution for the terms.
+"
+
+if &compatible || v:version < 600 || exists("b:loaded_bitbake_plugin")
+    finish
+endif
+
+fun! NewBBAppendTemplate()
+    if line2byte(line('$') + 1) != -1
+        return
+    endif
+
+    let l:paste = &paste
+    set nopaste
+
+    " New bbappend template
+    0 put ='FILESEXTRAPATHS_prepend := \"${THISDIR}/${PN}:\"'
+    2
+
+    if paste == 1
+        set paste
+    endif
+endfun
+
+if !exists("g:bb_create_on_empty")
+    let g:bb_create_on_empty = 1
+endif
+
+" disable in case of vimdiff
+if v:progname =~ "vimdiff"
+    let g:bb_create_on_empty = 0
+endif
+
+augroup NewBBAppend
+    au BufNewFile,BufReadPost *.bbappend
+                \ if g:bb_create_on_empty |
+                \    call NewBBAppendTemplate() |
+                \ endif
+augroup END
+

+ 126 - 0
openembedded-core/bitbake/contrib/vim/syntax/bitbake.vim

@@ -0,0 +1,126 @@
+" Vim syntax file
+" Language:     BitBake bb/bbclasses/inc
+" Author:       Chris Larson <kergoth@handhelds.org>
+"               Ricardo Salveti <rsalveti@rsalveti.net>
+" Copyright:    Copyright (C) 2004  Chris Larson <kergoth@handhelds.org>
+"               Copyright (C) 2008  Ricardo Salveti <rsalveti@rsalveti.net>
+"
+" This file is licensed under the MIT license, see COPYING.MIT in
+" this source distribution for the terms.
+"
+" Syntax highlighting for bb, bbclasses and inc files.
+"
+" It's an entirely new type, just has specific syntax in shell and python code
+
+if &compatible || v:version < 600 || exists("b:loaded_bitbake_plugin")
+    finish
+endif
+if exists("b:current_syntax")
+    finish
+endif
+
+syn include @python syntax/python.vim
+if exists("b:current_syntax")
+  unlet b:current_syntax
+endif
+
+" BitBake syntax
+
+" Matching case
+syn case match
+
+" Indicates the error when nothing is matched
+syn match bbUnmatched           "."
+
+" Comments
+syn cluster bbCommentGroup      contains=bbTodo,@Spell
+syn keyword bbTodo              COMBAK FIXME TODO XXX contained
+syn match bbComment             "#.*$" contains=@bbCommentGroup
+
+" String helpers
+syn match bbQuote               +['"]+ contained 
+syn match bbDelimiter           "[(){}=]" contained
+syn match bbArrayBrackets       "[\[\]]" contained
+
+" BitBake strings
+syn match bbContinue            "\\$"
+syn region bbString             matchgroup=bbQuote start=+"+ skip=+\\$+ end=+"+ contained contains=bbTodo,bbContinue,bbVarDeref,bbVarPyValue,@Spell
+syn region bbString             matchgroup=bbQuote start=+'+ skip=+\\$+ end=+'+ contained contains=bbTodo,bbContinue,bbVarDeref,bbVarPyValue,@Spell
+
+" Vars definition
+syn match bbExport            "^export" nextgroup=bbIdentifier skipwhite
+syn keyword bbExportFlag        export contained nextgroup=bbIdentifier skipwhite
+syn match bbIdentifier          "[a-zA-Z0-9\-_\.\/\+]\+" display contained
+syn match bbVarDeref            "${[a-zA-Z0-9\-_\.\/\+]\+}" contained
+syn match bbVarEq               "\(:=\|+=\|=+\|\.=\|=\.\|?=\|??=\|=\)" contained nextgroup=bbVarValue
+syn match bbVarDef              "^\(export\s*\)\?\([a-zA-Z0-9\-_\.\/\+]\+\(_[${}a-zA-Z0-9\-_\.\/\+]\+\)\?\)\s*\(:=\|+=\|=+\|\.=\|=\.\|?=\|??=\|=\)\@=" contains=bbExportFlag,bbIdentifier,bbVarDeref nextgroup=bbVarEq
+syn match bbVarValue            ".*$" contained contains=bbString,bbVarDeref,bbVarPyValue
+syn region bbVarPyValue         start=+${@+ skip=+\\$+ end=+}+ contained contains=@python
+
+" Vars metadata flags
+syn match bbVarFlagDef          "^\([a-zA-Z0-9\-_\.]\+\)\(\[[a-zA-Z0-9\-_\.+]\+\]\)\@=" contains=bbIdentifier nextgroup=bbVarFlagFlag
+syn region bbVarFlagFlag        matchgroup=bbArrayBrackets start="\[" end="\]\s*\(:=\|=\|.=\|=.|+=\|=+\|?=\)\@=" contained contains=bbIdentifier nextgroup=bbVarEq
+
+" Includes and requires
+syn keyword bbInclude           inherit include require contained 
+syn match bbIncludeRest         ".*$" contained contains=bbString,bbVarDeref
+syn match bbIncludeLine         "^\(inherit\|include\|require\)\s\+" contains=bbInclude nextgroup=bbIncludeRest
+
+" Add taks and similar
+syn keyword bbStatement         addtask deltask addhandler after before EXPORT_FUNCTIONS contained
+syn match bbStatementRest       ".*$" skipwhite contained contains=bbStatement
+syn match bbStatementLine       "^\(addtask\|deltask\|addhandler\|after\|before\|EXPORT_FUNCTIONS\)\s\+" contains=bbStatement nextgroup=bbStatementRest
+
+" OE Important Functions
+syn keyword bbOEFunctions       do_fetch do_unpack do_patch do_configure do_compile do_stage do_install do_package contained
+
+" Generic Functions
+syn match bbFunction            "\h[0-9A-Za-z_\-\.]*" display contained contains=bbOEFunctions
+
+" BitBake shell metadata
+syn include @shell syntax/sh.vim
+if exists("b:current_syntax")
+  unlet b:current_syntax
+endif
+syn keyword bbShFakeRootFlag    fakeroot contained
+syn match bbShFuncDef           "^\(fakeroot\s*\)\?\([\.0-9A-Za-z_${}\-\.]\+\)\(python\)\@<!\(\s*()\s*\)\({\)\@=" contains=bbShFakeRootFlag,bbFunction,bbVarDeref,bbDelimiter nextgroup=bbShFuncRegion skipwhite
+syn region bbShFuncRegion       matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" contained contains=@shell
+
+" Python value inside shell functions
+syn region shDeref         start=+${@+ skip=+\\$+ excludenl end=+}+ contained contains=@python
+
+" BitBake python metadata
+syn keyword bbPyFlag            python contained
+syn match bbPyFuncDef           "^\(fakeroot\s*\)\?\(python\)\(\s\+[0-9A-Za-z_${}\-\.]\+\)\?\(\s*()\s*\)\({\)\@=" contains=bbShFakeRootFlag,bbPyFlag,bbFunction,bbVarDeref,bbDelimiter nextgroup=bbPyFuncRegion skipwhite
+syn region bbPyFuncRegion       matchgroup=bbDelimiter start="{\s*$" end="^}\s*$" contained contains=@python
+
+" BitBake 'def'd python functions
+syn keyword bbPyDef             def contained
+syn region bbPyDefRegion        start='^\(def\s\+\)\([0-9A-Za-z_-]\+\)\(\s*(.*)\s*\):\s*$' end='^\(\s\|$\)\@!' contains=@python
+
+" Highlighting Definitions
+hi def link bbUnmatched         Error
+hi def link bbInclude           Include
+hi def link bbTodo              Todo
+hi def link bbComment           Comment
+hi def link bbQuote             String
+hi def link bbString            String
+hi def link bbDelimiter         Keyword
+hi def link bbArrayBrackets     Statement
+hi def link bbContinue          Special
+hi def link bbExport            Type
+hi def link bbExportFlag        Type
+hi def link bbIdentifier	    Identifier
+hi def link bbVarDeref          PreProc
+hi def link bbVarDef            Identifier
+hi def link bbVarValue          String
+hi def link bbShFakeRootFlag    Type
+hi def link bbFunction          Function
+hi def link bbPyFlag            Type
+hi def link bbPyDef             Statement
+hi def link bbStatement         Statement
+hi def link bbStatementRest     Identifier
+hi def link bbOEFunctions       Special
+hi def link bbVarPyValue        PreProc
+
+let b:current_syntax = "bb"

+ 1 - 0
openembedded-core/bitbake/doc/.gitignore

@@ -0,0 +1 @@
+_build/

+ 339 - 0
openembedded-core/bitbake/doc/COPYING.GPL

@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.

+ 17 - 0
openembedded-core/bitbake/doc/COPYING.MIT

@@ -0,0 +1,17 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 35 - 0
openembedded-core/bitbake/doc/Makefile

@@ -0,0 +1,35 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS    ?=
+SPHINXBUILD   ?= sphinx-build
+SOURCEDIR     = .
+BUILDDIR      = _build
+DESTDIR       = final
+
+ifeq ($(shell if which $(SPHINXBUILD) >/dev/null 2>&1; then echo 1; else echo 0; fi),0)
+$(error "The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed")
+endif
+
+# Put it first so that "make" without argument is like "make help".
+help:
+	@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile clean publish
+
+publish: Makefile html singlehtml
+	rm -rf $(BUILDDIR)/$(DESTDIR)/
+	mkdir -p $(BUILDDIR)/$(DESTDIR)/
+	cp -r $(BUILDDIR)/html/* $(BUILDDIR)/$(DESTDIR)/
+	cp $(BUILDDIR)/singlehtml/index.html $(BUILDDIR)/$(DESTDIR)/singleindex.html
+	sed -i -e 's@index.html#@singleindex.html#@g' $(BUILDDIR)/$(DESTDIR)/singleindex.html
+
+clean:
+	@rm -rf $(BUILDDIR)
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+	@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

+ 55 - 0
openembedded-core/bitbake/doc/README

@@ -0,0 +1,55 @@
+Documentation
+=============
+
+This is the directory that contains the BitBake documentation. 
+
+Manual Organization
+===================
+
+Folders exist for individual manuals as follows:
+
+* bitbake-user-manual      - The BitBake User Manual 
+
+Each folder is self-contained regarding content and figures.
+
+If you want to find HTML versions of the BitBake manuals on the web, 
+go to http://www.openembedded.org/wiki/Documentation. 
+
+Sphinx
+======
+
+The BitBake documentation was migrated from the original DocBook
+format to Sphinx based documentation for the Yocto Project 3.2
+release.
+
+Additional information related to the Sphinx migration, and guidelines
+for developers willing to contribute to the BitBake documentation can
+be found in the Yocto Project Documentation README file:
+
+https://git.yoctoproject.org/cgit/cgit.cgi/yocto-docs/tree/documentation/README
+
+How to build the Yocto Project documentation
+============================================
+
+Sphinx is written in Python. While it might work with Python2, for
+obvious reasons, we will only support building the BitBake
+documentation with Python3.
+
+Sphinx might be available in your Linux distro packages repositories,
+however it is not recommend using distro packages, as they might be
+old versions, especially if you are using an LTS version of your
+distro. The recommended method to install Sphinx and all required
+dependencies is to use the Python Package Index (pip).
+
+To install all required packages run:
+
+ $ pip3 install sphinx sphinx_rtd_theme pyyaml
+
+To build the documentation locally, run:
+
+ $ cd documentation
+ $ make html
+
+The resulting HTML index page will be _build/html/index.html, and you
+can browse your own copy of the locally generated documentation with
+your browser.

+ 14 - 0
openembedded-core/bitbake/doc/_templates/breadcrumbs.html

@@ -0,0 +1,14 @@
+{% extends "!breadcrumbs.html" %}
+
+{% block breadcrumbs %}
+    <li>
+      <span class="doctype_switcher_placeholder">{{ doctype or 'single' }}</span>
+      <span class="version_switcher_placeholder">{{ release }}</span>
+    </li>
+    <li> &raquo;</li>
+    {% for doc in parents %}
+      <li><a href="{{ doc.link|e }}">{{ doc.title }}</a> &raquo;</li>
+    {% endfor %}
+    <li>{{ title }}</li>
+{% endblock %}
+

+ 7 - 0
openembedded-core/bitbake/doc/_templates/layout.html

@@ -0,0 +1,7 @@
+{% extends "!layout.html" %}
+
+{% block extrabody %}
+<div id="outdated-warning" style="text-align: center; background-color: #FFBABA; color: #6A0E0E;">
+</div>
+{% endblock %}
+

+ 733 - 0
openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-execution.rst

@@ -0,0 +1,733 @@
+.. SPDX-License-Identifier: CC-BY-2.5
+
+=========
+Execution
+=========
+
+|
+
+The primary purpose for running BitBake is to produce some kind of
+output such as a single installable package, a kernel, a software
+development kit, or even a full, board-specific bootable Linux image,
+complete with bootloader, kernel, and root filesystem. Of course, you
+can execute the ``bitbake`` command with options that cause it to
+execute single tasks, compile single recipe files, capture or clear
+data, or simply return information about the execution environment.
+
+This chapter describes BitBake's execution process from start to finish
+when you use it to create an image. The execution process is launched
+using the following command form: ::
+
+  $ bitbake target
+
+For information on
+the BitBake command and its options, see ":ref:`The BitBake Command
+<bitbake-user-manual-command>`" section.
+
+.. note::
+
+   Prior to executing BitBake, you should take advantage of available
+   parallel thread execution on your build host by setting the
+   :term:`BB_NUMBER_THREADS` variable in
+   your project's ``local.conf`` configuration file.
+
+   A common method to determine this value for your build host is to run
+   the following: ::
+
+     $ grep processor /proc/cpuinfo
+
+   This command returns
+   the number of processors, which takes into account hyper-threading.
+   Thus, a quad-core build host with hyper-threading most likely shows
+   eight processors, which is the value you would then assign to
+   ``BB_NUMBER_THREADS``.
+
+   A possibly simpler solution is that some Linux distributions (e.g.
+   Debian and Ubuntu) provide the ``ncpus`` command.
+
+Parsing the Base Configuration Metadata
+=======================================
+
+The first thing BitBake does is parse base configuration metadata. Base
+configuration metadata consists of your project's ``bblayers.conf`` file
+to determine what layers BitBake needs to recognize, all necessary
+``layer.conf`` files (one from each layer), and ``bitbake.conf``. The
+data itself is of various types:
+
+-  **Recipes:** Details about particular pieces of software.
+
+-  **Class Data:** An abstraction of common build information (e.g. how to
+   build a Linux kernel).
+
+-  **Configuration Data:** Machine-specific settings, policy decisions,
+   and so forth. Configuration data acts as the glue to bind everything
+   together.
+
+The ``layer.conf`` files are used to construct key variables such as
+:term:`BBPATH` and :term:`BBFILES`.
+``BBPATH`` is used to search for configuration and class files under the
+``conf`` and ``classes`` directories, respectively. ``BBFILES`` is used
+to locate both recipe and recipe append files (``.bb`` and
+``.bbappend``). If there is no ``bblayers.conf`` file, it is assumed the
+user has set the ``BBPATH`` and ``BBFILES`` directly in the environment.
+
+Next, the ``bitbake.conf`` file is located using the ``BBPATH`` variable
+that was just constructed. The ``bitbake.conf`` file may also include
+other configuration files using the ``include`` or ``require``
+directives.
+
+Prior to parsing configuration files, BitBake looks at certain
+variables, including:
+
+-  :term:`BB_ENV_WHITELIST`
+-  :term:`BB_ENV_EXTRAWHITE`
+-  :term:`BB_PRESERVE_ENV`
+-  :term:`BB_ORIGENV`
+-  :term:`BITBAKE_UI`
+
+The first four variables in this list relate to how BitBake treats shell
+environment variables during task execution. By default, BitBake cleans
+the environment variables and provides tight control over the shell
+execution environment. However, through the use of these first four
+variables, you can apply your control regarding the environment
+variables allowed to be used by BitBake in the shell during execution of
+tasks. See the
+":ref:`bitbake-user-manual/bitbake-user-manual-metadata:Passing Information Into the Build Task Environment`"
+section and the information about these variables in the variable
+glossary for more information on how they work and on how to use them.
+
+The base configuration metadata is global and therefore affects all
+recipes and tasks that are executed.
+
+BitBake first searches the current working directory for an optional
+``conf/bblayers.conf`` configuration file. This file is expected to
+contain a :term:`BBLAYERS` variable that is a
+space-delimited list of 'layer' directories. Recall that if BitBake
+cannot find a ``bblayers.conf`` file, then it is assumed the user has
+set the ``BBPATH`` and ``BBFILES`` variables directly in the
+environment.
+
+For each directory (layer) in this list, a ``conf/layer.conf`` file is
+located and parsed with the :term:`LAYERDIR` variable
+being set to the directory where the layer was found. The idea is these
+files automatically set up :term:`BBPATH` and other
+variables correctly for a given build directory.
+
+BitBake then expects to find the ``conf/bitbake.conf`` file somewhere in
+the user-specified ``BBPATH``. That configuration file generally has
+include directives to pull in any other metadata such as files specific
+to the architecture, the machine, the local environment, and so forth.
+
+Only variable definitions and include directives are allowed in BitBake
+``.conf`` files. Some variables directly influence BitBake's behavior.
+These variables might have been set from the environment depending on
+the environment variables previously mentioned or set in the
+configuration files. The ":ref:`bitbake-user-manual/bitbake-user-manual-ref-variables:Variables Glossary`"
+chapter presents a full list of
+variables.
+
+After parsing configuration files, BitBake uses its rudimentary
+inheritance mechanism, which is through class files, to inherit some
+standard classes. BitBake parses a class when the inherit directive
+responsible for getting that class is encountered.
+
+The ``base.bbclass`` file is always included. Other classes that are
+specified in the configuration using the
+:term:`INHERIT` variable are also included. BitBake
+searches for class files in a ``classes`` subdirectory under the paths
+in ``BBPATH`` in the same way as configuration files.
+
+A good way to get an idea of the configuration files and the class files
+used in your execution environment is to run the following BitBake
+command: ::
+
+  $ bitbake -e > mybb.log
+
+Examining the top of the ``mybb.log``
+shows you the many configuration files and class files used in your
+execution environment.
+
+.. note::
+
+   You need to be aware of how BitBake parses curly braces. If a recipe
+   uses a closing curly brace within the function and the character has
+   no leading spaces, BitBake produces a parsing error. If you use a
+   pair of curly braces in a shell function, the closing curly brace
+   must not be located at the start of the line without leading spaces.
+
+   Here is an example that causes BitBake to produce a parsing error: ::
+
+      fakeroot create_shar() {
+         cat << "EOF" > ${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.sh
+      usage()
+      {
+         echo "test"
+         ######  The following "}" at the start of the line causes a parsing error ######
+      }
+      EOF
+      }
+
+      Writing the recipe this way avoids the error:
+      fakeroot create_shar() {
+         cat << "EOF" > ${SDK_DEPLOY}/${TOOLCHAIN_OUTPUTNAME}.sh
+      usage()
+      {
+         echo "test"
+         ###### The following "}" with a leading space at the start of the line avoids the error ######
+       }
+      EOF
+      }
+
+Locating and Parsing Recipes
+============================
+
+During the configuration phase, BitBake will have set
+:term:`BBFILES`. BitBake now uses it to construct a
+list of recipes to parse, along with any append files (``.bbappend``) to
+apply. ``BBFILES`` is a space-separated list of available files and
+supports wildcards. An example would be: ::
+
+  BBFILES = "/path/to/bbfiles/*.bb /path/to/appends/*.bbappend"
+
+BitBake parses each
+recipe and append file located with ``BBFILES`` and stores the values of
+various variables into the datastore.
+
+.. note::
+
+   Append files are applied in the order they are encountered in BBFILES.
+
+For each file, a fresh copy of the base configuration is made, then the
+recipe is parsed line by line. Any inherit statements cause BitBake to
+find and then parse class files (``.bbclass``) using
+:term:`BBPATH` as the search path. Finally, BitBake
+parses in order any append files found in ``BBFILES``.
+
+One common convention is to use the recipe filename to define pieces of
+metadata. For example, in ``bitbake.conf`` the recipe name and version
+are used to set the variables :term:`PN` and
+:term:`PV`: ::
+
+   PN = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
+   PV = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[1] or '1.0'}"
+
+In this example, a recipe called "something_1.2.3.bb" would set
+``PN`` to "something" and ``PV`` to "1.2.3".
+
+By the time parsing is complete for a recipe, BitBake has a list of
+tasks that the recipe defines and a set of data consisting of keys and
+values as well as dependency information about the tasks.
+
+BitBake does not need all of this information. It only needs a small
+subset of the information to make decisions about the recipe.
+Consequently, BitBake caches the values in which it is interested and
+does not store the rest of the information. Experience has shown it is
+faster to re-parse the metadata than to try and write it out to the disk
+and then reload it.
+
+Where possible, subsequent BitBake commands reuse this cache of recipe
+information. The validity of this cache is determined by first computing
+a checksum of the base configuration data (see
+:term:`BB_HASHCONFIG_WHITELIST`) and
+then checking if the checksum matches. If that checksum matches what is
+in the cache and the recipe and class files have not changed, BitBake is
+able to use the cache. BitBake then reloads the cached information about
+the recipe instead of reparsing it from scratch.
+
+Recipe file collections exist to allow the user to have multiple
+repositories of ``.bb`` files that contain the same exact package. For
+example, one could easily use them to make one's own local copy of an
+upstream repository, but with custom modifications that one does not
+want upstream. Here is an example: ::
+
+  BBFILES = "/stuff/openembedded/*/*.bb /stuff/openembedded.modified/*/*.bb"
+  BBFILE_COLLECTIONS = "upstream local"
+  BBFILE_PATTERN_upstream = "^/stuff/openembedded/"
+  BBFILE_PATTERN_local = "^/stuff/openembedded.modified/"
+  BBFILE_PRIORITY_upstream = "5" BBFILE_PRIORITY_local = "10"
+
+.. note::
+
+   The layers mechanism is now the preferred method of collecting code.
+   While the collections code remains, its main use is to set layer
+   priorities and to deal with overlap (conflicts) between layers.
+
+.. _bb-bitbake-providers:
+
+Providers
+=========
+
+Assuming BitBake has been instructed to execute a target and that all
+the recipe files have been parsed, BitBake starts to figure out how to
+build the target. BitBake looks through the ``PROVIDES`` list for each
+of the recipes. A ``PROVIDES`` list is the list of names by which the
+recipe can be known. Each recipe's ``PROVIDES`` list is created
+implicitly through the recipe's :term:`PN` variable and
+explicitly through the recipe's :term:`PROVIDES`
+variable, which is optional.
+
+When a recipe uses ``PROVIDES``, that recipe's functionality can be
+found under an alternative name or names other than the implicit ``PN``
+name. As an example, suppose a recipe named ``keyboard_1.0.bb``
+contained the following: ::
+
+  PROVIDES += "fullkeyboard"
+
+The ``PROVIDES``
+list for this recipe becomes "keyboard", which is implicit, and
+"fullkeyboard", which is explicit. Consequently, the functionality found
+in ``keyboard_1.0.bb`` can be found under two different names.
+
+.. _bb-bitbake-preferences:
+
+Preferences
+===========
+
+The ``PROVIDES`` list is only part of the solution for figuring out a
+target's recipes. Because targets might have multiple providers, BitBake
+needs to prioritize providers by determining provider preferences.
+
+A common example in which a target has multiple providers is
+"virtual/kernel", which is on the ``PROVIDES`` list for each kernel
+recipe. Each machine often selects the best kernel provider by using a
+line similar to the following in the machine configuration file: ::
+
+  PREFERRED_PROVIDER_virtual/kernel = "linux-yocto"
+
+The default :term:`PREFERRED_PROVIDER` is the provider
+with the same name as the target. BitBake iterates through each target
+it needs to build and resolves them and their dependencies using this
+process.
+
+Understanding how providers are chosen is made complicated by the fact
+that multiple versions might exist for a given provider. BitBake
+defaults to the highest version of a provider. Version comparisons are
+made using the same method as Debian. You can use the
+:term:`PREFERRED_VERSION` variable to
+specify a particular version. You can influence the order by using the
+:term:`DEFAULT_PREFERENCE` variable.
+
+By default, files have a preference of "0". Setting
+``DEFAULT_PREFERENCE`` to "-1" makes the recipe unlikely to be used
+unless it is explicitly referenced. Setting ``DEFAULT_PREFERENCE`` to
+"1" makes it likely the recipe is used. ``PREFERRED_VERSION`` overrides
+any ``DEFAULT_PREFERENCE`` setting. ``DEFAULT_PREFERENCE`` is often used
+to mark newer and more experimental recipe versions until they have
+undergone sufficient testing to be considered stable.
+
+When there are multiple "versions" of a given recipe, BitBake defaults
+to selecting the most recent version, unless otherwise specified. If the
+recipe in question has a
+:term:`DEFAULT_PREFERENCE` set lower than
+the other recipes (default is 0), then it will not be selected. This
+allows the person or persons maintaining the repository of recipe files
+to specify their preference for the default selected version.
+Additionally, the user can specify their preferred version.
+
+If the first recipe is named ``a_1.1.bb``, then the
+:term:`PN` variable will be set to "a", and the
+:term:`PV` variable will be set to 1.1.
+
+Thus, if a recipe named ``a_1.2.bb`` exists, BitBake will choose 1.2 by
+default. However, if you define the following variable in a ``.conf``
+file that BitBake parses, you can change that preference: ::
+
+  PREFERRED_VERSION_a = "1.1"
+
+.. note::
+
+   It is common for a recipe to provide two versions -- a stable,
+   numbered (and preferred) version, and a version that is automatically
+   checked out from a source code repository that is considered more
+   "bleeding edge" but can be selected only explicitly.
+
+   For example, in the OpenEmbedded codebase, there is a standard,
+   versioned recipe file for BusyBox, ``busybox_1.22.1.bb``, but there
+   is also a Git-based version, ``busybox_git.bb``, which explicitly
+   contains the line ::
+
+     DEFAULT_PREFERENCE = "-1"
+
+   to ensure that the
+   numbered, stable version is always preferred unless the developer
+   selects otherwise.
+
+.. _bb-bitbake-dependencies:
+
+Dependencies
+============
+
+Each target BitBake builds consists of multiple tasks such as ``fetch``,
+``unpack``, ``patch``, ``configure``, and ``compile``. For best
+performance on multi-core systems, BitBake considers each task as an
+independent entity with its own set of dependencies.
+
+Dependencies are defined through several variables. You can find
+information about variables BitBake uses in the
+:doc:`bitbake-user-manual-ref-variables` near the end of this manual. At a
+basic level, it is sufficient to know that BitBake uses the
+:term:`DEPENDS` and
+:term:`RDEPENDS` variables when calculating
+dependencies.
+
+For more information on how BitBake handles dependencies, see the
+:ref:`bitbake-user-manual/bitbake-user-manual-metadata:Dependencies`
+section.
+
+.. _ref-bitbake-tasklist:
+
+The Task List
+=============
+
+Based on the generated list of providers and the dependency information,
+BitBake can now calculate exactly what tasks it needs to run and in what
+order it needs to run them. The
+:ref:`bitbake-user-manual/bitbake-user-manual-execution:executing tasks`
+section has more information on how BitBake chooses which task to
+execute next.
+
+The build now starts with BitBake forking off threads up to the limit
+set in the :term:`BB_NUMBER_THREADS`
+variable. BitBake continues to fork threads as long as there are tasks
+ready to run, those tasks have all their dependencies met, and the
+thread threshold has not been exceeded.
+
+It is worth noting that you can greatly speed up the build time by
+properly setting the ``BB_NUMBER_THREADS`` variable.
+
+As each task completes, a timestamp is written to the directory
+specified by the :term:`STAMP` variable. On subsequent
+runs, BitBake looks in the build directory within ``tmp/stamps`` and
+does not rerun tasks that are already completed unless a timestamp is
+found to be invalid. Currently, invalid timestamps are only considered
+on a per recipe file basis. So, for example, if the configure stamp has
+a timestamp greater than the compile timestamp for a given target, then
+the compile task would rerun. Running the compile task again, however,
+has no effect on other providers that depend on that target.
+
+The exact format of the stamps is partly configurable. In modern
+versions of BitBake, a hash is appended to the stamp so that if the
+configuration changes, the stamp becomes invalid and the task is
+automatically rerun. This hash, or signature used, is governed by the
+signature policy that is configured (see the
+:ref:`bitbake-user-manual/bitbake-user-manual-execution:checksums (signatures)`
+section for information). It is also
+possible to append extra metadata to the stamp using the
+``[stamp-extra-info]`` task flag. For example, OpenEmbedded uses this
+flag to make some tasks machine-specific.
+
+.. note::
+
+   Some tasks are marked as "nostamp" tasks. No timestamp file is
+   created when these tasks are run. Consequently, "nostamp" tasks are
+   always rerun.
+
+For more information on tasks, see the
+:ref:`bitbake-user-manual/bitbake-user-manual-metadata:tasks` section.
+
+Executing Tasks
+===============
+
+Tasks can be either a shell task or a Python task. For shell tasks,
+BitBake writes a shell script to
+``${``\ :term:`T`\ ``}/run.do_taskname.pid`` and then
+executes the script. The generated shell script contains all the
+exported variables, and the shell functions with all variables expanded.
+Output from the shell script goes to the file
+``${T}/log.do_taskname.pid``. Looking at the expanded shell functions in
+the run file and the output in the log files is a useful debugging
+technique.
+
+For Python tasks, BitBake executes the task internally and logs
+information to the controlling terminal. Future versions of BitBake will
+write the functions to files similar to the way shell tasks are handled.
+Logging will be handled in a way similar to shell tasks as well.
+
+The order in which BitBake runs the tasks is controlled by its task
+scheduler. It is possible to configure the scheduler and define custom
+implementations for specific use cases. For more information, see these
+variables that control the behavior:
+
+-  :term:`BB_SCHEDULER`
+
+-  :term:`BB_SCHEDULERS`
+
+It is possible to have functions run before and after a task's main
+function. This is done using the ``[prefuncs]`` and ``[postfuncs]``
+flags of the task that lists the functions to run.
+
+.. _checksums:
+
+Checksums (Signatures)
+======================
+
+A checksum is a unique signature of a task's inputs. The signature of a
+task can be used to determine if a task needs to be run. Because it is a
+change in a task's inputs that triggers running the task, BitBake needs
+to detect all the inputs to a given task. For shell tasks, this turns
+out to be fairly easy because BitBake generates a "run" shell script for
+each task and it is possible to create a checksum that gives you a good
+idea of when the task's data changes.
+
+To complicate the problem, some things should not be included in the
+checksum. First, there is the actual specific build path of a given task
+- the working directory. It does not matter if the working directory
+changes because it should not affect the output for target packages. The
+simplistic approach for excluding the working directory is to set it to
+some fixed value and create the checksum for the "run" script. BitBake
+goes one step better and uses the
+:term:`BB_HASHBASE_WHITELIST` variable
+to define a list of variables that should never be included when
+generating the signatures.
+
+Another problem results from the "run" scripts containing functions that
+might or might not get called. The incremental build solution contains
+code that figures out dependencies between shell functions. This code is
+used to prune the "run" scripts down to the minimum set, thereby
+alleviating this problem and making the "run" scripts much more readable
+as a bonus.
+
+So far we have solutions for shell scripts. What about Python tasks? The
+same approach applies even though these tasks are more difficult. The
+process needs to figure out what variables a Python function accesses
+and what functions it calls. Again, the incremental build solution
+contains code that first figures out the variable and function
+dependencies, and then creates a checksum for the data used as the input
+to the task.
+
+Like the working directory case, situations exist where dependencies
+should be ignored. For these cases, you can instruct the build process
+to ignore a dependency by using a line like the following: ::
+
+  PACKAGE_ARCHS[vardepsexclude] = "MACHINE"
+
+This example ensures that the
+``PACKAGE_ARCHS`` variable does not depend on the value of ``MACHINE``,
+even if it does reference it.
+
+Equally, there are cases where we need to add dependencies BitBake is
+not able to find. You can accomplish this by using a line like the
+following: ::
+
+  PACKAGE_ARCHS[vardeps] = "MACHINE"
+
+This example explicitly
+adds the ``MACHINE`` variable as a dependency for ``PACKAGE_ARCHS``.
+
+Consider a case with in-line Python, for example, where BitBake is not
+able to figure out dependencies. When running in debug mode (i.e. using
+``-DDD``), BitBake produces output when it discovers something for which
+it cannot figure out dependencies.
+
+Thus far, this section has limited discussion to the direct inputs into
+a task. Information based on direct inputs is referred to as the
+"basehash" in the code. However, there is still the question of a task's
+indirect inputs - the things that were already built and present in the
+build directory. The checksum (or signature) for a particular task needs
+to add the hashes of all the tasks on which the particular task depends.
+Choosing which dependencies to add is a policy decision. However, the
+effect is to generate a master checksum that combines the basehash and
+the hashes of the task's dependencies.
+
+At the code level, there are a variety of ways both the basehash and the
+dependent task hashes can be influenced. Within the BitBake
+configuration file, we can give BitBake some extra information to help
+it construct the basehash. The following statement effectively results
+in a list of global variable dependency excludes - variables never
+included in any checksum. This example uses variables from OpenEmbedded
+to help illustrate the concept: ::
+
+   BB_HASHBASE_WHITELIST ?= "TMPDIR FILE PATH PWD BB_TASKHASH BBPATH DL_DIR \
+       SSTATE_DIR THISDIR FILESEXTRAPATHS FILE_DIRNAME HOME LOGNAME SHELL \
+       USER FILESPATH STAGING_DIR_HOST STAGING_DIR_TARGET COREBASE PRSERV_HOST \
+       PRSERV_DUMPDIR PRSERV_DUMPFILE PRSERV_LOCKDOWN PARALLEL_MAKE \
+       CCACHE_DIR EXTERNAL_TOOLCHAIN CCACHE CCACHE_DISABLE LICENSE_PATH SDKPKGSUFFIX"
+
+The previous example excludes the work directory, which is part of
+``TMPDIR``.
+
+The rules for deciding which hashes of dependent tasks to include
+through dependency chains are more complex and are generally
+accomplished with a Python function. The code in
+``meta/lib/oe/sstatesig.py`` shows two examples of this and also
+illustrates how you can insert your own policy into the system if so
+desired. This file defines the two basic signature generators
+OpenEmbedded-Core uses: "OEBasic" and "OEBasicHash". By default, there
+is a dummy "noop" signature handler enabled in BitBake. This means that
+behavior is unchanged from previous versions. ``OE-Core`` uses the
+"OEBasicHash" signature handler by default through this setting in the
+``bitbake.conf`` file: ::
+
+  BB_SIGNATURE_HANDLER ?= "OEBasicHash"
+
+The "OEBasicHash" ``BB_SIGNATURE_HANDLER`` is the same as the "OEBasic"
+version but adds the task hash to the stamp files. This results in any
+metadata change that changes the task hash, automatically causing the
+task to be run again. This removes the need to bump
+:term:`PR` values, and changes to metadata automatically
+ripple across the build.
+
+It is also worth noting that the end result of these signature
+generators is to make some dependency and hash information available to
+the build. This information includes:
+
+-  ``BB_BASEHASH_task-``\ *taskname*: The base hashes for each task in the
+   recipe.
+
+-  ``BB_BASEHASH_``\ *filename:taskname*: The base hashes for each
+   dependent task.
+
+-  ``BBHASHDEPS_``\ *filename:taskname*: The task dependencies for
+   each task.
+
+-  ``BB_TASKHASH``: The hash of the currently running task.
+
+It is worth noting that BitBake's "-S" option lets you debug BitBake's
+processing of signatures. The options passed to -S allow different
+debugging modes to be used, either using BitBake's own debug functions
+or possibly those defined in the metadata/signature handler itself. The
+simplest parameter to pass is "none", which causes a set of signature
+information to be written out into ``STAMPS_DIR`` corresponding to the
+targets specified. The other currently available parameter is
+"printdiff", which causes BitBake to try to establish the closest
+signature match it can (e.g. in the sstate cache) and then run
+``bitbake-diffsigs`` over the matches to determine the stamps and delta
+where these two stamp trees diverge.
+
+.. note::
+
+   It is likely that future versions of BitBake will provide other
+   signature handlers triggered through additional "-S" parameters.
+
+You can find more information on checksum metadata in the
+:ref:`bitbake-user-manual/bitbake-user-manual-metadata:task checksums and setscene`
+section.
+
+Setscene
+========
+
+The setscene process enables BitBake to handle "pre-built" artifacts.
+The ability to handle and reuse these artifacts allows BitBake the
+luxury of not having to build something from scratch every time.
+Instead, BitBake can use, when possible, existing build artifacts.
+
+BitBake needs to have reliable data indicating whether or not an
+artifact is compatible. Signatures, described in the previous section,
+provide an ideal way of representing whether an artifact is compatible.
+If a signature is the same, an object can be reused.
+
+If an object can be reused, the problem then becomes how to replace a
+given task or set of tasks with the pre-built artifact. BitBake solves
+the problem with the "setscene" process.
+
+When BitBake is asked to build a given target, before building anything,
+it first asks whether cached information is available for any of the
+targets it's building, or any of the intermediate targets. If cached
+information is available, BitBake uses this information instead of
+running the main tasks.
+
+BitBake first calls the function defined by the
+:term:`BB_HASHCHECK_FUNCTION` variable
+with a list of tasks and corresponding hashes it wants to build. This
+function is designed to be fast and returns a list of the tasks for
+which it believes in can obtain artifacts.
+
+Next, for each of the tasks that were returned as possibilities, BitBake
+executes a setscene version of the task that the possible artifact
+covers. Setscene versions of a task have the string "_setscene" appended
+to the task name. So, for example, the task with the name ``xxx`` has a
+setscene task named ``xxx_setscene``. The setscene version of the task
+executes and provides the necessary artifacts returning either success
+or failure.
+
+As previously mentioned, an artifact can cover more than one task. For
+example, it is pointless to obtain a compiler if you already have the
+compiled binary. To handle this, BitBake calls the
+:term:`BB_SETSCENE_DEPVALID` function for
+each successful setscene task to know whether or not it needs to obtain
+the dependencies of that task.
+
+Finally, after all the setscene tasks have executed, BitBake calls the
+function listed in
+:term:`BB_SETSCENE_VERIFY_FUNCTION2`
+with the list of tasks BitBake thinks has been "covered". The metadata
+can then ensure that this list is correct and can inform BitBake that it
+wants specific tasks to be run regardless of the setscene result.
+
+You can find more information on setscene metadata in the
+:ref:`bitbake-user-manual/bitbake-user-manual-metadata:task checksums and setscene`
+section.
+
+Logging
+=======
+
+In addition to the standard command line option to control how verbose
+builds are when execute, bitbake also supports user defined
+configuration of the `Python
+logging <https://docs.python.org/3/library/logging.html>`__ facilities
+through the :term:`BB_LOGCONFIG` variable. This
+variable defines a json or yaml `logging
+configuration <https://docs.python.org/3/library/logging.config.html>`__
+that will be intelligently merged into the default configuration. The
+logging configuration is merged using the following rules:
+
+-  The user defined configuration will completely replace the default
+   configuration if top level key ``bitbake_merge`` is set to the value
+   ``False``. In this case, all other rules are ignored.
+
+-  The user configuration must have a top level ``version`` which must
+   match the value of the default configuration.
+
+-  Any keys defined in the ``handlers``, ``formatters``, or ``filters``,
+   will be merged into the same section in the default configuration,
+   with the user specified keys taking replacing a default one if there
+   is a conflict. In practice, this means that if both the default
+   configuration and user configuration specify a handler named
+   ``myhandler``, the user defined one will replace the default. To
+   prevent the user from inadvertently replacing a default handler,
+   formatter, or filter, all of the default ones are named with a prefix
+   of "``BitBake.``"
+
+-  If a logger is defined by the user with the key ``bitbake_merge`` set
+   to ``False``, that logger will be completely replaced by user
+   configuration. In this case, no other rules will apply to that
+   logger.
+
+-  All user defined ``filter`` and ``handlers`` properties for a given
+   logger will be merged with corresponding properties from the default
+   logger. For example, if the user configuration adds a filter called
+   ``myFilter`` to the ``BitBake.SigGen``, and the default configuration
+   adds a filter called ``BitBake.defaultFilter``, both filters will be
+   applied to the logger
+
+As an example, consider the following user logging configuration file
+which logs all Hash Equivalence related messages of VERBOSE or higher to
+a file called ``hashequiv.log`` ::
+
+   {
+       "version": 1,
+       "handlers": {
+           "autobuilderlog": {
+               "class": "logging.FileHandler",
+               "formatter": "logfileFormatter",
+               "level": "DEBUG",
+               "filename": "hashequiv.log",
+               "mode": "w"
+           }
+       },
+       "formatters": {
+               "logfileFormatter": {
+                   "format": "%(name)s: %(levelname)s: %(message)s"
+               }
+       },
+       "loggers": {
+           "BitBake.SigGen.HashEquiv": {
+               "level": "VERBOSE",
+               "handlers": ["autobuilderlog"]
+           },
+           "BitBake.RunQueue.HashEquiv": {
+               "level": "VERBOSE",
+               "handlers": ["autobuilderlog"]
+           }
+       }
+   }

+ 652 - 0
openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-fetching.rst

@@ -0,0 +1,652 @@
+.. SPDX-License-Identifier: CC-BY-2.5
+
+=====================
+File Download Support
+=====================
+
+|
+
+BitBake's fetch module is a standalone piece of library code that deals
+with the intricacies of downloading source code and files from remote
+systems. Fetching source code is one of the cornerstones of building
+software. As such, this module forms an important part of BitBake.
+
+The current fetch module is called "fetch2" and refers to the fact that
+it is the second major version of the API. The original version is
+obsolete and has been removed from the codebase. Thus, in all cases,
+"fetch" refers to "fetch2" in this manual.
+
+The Download (Fetch)
+====================
+
+BitBake takes several steps when fetching source code or files. The
+fetcher codebase deals with two distinct processes in order: obtaining
+the files from somewhere (cached or otherwise) and then unpacking those
+files into a specific location and perhaps in a specific way. Getting
+and unpacking the files is often optionally followed by patching.
+Patching, however, is not covered by this module.
+
+The code to execute the first part of this process, a fetch, looks
+something like the following: ::
+
+   src_uri = (d.getVar('SRC_URI') or "").split()
+   fetcher = bb.fetch2.Fetch(src_uri, d)
+   fetcher.download()
+
+This code sets up an instance of the fetch class. The instance uses a
+space-separated list of URLs from the :term:`SRC_URI`
+variable and then calls the ``download`` method to download the files.
+
+The instantiation of the fetch class is usually followed by: ::
+
+   rootdir = l.getVar('WORKDIR')
+   fetcher.unpack(rootdir)
+
+This code unpacks the downloaded files to the specified by ``WORKDIR``.
+
+.. note::
+
+   For convenience, the naming in these examples matches the variables
+   used by OpenEmbedded. If you want to see the above code in action,
+   examine the OpenEmbedded class file ``base.bbclass``
+   .
+
+The ``SRC_URI`` and ``WORKDIR`` variables are not hardcoded into the
+fetcher, since those fetcher methods can be (and are) called with
+different variable names. In OpenEmbedded for example, the shared state
+(sstate) code uses the fetch module to fetch the sstate files.
+
+When the ``download()`` method is called, BitBake tries to resolve the
+URLs by looking for source files in a specific search order:
+
+-  *Pre-mirror Sites:* BitBake first uses pre-mirrors to try and find
+   source files. These locations are defined using the
+   :term:`PREMIRRORS` variable.
+
+-  *Source URI:* If pre-mirrors fail, BitBake uses the original URL (e.g
+   from ``SRC_URI``).
+
+-  *Mirror Sites:* If fetch failures occur, BitBake next uses mirror
+   locations as defined by the :term:`MIRRORS` variable.
+
+For each URL passed to the fetcher, the fetcher calls the submodule that
+handles that particular URL type. This behavior can be the source of
+some confusion when you are providing URLs for the ``SRC_URI`` variable.
+Consider the following two URLs: ::
+
+   http://git.yoctoproject.org/git/poky;protocol=git
+   git://git.yoctoproject.org/git/poky;protocol=http
+
+In the former case, the URL is passed to the ``wget`` fetcher, which does not
+understand "git". Therefore, the latter case is the correct form since the Git
+fetcher does know how to use HTTP as a transport.
+
+Here are some examples that show commonly used mirror definitions: ::
+
+   PREMIRRORS ?= "\
+      bzr://.*/.\*  http://somemirror.org/sources/ \\n \
+      cvs://.*/.\*  http://somemirror.org/sources/ \\n \
+      git://.*/.\*  http://somemirror.org/sources/ \\n \
+      hg://.*/.\*   http://somemirror.org/sources/ \\n \
+      osc://.*/.\*  http://somemirror.org/sources/ \\n \
+      p4://.*/.\*   http://somemirror.org/sources/ \\n \
+     svn://.*/.\*   http://somemirror.org/sources/ \\n"
+
+   MIRRORS =+ "\
+      ftp://.*/.\*   http://somemirror.org/sources/ \\n \
+      http://.*/.\*  http://somemirror.org/sources/ \\n \
+      https://.*/.\* http://somemirror.org/sources/ \\n"
+
+It is useful to note that BitBake
+supports cross-URLs. It is possible to mirror a Git repository on an
+HTTP server as a tarball. This is what the ``git://`` mapping in the
+previous example does.
+
+Since network accesses are slow, BitBake maintains a cache of files
+downloaded from the network. Any source files that are not local (i.e.
+downloaded from the Internet) are placed into the download directory,
+which is specified by the :term:`DL_DIR` variable.
+
+File integrity is of key importance for reproducing builds. For
+non-local archive downloads, the fetcher code can verify SHA-256 and MD5
+checksums to ensure the archives have been downloaded correctly. You can
+specify these checksums by using the ``SRC_URI`` variable with the
+appropriate varflags as follows: ::
+
+   SRC_URI[md5sum] = "value"
+   SRC_URI[sha256sum] = "value"
+
+You can also specify the checksums as
+parameters on the ``SRC_URI`` as shown below: ::
+
+  SRC_URI = "http://example.com/foobar.tar.bz2;md5sum=4a8e0f237e961fd7785d19d07fdb994d"
+
+If multiple URIs exist, you can specify the checksums either directly as
+in the previous example, or you can name the URLs. The following syntax
+shows how you name the URIs: ::
+
+   SRC_URI = "http://example.com/foobar.tar.bz2;name=foo"
+   SRC_URI[foo.md5sum] = 4a8e0f237e961fd7785d19d07fdb994d
+
+After a file has been downloaded and
+has had its checksum checked, a ".done" stamp is placed in ``DL_DIR``.
+BitBake uses this stamp during subsequent builds to avoid downloading or
+comparing a checksum for the file again.
+
+.. note::
+
+   It is assumed that local storage is safe from data corruption. If
+   this were not the case, there would be bigger issues to worry about.
+
+If :term:`BB_STRICT_CHECKSUM` is set, any
+download without a checksum triggers an error message. The
+:term:`BB_NO_NETWORK` variable can be used to
+make any attempted network access a fatal error, which is useful for
+checking that mirrors are complete as well as other things.
+
+.. _bb-the-unpack:
+
+The Unpack
+==========
+
+The unpack process usually immediately follows the download. For all
+URLs except Git URLs, BitBake uses the common ``unpack`` method.
+
+A number of parameters exist that you can specify within the URL to
+govern the behavior of the unpack stage:
+
+-  *unpack:* Controls whether the URL components are unpacked. If set to
+   "1", which is the default, the components are unpacked. If set to
+   "0", the unpack stage leaves the file alone. This parameter is useful
+   when you want an archive to be copied in and not be unpacked.
+
+-  *dos:* Applies to ``.zip`` and ``.jar`` files and specifies whether
+   to use DOS line ending conversion on text files.
+
+-  *basepath:* Instructs the unpack stage to strip the specified
+   directories from the source path when unpacking.
+
+-  *subdir:* Unpacks the specific URL to the specified subdirectory
+   within the root directory.
+
+The unpack call automatically decompresses and extracts files with ".Z",
+".z", ".gz", ".xz", ".zip", ".jar", ".ipk", ".rpm". ".srpm", ".deb" and
+".bz2" extensions as well as various combinations of tarball extensions.
+
+As mentioned, the Git fetcher has its own unpack method that is
+optimized to work with Git trees. Basically, this method works by
+cloning the tree into the final directory. The process is completed
+using references so that there is only one central copy of the Git
+metadata needed.
+
+.. _bb-fetchers:
+
+Fetchers
+========
+
+As mentioned earlier, the URL prefix determines which fetcher submodule
+BitBake uses. Each submodule can support different URL parameters, which
+are described in the following sections.
+
+.. _local-file-fetcher:
+
+Local file fetcher (``file://``)
+--------------------------------
+
+This submodule handles URLs that begin with ``file://``. The filename
+you specify within the URL can be either an absolute or relative path to
+a file. If the filename is relative, the contents of the
+:term:`FILESPATH` variable is used in the same way
+``PATH`` is used to find executables. If the file cannot be found, it is
+assumed that it is available in :term:`DL_DIR` by the
+time the ``download()`` method is called.
+
+If you specify a directory, the entire directory is unpacked.
+
+Here are a couple of example URLs, the first relative and the second
+absolute: ::
+
+   SRC_URI = "file://relativefile.patch"
+   SRC_URI = "file:///Users/ich/very_important_software"
+
+.. _http-ftp-fetcher:
+
+HTTP/FTP wget fetcher (``http://``, ``ftp://``, ``https://``)
+-------------------------------------------------------------
+
+This fetcher obtains files from web and FTP servers. Internally, the
+fetcher uses the wget utility.
+
+The executable and parameters used are specified by the
+``FETCHCMD_wget`` variable, which defaults to sensible values. The
+fetcher supports a parameter "downloadfilename" that allows the name of
+the downloaded file to be specified. Specifying the name of the
+downloaded file is useful for avoiding collisions in
+:term:`DL_DIR` when dealing with multiple files that
+have the same name.
+
+Some example URLs are as follows: ::
+
+   SRC_URI = "http://oe.handhelds.org/not_there.aac"
+   SRC_URI = "ftp://oe.handhelds.org/not_there_as_well.aac"
+   SRC_URI = "ftp://you@oe.handhelds.org/home/you/secret.plan"
+
+.. note::
+
+   Because URL parameters are delimited by semi-colons, this can
+   introduce ambiguity when parsing URLs that also contain semi-colons,
+   for example:
+   ::
+
+           SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git;a=snapshot;h=a5dd47"
+
+
+   Such URLs should should be modified by replacing semi-colons with '&'
+   characters:
+   ::
+
+           SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git&a=snapshot&h=a5dd47"
+
+
+   In most cases this should work. Treating semi-colons and '&' in
+   queries identically is recommended by the World Wide Web Consortium
+   (W3C). Note that due to the nature of the URL, you may have to
+   specify the name of the downloaded file as well:
+   ::
+
+           SRC_URI = "http://abc123.org/git/?p=gcc/gcc.git&a=snapshot&h=a5dd47;downloadfilename=myfile.bz2"
+
+
+.. _cvs-fetcher:
+
+CVS fetcher (``(cvs://``)
+-------------------------
+
+This submodule handles checking out files from the CVS version control
+system. You can configure it using a number of different variables:
+
+-  :term:`FETCHCMD_cvs <FETCHCMD>`: The name of the executable to use when running
+   the ``cvs`` command. This name is usually "cvs".
+
+-  :term:`SRCDATE`: The date to use when fetching the CVS source code. A
+   special value of "now" causes the checkout to be updated on every
+   build.
+
+-  :term:`CVSDIR`: Specifies where a temporary
+   checkout is saved. The location is often ``DL_DIR/cvs``.
+
+-  CVS_PROXY_HOST: The name to use as a "proxy=" parameter to the
+   ``cvs`` command.
+
+-  CVS_PROXY_PORT: The port number to use as a "proxyport="
+   parameter to the ``cvs`` command.
+
+As well as the standard username and password URL syntax, you can also
+configure the fetcher with various URL parameters:
+
+The supported parameters are as follows:
+
+-  *"method":* The protocol over which to communicate with the CVS
+   server. By default, this protocol is "pserver". If "method" is set to
+   "ext", BitBake examines the "rsh" parameter and sets ``CVS_RSH``. You
+   can use "dir" for local directories.
+
+-  *"module":* Specifies the module to check out. You must supply this
+   parameter.
+
+-  *"tag":* Describes which CVS TAG should be used for the checkout. By
+   default, the TAG is empty.
+
+-  *"date":* Specifies a date. If no "date" is specified, the
+   :term:`SRCDATE` of the configuration is used to
+   checkout a specific date. The special value of "now" causes the
+   checkout to be updated on every build.
+
+-  *"localdir":* Used to rename the module. Effectively, you are
+   renaming the output directory to which the module is unpacked. You
+   are forcing the module into a special directory relative to
+   :term:`CVSDIR`.
+
+-  *"rsh":* Used in conjunction with the "method" parameter.
+
+-  *"scmdata":* Causes the CVS metadata to be maintained in the tarball
+   the fetcher creates when set to "keep". The tarball is expanded into
+   the work directory. By default, the CVS metadata is removed.
+
+-  *"fullpath":* Controls whether the resulting checkout is at the
+   module level, which is the default, or is at deeper paths.
+
+-  *"norecurse":* Causes the fetcher to only checkout the specified
+   directory with no recurse into any subdirectories.
+
+-  *"port":* The port to which the CVS server connects.
+
+Some example URLs are as follows: ::
+
+   SRC_URI = "cvs://CVSROOT;module=mymodule;tag=some-version;method=ext"
+   SRC_URI = "cvs://CVSROOT;module=mymodule;date=20060126;localdir=usethat"
+
+.. _svn-fetcher:
+
+Subversion (SVN) Fetcher (``svn://``)
+-------------------------------------
+
+This fetcher submodule fetches code from the Subversion source control
+system. The executable used is specified by ``FETCHCMD_svn``, which
+defaults to "svn". The fetcher's temporary working directory is set by
+:term:`SVNDIR`, which is usually ``DL_DIR/svn``.
+
+The supported parameters are as follows:
+
+-  *"module":* The name of the svn module to checkout. You must provide
+   this parameter. You can think of this parameter as the top-level
+   directory of the repository data you want.
+
+-  *"path_spec":* A specific directory in which to checkout the
+   specified svn module.
+
+-  *"protocol":* The protocol to use, which defaults to "svn". If
+   "protocol" is set to "svn+ssh", the "ssh" parameter is also used.
+
+-  *"rev":* The revision of the source code to checkout.
+
+-  *"scmdata":* Causes the ".svn" directories to be available during
+   compile-time when set to "keep". By default, these directories are
+   removed.
+
+-  *"ssh":* An optional parameter used when "protocol" is set to
+   "svn+ssh". You can use this parameter to specify the ssh program used
+   by svn.
+
+-  *"transportuser":* When required, sets the username for the
+   transport. By default, this parameter is empty. The transport
+   username is different than the username used in the main URL, which
+   is passed to the subversion command.
+
+Following are three examples using svn: ::
+
+   SRC_URI = "svn://myrepos/proj1;module=vip;protocol=http;rev=667"
+   SRC_URI = "svn://myrepos/proj1;module=opie;protocol=svn+ssh"
+   SRC_URI = "svn://myrepos/proj1;module=trunk;protocol=http;path_spec=${MY_DIR}/proj1"
+
+.. _git-fetcher:
+
+Git Fetcher (``git://``)
+------------------------
+
+This fetcher submodule fetches code from the Git source control system.
+The fetcher works by creating a bare clone of the remote into
+:term:`GITDIR`, which is usually ``DL_DIR/git2``. This
+bare clone is then cloned into the work directory during the unpack
+stage when a specific tree is checked out. This is done using alternates
+and by reference to minimize the amount of duplicate data on the disk
+and make the unpack process fast. The executable used can be set with
+``FETCHCMD_git``.
+
+This fetcher supports the following parameters:
+
+-  *"protocol":* The protocol used to fetch the files. The default is
+   "git" when a hostname is set. If a hostname is not set, the Git
+   protocol is "file". You can also use "http", "https", "ssh" and
+   "rsync".
+
+-  *"nocheckout":* Tells the fetcher to not checkout source code when
+   unpacking when set to "1". Set this option for the URL where there is
+   a custom routine to checkout code. The default is "0".
+
+-  *"rebaseable":* Indicates that the upstream Git repository can be
+   rebased. You should set this parameter to "1" if revisions can become
+   detached from branches. In this case, the source mirror tarball is
+   done per revision, which has a loss of efficiency. Rebasing the
+   upstream Git repository could cause the current revision to disappear
+   from the upstream repository. This option reminds the fetcher to
+   preserve the local cache carefully for future use. The default value
+   for this parameter is "0".
+
+-  *"nobranch":* Tells the fetcher to not check the SHA validation for
+   the branch when set to "1". The default is "0". Set this option for
+   the recipe that refers to the commit that is valid for a tag instead
+   of the branch.
+
+-  *"bareclone":* Tells the fetcher to clone a bare clone into the
+   destination directory without checking out a working tree. Only the
+   raw Git metadata is provided. This parameter implies the "nocheckout"
+   parameter as well.
+
+-  *"branch":* The branch(es) of the Git tree to clone. If unset, this
+   is assumed to be "master". The number of branch parameters much match
+   the number of name parameters.
+
+-  *"rev":* The revision to use for the checkout. The default is
+   "master".
+
+-  *"tag":* Specifies a tag to use for the checkout. To correctly
+   resolve tags, BitBake must access the network. For that reason, tags
+   are often not used. As far as Git is concerned, the "tag" parameter
+   behaves effectively the same as the "rev" parameter.
+
+-  *"subpath":* Limits the checkout to a specific subpath of the tree.
+   By default, the whole tree is checked out.
+
+-  *"destsuffix":* The name of the path in which to place the checkout.
+   By default, the path is ``git/``.
+
+-  *"usehead":* Enables local ``git://`` URLs to use the current branch
+   HEAD as the revision for use with ``AUTOREV``. The "usehead"
+   parameter implies no branch and only works when the transfer protocol
+   is ``file://``.
+
+Here are some example URLs: ::
+
+   SRC_URI = "git://git.oe.handhelds.org/git/vip.git;tag=version-1"
+   SRC_URI = "git://git.oe.handhelds.org/git/vip.git;protocol=http"
+
+.. _gitsm-fetcher:
+
+Git Submodule Fetcher (``gitsm://``)
+------------------------------------
+
+This fetcher submodule inherits from the :ref:`Git
+fetcher<bitbake-user-manual/bitbake-user-manual-fetching:git fetcher
+(\`\`git://\`\`)>` and extends that fetcher's behavior by fetching a
+repository's submodules. :term:`SRC_URI` is passed to the Git fetcher as
+described in the :ref:`bitbake-user-manual/bitbake-user-manual-fetching:git
+fetcher (\`\`git://\`\`)` section.
+
+.. note::
+
+   You must clean a recipe when switching between '``git://``' and
+   '``gitsm://``' URLs.
+
+   The Git Submodules fetcher is not a complete fetcher implementation.
+   The fetcher has known issues where it does not use the normal source
+   mirroring infrastructure properly. Further, the submodule sources it
+   fetches are not visible to the licensing and source archiving
+   infrastructures.
+
+.. _clearcase-fetcher:
+
+ClearCase Fetcher (``ccrc://``)
+-------------------------------
+
+This fetcher submodule fetches code from a
+`ClearCase <http://en.wikipedia.org/wiki/Rational_ClearCase>`__
+repository.
+
+To use this fetcher, make sure your recipe has proper
+:term:`SRC_URI`, :term:`SRCREV`, and
+:term:`PV` settings. Here is an example: ::
+
+   SRC_URI = "ccrc://cc.example.org/ccrc;vob=/example_vob;module=/example_module"
+   SRCREV = "EXAMPLE_CLEARCASE_TAG"
+   PV = "${@d.getVar("SRCREV", False).replace("/", "+")}"
+
+The fetcher uses the ``rcleartool`` or
+``cleartool`` remote client, depending on which one is available.
+
+Following are options for the ``SRC_URI`` statement:
+
+-  *vob*: The name, which must include the prepending "/" character,
+   of the ClearCase VOB. This option is required.
+
+-  *module*: The module, which must include the prepending "/"
+   character, in the selected VOB.
+
+   .. note::
+
+      The module and vob options are combined to create the load rule in the
+      view config spec. As an example, consider the vob and module values from
+      the SRC_URI statement at the start of this section. Combining those values
+      results in the following: ::
+
+         load /example_vob/example_module
+
+-  *proto*: The protocol, which can be either ``http`` or ``https``.
+
+By default, the fetcher creates a configuration specification. If you
+want this specification written to an area other than the default, use
+the ``CCASE_CUSTOM_CONFIG_SPEC`` variable in your recipe to define where
+the specification is written.
+
+.. note::
+
+   the SRCREV loses its functionality if you specify this variable. However,
+   SRCREV is still used to label the archive after a fetch even though it does
+   not define what is fetched.
+
+Here are a couple of other behaviors worth mentioning:
+
+-  When using ``cleartool``, the login of ``cleartool`` is handled by
+   the system. The login require no special steps.
+
+-  In order to use ``rcleartool`` with authenticated users, an
+   "rcleartool login" is necessary before using the fetcher.
+
+.. _perforce-fetcher:
+
+Perforce Fetcher (``p4://``)
+----------------------------
+
+This fetcher submodule fetches code from the
+`Perforce <https://www.perforce.com/>`__ source control system. The
+executable used is specified by ``FETCHCMD_p4``, which defaults to "p4".
+The fetcher's temporary working directory is set by
+:term:`P4DIR`, which defaults to "DL_DIR/p4".
+The fetcher does not make use of a perforce client, instead it
+relies on ``p4 files`` to retrieve a list of
+files and ``p4 print`` to transfer the content
+of those files locally.
+
+To use this fetcher, make sure your recipe has proper
+:term:`SRC_URI`, :term:`SRCREV`, and
+:term:`PV` values. The p4 executable is able to use the
+config file defined by your system's ``P4CONFIG`` environment variable
+in order to define the Perforce server URL and port, username, and
+password if you do not wish to keep those values in a recipe itself. If
+you choose not to use ``P4CONFIG``, or to explicitly set variables that
+``P4CONFIG`` can contain, you can specify the ``P4PORT`` value, which is
+the server's URL and port number, and you can specify a username and
+password directly in your recipe within ``SRC_URI``.
+
+Here is an example that relies on ``P4CONFIG`` to specify the server URL
+and port, username, and password, and fetches the Head Revision: ::
+
+   SRC_URI = "p4://example-depot/main/source/..."
+   SRCREV = "${AUTOREV}"
+   PV = "p4-${SRCPV}"
+   S = "${WORKDIR}/p4"
+
+Here is an example that specifies the server URL and port, username, and
+password, and fetches a Revision based on a Label: ::
+
+   P4PORT = "tcp:p4server.example.net:1666"
+   SRC_URI = "p4://user:passwd@example-depot/main/source/..."
+   SRCREV = "release-1.0"
+   PV = "p4-${SRCPV}"
+   S = "${WORKDIR}/p4"
+
+.. note::
+
+   You should always set S to "${WORKDIR}/p4" in your recipe.
+
+By default, the fetcher strips the depot location from the local file paths. In
+the above example, the content of ``example-depot/main/source/`` will be placed
+in ``${WORKDIR}/p4``.  For situations where preserving parts of the remote depot
+paths locally is desirable, the fetcher supports two parameters:
+
+- *"module":*
+    The top-level depot location or directory to fetch. The value of this
+    parameter can also point to a single file within the depot, in which case
+    the local file path will include the module path.
+- *"remotepath":*
+    When used with the value "``keep``", the fetcher will mirror the full depot
+    paths locally for the specified location, even in combination with the
+    ``module`` parameter.
+
+Here is an example use of the the ``module`` parameter: ::
+
+   SRC_URI = "p4://user:passwd@example-depot/main;module=source/..."
+
+In this case, the content of the top-level directory ``source/`` will be fetched
+to ``${P4DIR}``, including the directory itself.  The top-level directory will
+be accesible at ``${P4DIR}/source/``.
+
+Here is an example use of the the ``remotepath`` parameter: ::
+
+   SRC_URI = "p4://user:passwd@example-depot/main;module=source/...;remotepath=keep"
+
+In this case, the content of the top-level directory ``source/`` will be fetched
+to ``${P4DIR}``, but the complete depot paths will be mirrored locally. The
+top-level directory will be accessible at
+``${P4DIR}/example-depot/main/source/``.
+
+.. _repo-fetcher:
+
+Repo Fetcher (``repo://``)
+--------------------------
+
+This fetcher submodule fetches code from ``google-repo`` source control
+system. The fetcher works by initiating and syncing sources of the
+repository into :term:`REPODIR`, which is usually
+``${DL_DIR}/repo``.
+
+This fetcher supports the following parameters:
+
+-  *"protocol":* Protocol to fetch the repository manifest (default:
+   git).
+
+-  *"branch":* Branch or tag of repository to get (default: master).
+
+-  *"manifest":* Name of the manifest file (default: ``default.xml``).
+
+Here are some example URLs: ::
+
+   SRC_URI = "repo://REPOROOT;protocol=git;branch=some_branch;manifest=my_manifest.xml"
+   SRC_URI = "repo://REPOROOT;protocol=file;branch=some_branch;manifest=my_manifest.xml"
+
+Other Fetchers
+--------------
+
+Fetch submodules also exist for the following:
+
+-  Bazaar (``bzr://``)
+
+-  Mercurial (``hg://``)
+
+-  npm (``npm://``)
+
+-  OSC (``osc://``)
+
+-  Secure FTP (``sftp://``)
+
+-  Secure Shell (``ssh://``)
+
+-  Trees using Git Annex (``gitannex://``)
+
+No documentation currently exists for these lesser used fetcher
+submodules. However, you might find the code helpful and readable.
+
+Auto Revisions
+==============
+
+We need to document ``AUTOREV`` and ``SRCREV_FORMAT`` here.

+ 415 - 0
openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-hello.rst

@@ -0,0 +1,415 @@
+.. SPDX-License-Identifier: CC-BY-2.5
+
+===================
+Hello World Example
+===================
+
+BitBake Hello World
+===================
+
+The simplest example commonly used to demonstrate any new programming
+language or tool is the "`Hello
+World <http://en.wikipedia.org/wiki/Hello_world_program>`__" example.
+This appendix demonstrates, in tutorial form, Hello World within the
+context of BitBake. The tutorial describes how to create a new project
+and the applicable metadata files necessary to allow BitBake to build
+it.
+
+Obtaining BitBake
+=================
+
+See the :ref:`bitbake-user-manual/bitbake-user-manual-hello:obtaining bitbake` section for
+information on how to obtain BitBake. Once you have the source code on
+your machine, the BitBake directory appears as follows: ::
+
+   $ ls -al
+   total 100
+   drwxrwxr-x. 9 wmat wmat  4096 Jan 31 13:44 .
+   drwxrwxr-x. 3 wmat wmat  4096 Feb  4 10:45 ..
+   -rw-rw-r--. 1 wmat wmat   365 Nov 26 04:55 AUTHORS
+   drwxrwxr-x. 2 wmat wmat  4096 Nov 26 04:55 bin
+   drwxrwxr-x. 4 wmat wmat  4096 Jan 31 13:44 build
+   -rw-rw-r--. 1 wmat wmat 16501 Nov 26 04:55 ChangeLog
+   drwxrwxr-x. 2 wmat wmat  4096 Nov 26 04:55 classes
+   drwxrwxr-x. 2 wmat wmat  4096 Nov 26 04:55 conf
+   drwxrwxr-x. 3 wmat wmat  4096 Nov 26 04:55 contrib
+   -rw-rw-r--. 1 wmat wmat 17987 Nov 26 04:55 COPYING
+   drwxrwxr-x. 3 wmat wmat  4096 Nov 26 04:55 doc
+   -rw-rw-r--. 1 wmat wmat    69 Nov 26 04:55 .gitignore
+   -rw-rw-r--. 1 wmat wmat   849 Nov 26 04:55 HEADER
+   drwxrwxr-x. 5 wmat wmat  4096 Jan 31 13:44 lib
+   -rw-rw-r--. 1 wmat wmat   195 Nov 26 04:55 MANIFEST.in
+   -rw-rw-r--. 1 wmat wmat  2887 Nov 26 04:55 TODO
+
+At this point, you should have BitBake cloned to a directory that
+matches the previous listing except for dates and user names.
+
+Setting Up the BitBake Environment
+==================================
+
+First, you need to be sure that you can run BitBake. Set your working
+directory to where your local BitBake files are and run the following
+command: ::
+
+  $ ./bin/bitbake --version
+  BitBake Build Tool Core version 1.23.0, bitbake version 1.23.0
+
+The console output tells you what version
+you are running.
+
+The recommended method to run BitBake is from a directory of your
+choice. To be able to run BitBake from any directory, you need to add
+the executable binary to your binary to your shell's environment
+``PATH`` variable. First, look at your current ``PATH`` variable by
+entering the following: ::
+
+  $ echo $PATH
+
+Next, add the directory location
+for the BitBake binary to the ``PATH``. Here is an example that adds the
+``/home/scott-lenovo/bitbake/bin`` directory to the front of the
+``PATH`` variable: ::
+
+  $ export PATH=/home/scott-lenovo/bitbake/bin:$PATH
+
+You should now be able to enter the ``bitbake`` command from the command
+line while working from any directory.
+
+The Hello World Example
+=======================
+
+The overall goal of this exercise is to build a complete "Hello World"
+example utilizing task and layer concepts. Because this is how modern
+projects such as OpenEmbedded and the Yocto Project utilize BitBake, the
+example provides an excellent starting point for understanding BitBake.
+
+To help you understand how to use BitBake to build targets, the example
+starts with nothing but the ``bitbake`` command, which causes BitBake to
+fail and report problems. The example progresses by adding pieces to the
+build to eventually conclude with a working, minimal "Hello World"
+example.
+
+While every attempt is made to explain what is happening during the
+example, the descriptions cannot cover everything. You can find further
+information throughout this manual. Also, you can actively participate
+in the :oe_lists:`/g/bitbake-devel`
+discussion mailing list about the BitBake build tool.
+
+.. note::
+
+   This example was inspired by and drew heavily from
+   `Mailing List post - The BitBake equivalent of "Hello, World!"
+   <http://www.mail-archive.com/yocto@yoctoproject.org/msg09379.html>`_.
+
+As stated earlier, the goal of this example is to eventually compile
+"Hello World". However, it is unknown what BitBake needs and what you
+have to provide in order to achieve that goal. Recall that BitBake
+utilizes three types of metadata files:
+:ref:`bitbake-user-manual/bitbake-user-manual-intro:configuration files`,
+:ref:`bitbake-user-manual/bitbake-user-manual-intro:classes`, and
+:ref:`bitbake-user-manual/bitbake-user-manual-intro:recipes`.
+But where do they go? How does BitBake find
+them? BitBake's error messaging helps you answer these types of
+questions and helps you better understand exactly what is going on.
+
+Following is the complete "Hello World" example.
+
+#.  **Create a Project Directory:** First, set up a directory for the
+    "Hello World" project. Here is how you can do so in your home
+    directory: ::
+
+      $ mkdir ~/hello
+      $ cd ~/hello
+
+    This is the directory that
+    BitBake will use to do all of its work. You can use this directory
+    to keep all the metafiles needed by BitBake. Having a project
+    directory is a good way to isolate your project.
+
+#.  **Run BitBake:** At this point, you have nothing but a project
+    directory. Run the ``bitbake`` command and see what it does: ::
+
+       $ bitbake
+       The BBPATH variable is not set and bitbake did not
+       find a conf/bblayers.conf file in the expected location.
+       Maybe you accidentally invoked bitbake from the wrong directory?
+       DEBUG: Removed the following variables from the environment:
+       GNOME_DESKTOP_SESSION_ID, XDG_CURRENT_DESKTOP,
+       GNOME_KEYRING_CONTROL, DISPLAY, SSH_AGENT_PID, LANG, no_proxy,
+       XDG_SESSION_PATH, XAUTHORITY, SESSION_MANAGER, SHLVL,
+       MANDATORY_PATH, COMPIZ_CONFIG_PROFILE, WINDOWID, EDITOR,
+       GPG_AGENT_INFO, SSH_AUTH_SOCK, GDMSESSION, GNOME_KEYRING_PID,
+       XDG_SEAT_PATH, XDG_CONFIG_DIRS, LESSOPEN, DBUS_SESSION_BUS_ADDRESS,
+       _, XDG_SESSION_COOKIE, DESKTOP_SESSION, LESSCLOSE, DEFAULTS_PATH,
+       UBUNTU_MENUPROXY, OLDPWD, XDG_DATA_DIRS, COLORTERM, LS_COLORS
+
+    The majority of this output is specific to environment variables that
+    are not directly relevant to BitBake. However, the very first
+    message regarding the ``BBPATH`` variable and the
+    ``conf/bblayers.conf`` file is relevant.
+
+    When you run BitBake, it begins looking for metadata files. The
+    :term:`BBPATH` variable is what tells BitBake where
+    to look for those files. ``BBPATH`` is not set and you need to set
+    it. Without ``BBPATH``, BitBake cannot find any configuration files
+    (``.conf``) or recipe files (``.bb``) at all. BitBake also cannot
+    find the ``bitbake.conf`` file.
+
+#.  **Setting BBPATH:** For this example, you can set ``BBPATH`` in
+    the same manner that you set ``PATH`` earlier in the appendix. You
+    should realize, though, that it is much more flexible to set the
+    ``BBPATH`` variable up in a configuration file for each project.
+
+    From your shell, enter the following commands to set and export the
+    ``BBPATH`` variable: ::
+
+      $ BBPATH="projectdirectory"
+      $ export BBPATH
+
+    Use your actual project directory in the command. BitBake uses that
+    directory to find the metadata it needs for your project.
+
+    .. note::
+
+       When specifying your project directory, do not use the tilde
+       ("~") character as BitBake does not expand that character as the
+       shell would.
+
+#.  **Run BitBake:** Now that you have ``BBPATH`` defined, run the
+    ``bitbake`` command again: ::
+
+       $ bitbake
+       ERROR: Traceback (most recent call last):
+         File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 163, in wrapped
+           return func(fn, *args)
+         File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 173, in parse_config_file
+           return bb.parse.handle(fn, data, include)
+         File "/home/scott-lenovo/bitbake/lib/bb/parse/__init__.py", line 99, in handle
+           return h['handle'](fn, data, include)
+         File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 120, in handle
+           abs_fn = resolve_file(fn, data)
+         File "/home/scott-lenovo/bitbake/lib/bb/parse/__init__.py", line 117, in resolve_file
+           raise IOError("file %s not found in %s" % (fn, bbpath))
+       IOError: file conf/bitbake.conf not found in /home/scott-lenovo/hello
+
+       ERROR: Unable to parse conf/bitbake.conf: file conf/bitbake.conf not found in /home/scott-lenovo/hello
+
+    This sample output shows that BitBake could not find the
+    ``conf/bitbake.conf`` file in the project directory. This file is
+    the first thing BitBake must find in order to build a target. And,
+    since the project directory for this example is empty, you need to
+    provide a ``conf/bitbake.conf`` file.
+
+#.  **Creating conf/bitbake.conf:** The ``conf/bitbake.conf`` includes
+    a number of configuration variables BitBake uses for metadata and
+    recipe files. For this example, you need to create the file in your
+    project directory and define some key BitBake variables. For more
+    information on the ``bitbake.conf`` file, see
+    http://git.openembedded.org/bitbake/tree/conf/bitbake.conf.
+
+    Use the following commands to create the ``conf`` directory in the
+    project directory: ::
+
+      $ mkdir conf
+
+    From within the ``conf`` directory,
+    use some editor to create the ``bitbake.conf`` so that it contains
+    the following: ::
+
+       PN  = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
+
+       TMPDIR  = "${TOPDIR}/tmp"
+       CACHE   = "${TMPDIR}/cache"
+       STAMP   = "${TMPDIR}/${PN}/stamps"
+       T       = "${TMPDIR}/${PN}/work"
+       B       = "${TMPDIR}/${PN}"
+
+    .. note::
+
+       Without a value for PN , the variables STAMP , T , and B , prevent more
+       than one recipe from working. You can fix this by either setting PN to
+       have a value similar to what OpenEmbedded and BitBake use in the default
+       bitbake.conf file (see previous example). Or, by manually updating each
+       recipe to set PN . You will also need to include PN as part of the STAMP
+       , T , and B variable definitions in the local.conf file.
+
+    The ``TMPDIR`` variable establishes a directory that BitBake uses
+    for build output and intermediate files other than the cached
+    information used by the
+    :ref:`bitbake-user-manual/bitbake-user-manual-execution:setscene`
+    process. Here, the ``TMPDIR`` directory is set to ``hello/tmp``.
+
+    .. tip::
+
+       You can always safely delete the tmp directory in order to rebuild a
+       BitBake target. The build process creates the directory for you when you
+       run BitBake.
+
+    For information about each of the other variables defined in this
+    example, check :term:`PN`, :term:`TOPDIR`, :term:`CACHE`, :term:`STAMP`,
+    :term:`T` or :term:`B` to take you to the definitions in the
+    glossary.
+
+#.  **Run BitBake:** After making sure that the ``conf/bitbake.conf`` file
+    exists, you can run the ``bitbake`` command again: ::
+
+       $ bitbake
+       ERROR: Traceback (most recent call last):
+         File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 163, in wrapped
+           return func(fn, *args)
+         File "/home/scott-lenovo/bitbake/lib/bb/cookerdata.py", line 177, in _inherit
+           bb.parse.BBHandler.inherit(bbclass, "configuration INHERITs", 0, data)
+         File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/BBHandler.py", line 92, in inherit
+           include(fn, file, lineno, d, "inherit")
+         File "/home/scott-lenovo/bitbake/lib/bb/parse/parse_py/ConfHandler.py", line 100, in include
+           raise ParseError("Could not %(error_out)s file %(fn)s" % vars(), oldfn, lineno)
+       ParseError: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
+
+       ERROR: Unable to parse base: ParseError in configuration INHERITs: Could not inherit file classes/base.bbclass
+
+    In the sample output,
+    BitBake could not find the ``classes/base.bbclass`` file. You need
+    to create that file next.
+
+#.  **Creating classes/base.bbclass:** BitBake uses class files to
+    provide common code and functionality. The minimally required class
+    for BitBake is the ``classes/base.bbclass`` file. The ``base`` class
+    is implicitly inherited by every recipe. BitBake looks for the class
+    in the ``classes`` directory of the project (i.e ``hello/classes``
+    in this example).
+
+    Create the ``classes`` directory as follows: ::
+
+      $ cd $HOME/hello
+      $ mkdir classes
+
+    Move to the ``classes`` directory and then create the
+    ``base.bbclass`` file by inserting this single line: addtask build
+    The minimal task that BitBake runs is the ``do_build`` task. This is
+    all the example needs in order to build the project. Of course, the
+    ``base.bbclass`` can have much more depending on which build
+    environments BitBake is supporting.
+
+#.  **Run BitBake:** After making sure that the ``classes/base.bbclass``
+    file exists, you can run the ``bitbake`` command again: ::
+
+       $ bitbake
+       Nothing to do. Use 'bitbake world' to build everything, or run 'bitbake --help' for usage information.
+
+    BitBake is finally reporting
+    no errors. However, you can see that it really does not have
+    anything to do. You need to create a recipe that gives BitBake
+    something to do.
+
+#.  **Creating a Layer:** While it is not really necessary for such a
+    small example, it is good practice to create a layer in which to
+    keep your code separate from the general metadata used by BitBake.
+    Thus, this example creates and uses a layer called "mylayer".
+
+    .. note::
+
+       You can find additional information on layers in the
+       ":ref:`bitbake-user-manual/bitbake-user-manual-intro:Layers`" section.
+
+    Minimally, you need a recipe file and a layer configuration file in
+    your layer. The configuration file needs to be in the ``conf``
+    directory inside the layer. Use these commands to set up the layer
+    and the ``conf`` directory: ::
+
+       $ cd $HOME
+       $ mkdir mylayer
+       $ cd mylayer
+       $ mkdir conf
+
+    Move to the ``conf`` directory and create a ``layer.conf`` file that has the
+    following: ::
+
+      BBPATH .= ":${LAYERDIR}"
+      BBFILES += "${LAYERDIR}/\*.bb"
+      BBFILE_COLLECTIONS += "mylayer"
+     `BBFILE_PATTERN_mylayer := "^${LAYERDIR_RE}/"
+
+    For information on these variables, click on :term:`BBFILES`,
+    :term:`LAYERDIR`, :term:`BBFILE_COLLECTIONS` or :term:`BBFILE_PATTERN_mylayer <BBFILE_PATTERN>`
+    to go to the definitions in the glossary.
+
+    You need to create the recipe file next. Inside your layer at the
+    top-level, use an editor and create a recipe file named
+    ``printhello.bb`` that has the following: ::
+
+       DESCRIPTION = "Prints Hello World"
+       PN = 'printhello'
+       PV = '1'
+
+       python do_build() {
+          bb.plain("********************");
+          bb.plain("*                  *");
+          bb.plain("*  Hello, World!   *");
+          bb.plain("*                  *");
+          bb.plain("********************");
+       }
+
+    The recipe file simply provides
+    a description of the recipe, the name, version, and the ``do_build``
+    task, which prints out "Hello World" to the console. For more
+    information on :term:`DESCRIPTION`, :term:`PN` or :term:`PV`
+    follow the links to the glossary.
+
+#. **Run BitBake With a Target:** Now that a BitBake target exists, run
+    the command and provide that target: ::
+
+      $ cd $HOME/hello
+      $ bitbake printhello
+      ERROR: no recipe files to build, check your BBPATH and BBFILES?
+
+      Summary: There was 1 ERROR message shown, returning a non-zero exit code.
+
+    We have created the layer with the recipe and
+    the layer configuration file but it still seems that BitBake cannot
+    find the recipe. BitBake needs a ``conf/bblayers.conf`` that lists
+    the layers for the project. Without this file, BitBake cannot find
+    the recipe.
+
+#. **Creating conf/bblayers.conf:** BitBake uses the
+    ``conf/bblayers.conf`` file to locate layers needed for the project.
+    This file must reside in the ``conf`` directory of the project (i.e.
+    ``hello/conf`` for this example).
+
+    Set your working directory to the ``hello/conf`` directory and then
+    create the ``bblayers.conf`` file so that it contains the following: ::
+
+       BBLAYERS ?= " \
+           /home/<you>/mylayer \
+       "
+
+    You need to provide your own information for ``you`` in the file.
+
+#. **Run BitBake With a Target:** Now that you have supplied the
+    ``bblayers.conf`` file, run the ``bitbake`` command and provide the
+    target: ::
+
+       $ bitbake printhello
+       Parsing recipes: 100% |##################################################################################|
+       Time: 00:00:00
+       Parsing of 1 .bb files complete (0 cached, 1 parsed). 1 targets, 0 skipped, 0 masked, 0 errors.
+       NOTE: Resolving any missing task queue dependencies
+       NOTE: Preparing RunQueue
+       NOTE: Executing RunQueue Tasks
+       ********************
+       *                  *
+       *  Hello, World!   *
+       *                  *
+       ********************
+       NOTE: Tasks Summary: Attempted 1 tasks of which 0 didn't need to be rerun and all succeeded.
+
+    .. note::
+
+       After the first execution, re-running bitbake printhello again will not
+       result in a BitBake run that prints the same console output. The reason
+       for this is that the first time the printhello.bb recipe's do_build task
+       executes successfully, BitBake writes a stamp file for the task. Thus,
+       the next time you attempt to run the task using that same bitbake
+       command, BitBake notices the stamp and therefore determines that the task
+       does not need to be re-run. If you delete the tmp directory or run
+       bitbake -c clean printhello and then re-run the build, the "Hello,
+       World!" message will be printed again.

+ 651 - 0
openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-intro.rst

@@ -0,0 +1,651 @@
+.. SPDX-License-Identifier: CC-BY-2.5
+
+========
+Overview
+========
+
+|
+
+Welcome to the BitBake User Manual. This manual provides information on
+the BitBake tool. The information attempts to be as independent as
+possible regarding systems that use BitBake, such as OpenEmbedded and
+the Yocto Project. In some cases, scenarios or examples within the
+context of a build system are used in the manual to help with
+understanding. For these cases, the manual clearly states the context.
+
+.. _intro:
+
+Introduction
+============
+
+Fundamentally, BitBake is a generic task execution engine that allows
+shell and Python tasks to be run efficiently and in parallel while
+working within complex inter-task dependency constraints. One of
+BitBake's main users, OpenEmbedded, takes this core and builds embedded
+Linux software stacks using a task-oriented approach.
+
+Conceptually, BitBake is similar to GNU Make in some regards but has
+significant differences:
+
+-  BitBake executes tasks according to provided metadata that builds up
+   the tasks. Metadata is stored in recipe (``.bb``) and related recipe
+   "append" (``.bbappend``) files, configuration (``.conf``) and
+   underlying include (``.inc``) files, and in class (``.bbclass``)
+   files. The metadata provides BitBake with instructions on what tasks
+   to run and the dependencies between those tasks.
+
+-  BitBake includes a fetcher library for obtaining source code from
+   various places such as local files, source control systems, or
+   websites.
+
+-  The instructions for each unit to be built (e.g. a piece of software)
+   are known as "recipe" files and contain all the information about the
+   unit (dependencies, source file locations, checksums, description and
+   so on).
+
+-  BitBake includes a client/server abstraction and can be used from a
+   command line or used as a service over XML-RPC and has several
+   different user interfaces.
+
+History and Goals
+=================
+
+BitBake was originally a part of the OpenEmbedded project. It was
+inspired by the Portage package management system used by the Gentoo
+Linux distribution. On December 7, 2004, OpenEmbedded project team
+member Chris Larson split the project into two distinct pieces:
+
+-  BitBake, a generic task executor
+
+-  OpenEmbedded, a metadata set utilized by BitBake
+
+Today, BitBake is the primary basis of the
+`OpenEmbedded <http://www.openembedded.org/>`__ project, which is being
+used to build and maintain Linux distributions such as the `Angstrom
+Distribution <http://www.angstrom-distribution.org/>`__, and which is
+also being used as the build tool for Linux projects such as the `Yocto
+Project <http://www.yoctoproject.org>`__.
+
+Prior to BitBake, no other build tool adequately met the needs of an
+aspiring embedded Linux distribution. All of the build systems used by
+traditional desktop Linux distributions lacked important functionality,
+and none of the ad hoc Buildroot-based systems, prevalent in the
+embedded space, were scalable or maintainable.
+
+Some important original goals for BitBake were:
+
+-  Handle cross-compilation.
+
+-  Handle inter-package dependencies (build time on target architecture,
+   build time on native architecture, and runtime).
+
+-  Support running any number of tasks within a given package,
+   including, but not limited to, fetching upstream sources, unpacking
+   them, patching them, configuring them, and so forth.
+
+-  Be Linux distribution agnostic for both build and target systems.
+
+-  Be architecture agnostic.
+
+-  Support multiple build and target operating systems (e.g. Cygwin, the
+   BSDs, and so forth).
+
+-  Be self-contained, rather than tightly integrated into the build
+   machine's root filesystem.
+
+-  Handle conditional metadata on the target architecture, operating
+   system, distribution, and machine.
+
+-  Be easy to use the tools to supply local metadata and packages
+   against which to operate.
+
+-  Be easy to use BitBake to collaborate between multiple projects for
+   their builds.
+
+-  Provide an inheritance mechanism to share common metadata between
+   many packages.
+
+Over time it became apparent that some further requirements were
+necessary:
+
+-  Handle variants of a base recipe (e.g. native, sdk, and multilib).
+
+-  Split metadata into layers and allow layers to enhance or override
+   other layers.
+
+-  Allow representation of a given set of input variables to a task as a
+   checksum. Based on that checksum, allow acceleration of builds with
+   prebuilt components.
+
+BitBake satisfies all the original requirements and many more with
+extensions being made to the basic functionality to reflect the
+additional requirements. Flexibility and power have always been the
+priorities. BitBake is highly extensible and supports embedded Python
+code and execution of any arbitrary tasks.
+
+.. _Concepts:
+
+Concepts
+========
+
+BitBake is a program written in the Python language. At the highest
+level, BitBake interprets metadata, decides what tasks are required to
+run, and executes those tasks. Similar to GNU Make, BitBake controls how
+software is built. GNU Make achieves its control through "makefiles",
+while BitBake uses "recipes".
+
+BitBake extends the capabilities of a simple tool like GNU Make by
+allowing for the definition of much more complex tasks, such as
+assembling entire embedded Linux distributions.
+
+The remainder of this section introduces several concepts that should be
+understood in order to better leverage the power of BitBake.
+
+Recipes
+-------
+
+BitBake Recipes, which are denoted by the file extension ``.bb``, are
+the most basic metadata files. These recipe files provide BitBake with
+the following:
+
+-  Descriptive information about the package (author, homepage, license,
+   and so on)
+
+-  The version of the recipe
+
+-  Existing dependencies (both build and runtime dependencies)
+
+-  Where the source code resides and how to fetch it
+
+-  Whether the source code requires any patches, where to find them, and
+   how to apply them
+
+-  How to configure and compile the source code
+
+-  How to assemble the generated artifacts into one or more installable
+   packages
+
+-  Where on the target machine to install the package or packages
+   created
+
+Within the context of BitBake, or any project utilizing BitBake as its
+build system, files with the ``.bb`` extension are referred to as
+recipes.
+
+.. note::
+
+   The term "package" is also commonly used to describe recipes.
+   However, since the same word is used to describe packaged output from
+   a project, it is best to maintain a single descriptive term -
+   "recipes". Put another way, a single "recipe" file is quite capable
+   of generating a number of related but separately installable
+   "packages". In fact, that ability is fairly common.
+
+Configuration Files
+-------------------
+
+Configuration files, which are denoted by the ``.conf`` extension,
+define various configuration variables that govern the project's build
+process. These files fall into several areas that define machine
+configuration, distribution configuration, possible compiler tuning,
+general common configuration, and user configuration. The main
+configuration file is the sample ``bitbake.conf`` file, which is located
+within the BitBake source tree ``conf`` directory.
+
+Classes
+-------
+
+Class files, which are denoted by the ``.bbclass`` extension, contain
+information that is useful to share between metadata files. The BitBake
+source tree currently comes with one class metadata file called
+``base.bbclass``. You can find this file in the ``classes`` directory.
+The ``base.bbclass`` class files is special since it is always included
+automatically for all recipes and classes. This class contains
+definitions for standard basic tasks such as fetching, unpacking,
+configuring (empty by default), compiling (runs any Makefile present),
+installing (empty by default) and packaging (empty by default). These
+tasks are often overridden or extended by other classes added during the
+project development process.
+
+Layers
+------
+
+Layers allow you to isolate different types of customizations from each
+other. While you might find it tempting to keep everything in one layer
+when working on a single project, the more modular your metadata, the
+easier it is to cope with future changes.
+
+To illustrate how you can use layers to keep things modular, consider
+customizations you might make to support a specific target machine.
+These types of customizations typically reside in a special layer,
+rather than a general layer, called a Board Support Package (BSP) layer.
+Furthermore, the machine customizations should be isolated from recipes
+and metadata that support a new GUI environment, for example. This
+situation gives you a couple of layers: one for the machine
+configurations and one for the GUI environment. It is important to
+understand, however, that the BSP layer can still make machine-specific
+additions to recipes within the GUI environment layer without polluting
+the GUI layer itself with those machine-specific changes. You can
+accomplish this through a recipe that is a BitBake append
+(``.bbappend``) file.
+
+.. _append-bbappend-files:
+
+Append Files
+------------
+
+Append files, which are files that have the ``.bbappend`` file
+extension, extend or override information in an existing recipe file.
+
+BitBake expects every append file to have a corresponding recipe file.
+Furthermore, the append file and corresponding recipe file must use the
+same root filename. The filenames can differ only in the file type
+suffix used (e.g. ``formfactor_0.0.bb`` and
+``formfactor_0.0.bbappend``).
+
+Information in append files extends or overrides the information in the
+underlying, similarly-named recipe files.
+
+When you name an append file, you can use the "``%``" wildcard character
+to allow for matching recipe names. For example, suppose you have an
+append file named as follows: ::
+
+  busybox_1.21.%.bbappend
+
+That append file
+would match any ``busybox_1.21.``\ x\ ``.bb`` version of the recipe. So,
+the append file would match the following recipe names: ::
+
+  busybox_1.21.1.bb
+  busybox_1.21.2.bb
+  busybox_1.21.3.bb
+
+.. note::
+
+   The use of the " % " character is limited in that it only works directly in
+   front of the .bbappend portion of the append file's name. You cannot use the
+   wildcard character in any other location of the name.
+
+If the ``busybox`` recipe was updated to ``busybox_1.3.0.bb``, the
+append name would not match. However, if you named the append file
+``busybox_1.%.bbappend``, then you would have a match.
+
+In the most general case, you could name the append file something as
+simple as ``busybox_%.bbappend`` to be entirely version independent.
+
+Obtaining BitBake
+=================
+
+You can obtain BitBake several different ways:
+
+-  **Cloning BitBake:** Using Git to clone the BitBake source code
+   repository is the recommended method for obtaining BitBake. Cloning
+   the repository makes it easy to get bug fixes and have access to
+   stable branches and the master branch. Once you have cloned BitBake,
+   you should use the latest stable branch for development since the
+   master branch is for BitBake development and might contain less
+   stable changes.
+
+   You usually need a version of BitBake that matches the metadata you
+   are using. The metadata is generally backwards compatible but not
+   forward compatible.
+
+   Here is an example that clones the BitBake repository: ::
+
+     $ git clone git://git.openembedded.org/bitbake
+
+   This command clones the BitBake
+   Git repository into a directory called ``bitbake``. Alternatively,
+   you can designate a directory after the ``git clone`` command if you
+   want to call the new directory something other than ``bitbake``. Here
+   is an example that names the directory ``bbdev``: ::
+
+     $ git clone git://git.openembedded.org/bitbake bbdev
+
+-  **Installation using your Distribution Package Management System:**
+   This method is not recommended because the BitBake version that is
+   provided by your distribution, in most cases, is several releases
+   behind a snapshot of the BitBake repository.
+
+-  **Taking a snapshot of BitBake:** Downloading a snapshot of BitBake
+   from the source code repository gives you access to a known branch or
+   release of BitBake.
+
+      .. note::
+
+         Cloning the Git repository, as described earlier, is the preferred
+         method for getting BitBake. Cloning the repository makes it easier
+         to update as patches are added to the stable branches.
+
+   The following example downloads a snapshot of BitBake version 1.17.0: ::
+
+     $ wget http://git.openembedded.org/bitbake/snapshot/bitbake-1.17.0.tar.gz
+     $ tar zxpvf bitbake-1.17.0.tar.gz
+
+   After extraction of the tarball using
+   the tar utility, you have a directory entitled ``bitbake-1.17.0``.
+
+-  **Using the BitBake that Comes With Your Build Checkout:** A final
+   possibility for getting a copy of BitBake is that it already comes
+   with your checkout of a larger BitBake-based build system, such as
+   Poky. Rather than manually checking out individual layers and gluing
+   them together yourself, you can check out an entire build system. The
+   checkout will already include a version of BitBake that has been
+   thoroughly tested for compatibility with the other components. For
+   information on how to check out a particular BitBake-based build
+   system, consult that build system's supporting documentation.
+
+.. _bitbake-user-manual-command:
+
+The BitBake Command
+===================
+
+The ``bitbake`` command is the primary interface to the BitBake tool.
+This section presents the BitBake command syntax and provides several
+execution examples.
+
+Usage and syntax
+----------------
+
+Following is the usage and syntax for BitBake: ::
+
+   $ bitbake -h
+   Usage: bitbake [options] [recipename/target recipe:do_task ...]
+
+       Executes the specified task (default is 'build') for a given set of target recipes (.bb files).
+       It is assumed there is a conf/bblayers.conf available in cwd or in BBPATH which
+       will provide the layer, BBFILES and other configuration information.
+
+   Options:
+     --version             show program's version number and exit
+     -h, --help            show this help message and exit
+     -b BUILDFILE, --buildfile=BUILDFILE
+                           Execute tasks from a specific .bb recipe directly.
+                           WARNING: Does not handle any dependencies from other
+                           recipes.
+     -k, --continue        Continue as much as possible after an error. While the
+                           target that failed and anything depending on it cannot
+                           be built, as much as possible will be built before
+                           stopping.
+     -f, --force           Force the specified targets/task to run (invalidating
+                           any existing stamp file).
+     -c CMD, --cmd=CMD     Specify the task to execute. The exact options
+                           available depend on the metadata. Some examples might
+                           be 'compile' or 'populate_sysroot' or 'listtasks' may
+                           give a list of the tasks available.
+     -C INVALIDATE_STAMP, --clear-stamp=INVALIDATE_STAMP
+                           Invalidate the stamp for the specified task such as
+                           'compile' and then run the default task for the
+                           specified target(s).
+     -r PREFILE, --read=PREFILE
+                           Read the specified file before bitbake.conf.
+     -R POSTFILE, --postread=POSTFILE
+                           Read the specified file after bitbake.conf.
+     -v, --verbose         Enable tracing of shell tasks (with 'set -x'). Also
+                           print bb.note(...) messages to stdout (in addition to
+                           writing them to ${T}/log.do_&lt;task&gt;).
+     -D, --debug           Increase the debug level. You can specify this more
+                           than once. -D sets the debug level to 1, where only
+                           bb.debug(1, ...) messages are printed to stdout; -DD
+                           sets the debug level to 2, where both bb.debug(1, ...)
+                           and bb.debug(2, ...) messages are printed; etc.
+                           Without -D, no debug messages are printed. Note that
+                           -D only affects output to stdout. All debug messages
+                           are written to ${T}/log.do_taskname, regardless of the
+                           debug level.
+     -q, --quiet           Output less log message data to the terminal. You can
+                           specify this more than once.
+     -n, --dry-run         Don't execute, just go through the motions.
+     -S SIGNATURE_HANDLER, --dump-signatures=SIGNATURE_HANDLER
+                           Dump out the signature construction information, with
+                           no task execution. The SIGNATURE_HANDLER parameter is
+                           passed to the handler. Two common values are none and
+                           printdiff but the handler may define more/less. none
+                           means only dump the signature, printdiff means compare
+                           the dumped signature with the cached one.
+     -p, --parse-only      Quit after parsing the BB recipes.
+     -s, --show-versions   Show current and preferred versions of all recipes.
+     -e, --environment     Show the global or per-recipe environment complete
+                           with information about where variables were
+                           set/changed.
+     -g, --graphviz        Save dependency tree information for the specified
+                           targets in the dot syntax.
+     -I EXTRA_ASSUME_PROVIDED, --ignore-deps=EXTRA_ASSUME_PROVIDED
+                           Assume these dependencies don't exist and are already
+                           provided (equivalent to ASSUME_PROVIDED). Useful to
+                           make dependency graphs more appealing
+     -l DEBUG_DOMAINS, --log-domains=DEBUG_DOMAINS
+                           Show debug logging for the specified logging domains
+     -P, --profile         Profile the command and save reports.
+     -u UI, --ui=UI        The user interface to use (knotty, ncurses or taskexp
+                           - default knotty).
+     --token=XMLRPCTOKEN   Specify the connection token to be used when
+                           connecting to a remote server.
+     --revisions-changed   Set the exit code depending on whether upstream
+                           floating revisions have changed or not.
+     --server-only         Run bitbake without a UI, only starting a server
+                           (cooker) process.
+     -B BIND, --bind=BIND  The name/address for the bitbake xmlrpc server to bind
+                           to.
+     -T SERVER_TIMEOUT, --idle-timeout=SERVER_TIMEOUT
+                           Set timeout to unload bitbake server due to
+                           inactivity, set to -1 means no unload, default:
+                           Environment variable BB_SERVER_TIMEOUT.
+     --no-setscene         Do not run any setscene tasks. sstate will be ignored
+                           and everything needed, built.
+     --setscene-only       Only run setscene tasks, don't run any real tasks.
+     --remote-server=REMOTE_SERVER
+                           Connect to the specified server.
+     -m, --kill-server     Terminate any running bitbake server.
+     --observe-only        Connect to a server as an observing-only client.
+     --status-only         Check the status of the remote bitbake server.
+     -w WRITEEVENTLOG, --write-log=WRITEEVENTLOG
+                           Writes the event log of the build to a bitbake event
+                           json file. Use '' (empty string) to assign the name
+                           automatically.
+     --runall=RUNALL       Run the specified task for any recipe in the taskgraph
+                           of the specified target (even if it wouldn't otherwise
+                           have run).
+     --runonly=RUNONLY     Run only the specified task within the taskgraph of
+                           the specified targets (and any task dependencies those
+                           tasks may have).
+
+.. _bitbake-examples:
+
+Examples
+--------
+
+This section presents some examples showing how to use BitBake.
+
+.. _example-executing-a-task-against-a-single-recipe:
+
+Executing a Task Against a Single Recipe
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Executing tasks for a single recipe file is relatively simple. You
+specify the file in question, and BitBake parses it and executes the
+specified task. If you do not specify a task, BitBake executes the
+default task, which is "build". BitBake obeys inter-task dependencies
+when doing so.
+
+The following command runs the build task, which is the default task, on
+the ``foo_1.0.bb`` recipe file: ::
+
+  $ bitbake -b foo_1.0.bb
+
+The following command runs the clean task on the ``foo.bb`` recipe file: ::
+
+  $ bitbake -b foo.bb -c clean
+
+.. note::
+
+   The "-b" option explicitly does not handle recipe dependencies. Other
+   than for debugging purposes, it is instead recommended that you use
+   the syntax presented in the next section.
+
+Executing Tasks Against a Set of Recipe Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are a number of additional complexities introduced when one wants
+to manage multiple ``.bb`` files. Clearly there needs to be a way to
+tell BitBake what files are available and, of those, which you want to
+execute. There also needs to be a way for each recipe to express its
+dependencies, both for build-time and runtime. There must be a way for
+you to express recipe preferences when multiple recipes provide the same
+functionality, or when there are multiple versions of a recipe.
+
+The ``bitbake`` command, when not using "--buildfile" or "-b" only
+accepts a "PROVIDES". You cannot provide anything else. By default, a
+recipe file generally "PROVIDES" its "packagename" as shown in the
+following example: ::
+
+  $ bitbake foo
+
+This next example "PROVIDES" the
+package name and also uses the "-c" option to tell BitBake to just
+execute the ``do_clean`` task: ::
+
+  $ bitbake -c clean foo
+
+Executing a List of Task and Recipe Combinations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The BitBake command line supports specifying different tasks for
+individual targets when you specify multiple targets. For example,
+suppose you had two targets (or recipes) ``myfirstrecipe`` and
+``mysecondrecipe`` and you needed BitBake to run ``taskA`` for the first
+recipe and ``taskB`` for the second recipe: ::
+
+  $ bitbake myfirstrecipe:do_taskA mysecondrecipe:do_taskB
+
+Generating Dependency Graphs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+BitBake is able to generate dependency graphs using the ``dot`` syntax.
+You can convert these graphs into images using the ``dot`` tool from
+`Graphviz <http://www.graphviz.org>`__.
+
+When you generate a dependency graph, BitBake writes two files to the
+current working directory:
+
+-  ``task-depends.dot``: Shows dependencies between tasks. These
+   dependencies match BitBake's internal task execution list.
+
+-  ``pn-buildlist``: Shows a simple list of targets that are to be
+   built.
+
+To stop depending on common depends, use the "-I" depend option and
+BitBake omits them from the graph. Leaving this information out can
+produce more readable graphs. This way, you can remove from the graph
+``DEPENDS`` from inherited classes such as ``base.bbclass``.
+
+Here are two examples that create dependency graphs. The second example
+omits depends common in OpenEmbedded from the graph: ::
+
+  $ bitbake -g foo
+
+  $ bitbake -g -I virtual/kernel -I eglibc foo
+
+Executing a Multiple Configuration Build
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+BitBake is able to build multiple images or packages using a single
+command where the different targets require different configurations
+(multiple configuration builds). Each target, in this scenario, is
+referred to as a "multiconfig".
+
+To accomplish a multiple configuration build, you must define each
+target's configuration separately using a parallel configuration file in
+the build directory. The location for these multiconfig configuration
+files is specific. They must reside in the current build directory in a
+sub-directory of ``conf`` named ``multiconfig``. Following is an example
+for two separate targets:
+
+.. image:: figures/bb_multiconfig_files.png
+   :align: center
+
+The reason for this required file hierarchy is because the ``BBPATH``
+variable is not constructed until the layers are parsed. Consequently,
+using the configuration file as a pre-configuration file is not possible
+unless it is located in the current working directory.
+
+Minimally, each configuration file must define the machine and the
+temporary directory BitBake uses for the build. Suggested practice
+dictates that you do not overlap the temporary directories used during
+the builds.
+
+Aside from separate configuration files for each target, you must also
+enable BitBake to perform multiple configuration builds. Enabling is
+accomplished by setting the
+:term:`BBMULTICONFIG` variable in the
+``local.conf`` configuration file. As an example, suppose you had
+configuration files for ``target1`` and ``target2`` defined in the build
+directory. The following statement in the ``local.conf`` file both
+enables BitBake to perform multiple configuration builds and specifies
+the two extra multiconfigs: ::
+
+  BBMULTICONFIG = "target1 target2"
+
+Once the target configuration files are in place and BitBake has been
+enabled to perform multiple configuration builds, use the following
+command form to start the builds: ::
+
+  $ bitbake [mc:multiconfigname:]target [[[mc:multiconfigname:]target] ... ]
+
+Here is an example for two extra multiconfigs: ``target1`` and ``target2``: ::
+
+  $ bitbake mc::target mc:target1:target mc:target2:target
+
+.. _bb-enabling-multiple-configuration-build-dependencies:
+
+Enabling Multiple Configuration Build Dependencies
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Sometimes dependencies can exist between targets (multiconfigs) in a
+multiple configuration build. For example, suppose that in order to
+build an image for a particular architecture, the root filesystem of
+another build for a different architecture needs to exist. In other
+words, the image for the first multiconfig depends on the root
+filesystem of the second multiconfig. This dependency is essentially
+that the task in the recipe that builds one multiconfig is dependent on
+the completion of the task in the recipe that builds another
+multiconfig.
+
+To enable dependencies in a multiple configuration build, you must
+declare the dependencies in the recipe using the following statement
+form: ::
+
+  task_or_package[mcdepends] = "mc:from_multiconfig:to_multiconfig:recipe_name:task_on_which_to_depend"
+
+To better show how to use this statement, consider an example with two
+multiconfigs: ``target1`` and ``target2``: ::
+
+  image_task[mcdepends] = "mc:target1:target2:image2:rootfs_task"
+
+In this example, the
+``from_multiconfig`` is "target1" and the ``to_multiconfig`` is "target2". The
+task on which the image whose recipe contains image_task depends on the
+completion of the rootfs_task used to build out image2, which is
+associated with the "target2" multiconfig.
+
+Once you set up this dependency, you can build the "target1" multiconfig
+using a BitBake command as follows: ::
+
+  $ bitbake mc:target1:image1
+
+This command executes all the tasks needed to create ``image1`` for the "target1"
+multiconfig. Because of the dependency, BitBake also executes through
+the ``rootfs_task`` for the "target2" multiconfig build.
+
+Having a recipe depend on the root filesystem of another build might not
+seem that useful. Consider this change to the statement in the image1
+recipe: ::
+
+  image_task[mcdepends] = "mc:target1:target2:image2:image_task"
+
+In this case, BitBake must create ``image2`` for the "target2" build since
+the "target1" build depends on it.
+
+Because "target1" and "target2" are enabled for multiple configuration
+builds and have separate configuration files, BitBake places the
+artifacts for each build in the respective temporary build directories.

+ 1969 - 0
openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-metadata.rst

@@ -0,0 +1,1969 @@
+.. SPDX-License-Identifier: CC-BY-2.5
+
+====================
+Syntax and Operators
+====================
+
+|
+
+BitBake files have their own syntax. The syntax has similarities to
+several other languages but also has some unique features. This section
+describes the available syntax and operators as well as provides
+examples.
+
+Basic Syntax
+============
+
+This section provides some basic syntax examples.
+
+Basic Variable Setting
+----------------------
+
+The following example sets ``VARIABLE`` to "value". This assignment
+occurs immediately as the statement is parsed. It is a "hard"
+assignment. ::
+
+   VARIABLE = "value"
+
+As expected, if you include leading or
+trailing spaces as part of an assignment, the spaces are retained: ::
+
+   VARIABLE = " value"
+   VARIABLE = "value "
+
+Setting ``VARIABLE`` to "" sets
+it to an empty string, while setting the variable to " " sets it to a
+blank space (i.e. these are not the same values). ::
+
+   VARIABLE = ""
+   VARIABLE = " "
+
+You can use single quotes instead of double quotes when setting a
+variable's value. Doing so allows you to use values that contain the
+double quote character: ::
+
+   VARIABLE = 'I have a " in my value'
+
+.. note::
+
+   Unlike in Bourne shells, single quotes work identically to double
+   quotes in all other ways. They do not suppress variable expansions.
+
+Modifying Existing Variables
+----------------------------
+
+Sometimes you need to modify existing variables. Following are some
+cases where you might find you want to modify an existing variable:
+
+-  Customize a recipe that uses the variable.
+
+-  Change a variable's default value used in a ``*.bbclass`` file.
+
+-  Change the variable in a ``*.bbappend`` file to override the variable
+   in the original recipe.
+
+-  Change the variable in a configuration file so that the value
+   overrides an existing configuration.
+
+Changing a variable value can sometimes depend on how the value was
+originally assigned and also on the desired intent of the change. In
+particular, when you append a value to a variable that has a default
+value, the resulting value might not be what you expect. In this case,
+the value you provide might replace the value rather than append to the
+default value.
+
+If after you have changed a variable's value and something unexplained
+occurs, you can use BitBake to check the actual value of the suspect
+variable. You can make these checks for both configuration and recipe
+level changes:
+
+-  For configuration changes, use the following: ::
+
+      $ bitbake -e
+
+   This
+   command displays variable values after the configuration files (i.e.
+   ``local.conf``, ``bblayers.conf``, ``bitbake.conf`` and so forth)
+   have been parsed.
+
+   .. note::
+
+      Variables that are exported to the environment are preceded by the
+      string "export" in the command's output.
+
+-  For recipe changes, use the following: ::
+
+      $ bitbake recipe -e \| grep VARIABLE="
+
+   This command checks to see if the variable actually makes
+   it into a specific recipe.
+
+Line Joining
+------------
+
+Outside of :ref:`functions <bitbake-user-manual/bitbake-user-manual-metadata:functions>`,
+BitBake joins any line ending in
+a backslash character ("\") with the following line before parsing
+statements. The most common use for the "\" character is to split
+variable assignments over multiple lines, as in the following example: ::
+
+   FOO = "bar \
+          baz \
+          qaz"
+
+Both the "\" character and the newline
+character that follow it are removed when joining lines. Thus, no
+newline characters end up in the value of ``FOO``.
+
+Consider this additional example where the two assignments both assign
+"barbaz" to ``FOO``: ::
+
+   FOO = "barbaz"
+   FOO = "bar\
+   baz"
+
+.. note::
+
+   BitBake does not interpret escape sequences like "\n" in variable
+   values. For these to have an effect, the value must be passed to some
+   utility that interprets escape sequences, such as
+   ``printf`` or ``echo -n``.
+
+Variable Expansion
+------------------
+
+Variables can reference the contents of other variables using a syntax
+that is similar to variable expansion in Bourne shells. The following
+assignments result in A containing "aval" and B evaluating to
+"preavalpost". ::
+
+   A = "aval"
+   B = "pre${A}post"
+
+.. note::
+
+   Unlike in Bourne shells, the curly braces are mandatory: Only ``${FOO}`` and not
+   ``$FOO`` is recognized as an expansion of ``FOO``.
+
+The "=" operator does not immediately expand variable references in the
+right-hand side. Instead, expansion is deferred until the variable
+assigned to is actually used. The result depends on the current values
+of the referenced variables. The following example should clarify this
+behavior: ::
+
+   A = "${B} baz"
+   B = "${C} bar"
+   C = "foo"
+   *At this point, ${A} equals "foo bar baz"*
+   C = "qux"
+   *At this point, ${A} equals "qux bar baz"*
+   B = "norf"
+   *At this point, ${A} equals "norf baz"\*
+
+Contrast this behavior with the
+:ref:`bitbake-user-manual/bitbake-user-manual-metadata:immediate variable
+expansion (:=)` operator.
+
+If the variable expansion syntax is used on a variable that does not
+exist, the string is kept as is. For example, given the following
+assignment, ``BAR`` expands to the literal string "${FOO}" as long as
+``FOO`` does not exist. ::
+
+   BAR = "${FOO}"
+
+Setting a default value (?=)
+----------------------------
+
+You can use the "?=" operator to achieve a "softer" assignment for a
+variable. This type of assignment allows you to define a variable if it
+is undefined when the statement is parsed, but to leave the value alone
+if the variable has a value. Here is an example: ::
+
+   A ?= "aval"
+
+If ``A`` is
+set at the time this statement is parsed, the variable retains its
+value. However, if ``A`` is not set, the variable is set to "aval".
+
+.. note::
+
+   This assignment is immediate. Consequently, if multiple "?="
+   assignments to a single variable exist, the first of those ends up
+   getting used.
+
+Setting a weak default value (??=)
+----------------------------------
+
+It is possible to use a "weaker" assignment than in the previous section
+by using the "??=" operator. This assignment behaves identical to "?="
+except that the assignment is made at the end of the parsing process
+rather than immediately. Consequently, when multiple "??=" assignments
+exist, the last one is used. Also, any "=" or "?=" assignment will
+override the value set with "??=". Here is an example: ::
+
+   A ??= "somevalue"
+   A ??= "someothervalue"
+
+If ``A`` is set before the above statements are
+parsed, the variable retains its value. If ``A`` is not set, the
+variable is set to "someothervalue".
+
+Again, this assignment is a "lazy" or "weak" assignment because it does
+not occur until the end of the parsing process.
+
+Immediate variable expansion (:=)
+---------------------------------
+
+The ":=" operator results in a variable's contents being expanded
+immediately, rather than when the variable is actually used: ::
+
+   T = "123"
+   A := "test ${T}"
+   T = "456"
+   B := "${T} ${C}"
+   C = "cval"
+   C := "${C}append"
+
+In this example, ``A`` contains "test 123", even though the final value
+of ``T`` is "456". The variable ``B`` will end up containing "456
+cvalappend". This is because references to undefined variables are
+preserved as is during (immediate)expansion. This is in contrast to GNU
+Make, where undefined variables expand to nothing. The variable ``C``
+contains "cvalappend" since ``${C}`` immediately expands to "cval".
+
+.. _appending-and-prepending:
+
+Appending (+=) and prepending (=+) With Spaces
+----------------------------------------------
+
+Appending and prepending values is common and can be accomplished using
+the "+=" and "=+" operators. These operators insert a space between the
+current value and prepended or appended value.
+
+These operators take immediate effect during parsing. Here are some
+examples: ::
+
+   B = "bval"
+   B += "additionaldata"
+   C = "cval"
+   C =+ "test"
+
+The variable ``B`` contains "bval additionaldata" and ``C`` contains "test
+cval".
+
+.. _appending-and-prepending-without-spaces:
+
+Appending (.=) and Prepending (=.) Without Spaces
+-------------------------------------------------
+
+If you want to append or prepend values without an inserted space, use
+the ".=" and "=." operators.
+
+These operators take immediate effect during parsing. Here are some
+examples: ::
+
+   B = "bval"
+   B .= "additionaldata"
+   C = "cval"
+   C =. "test"
+
+The variable ``B`` contains "bvaladditionaldata" and ``C`` contains
+"testcval".
+
+Appending and Prepending (Override Style Syntax)
+------------------------------------------------
+
+You can also append and prepend a variable's value using an override
+style syntax. When you use this syntax, no spaces are inserted.
+
+These operators differ from the ":=", ".=", "=.", "+=", and "=+"
+operators in that their effects are applied at variable expansion time
+rather than being immediately applied. Here are some examples: ::
+
+   B = "bval"
+   B_append = " additional data"
+   C = "cval"
+   C_prepend = "additional data "
+   D = "dval"
+   D_append = "additional data"
+
+The variable ``B``
+becomes "bval additional data" and ``C`` becomes "additional data cval".
+The variable ``D`` becomes "dvaladditional data".
+
+.. note::
+
+   You must control all spacing when you use the override syntax.
+
+It is also possible to append and prepend to shell functions and
+BitBake-style Python functions. See the ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:shell functions`" and ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:bitbake-style python functions`"
+sections for examples.
+
+.. _removing-override-style-syntax:
+
+Removal (Override Style Syntax)
+-------------------------------
+
+You can remove values from lists using the removal override style
+syntax. Specifying a value for removal causes all occurrences of that
+value to be removed from the variable.
+
+When you use this syntax, BitBake expects one or more strings.
+Surrounding spaces and spacing are preserved. Here is an example: ::
+
+   FOO = "123 456 789 123456 123 456 123 456"
+   FOO_remove = "123"
+   FOO_remove = "456"
+   FOO2 = " abc def ghi abcdef abc def abc def def"
+   FOO2_remove = "\
+       def \
+       abc \
+       ghi \
+       "
+
+The variable ``FOO`` becomes
+"  789 123456    " and ``FOO2`` becomes "    abcdef     ".
+
+Like "_append" and "_prepend", "_remove" is applied at variable
+expansion time.
+
+Override Style Operation Advantages
+-----------------------------------
+
+An advantage of the override style operations "_append", "_prepend", and
+"_remove" as compared to the "+=" and "=+" operators is that the
+override style operators provide guaranteed operations. For example,
+consider a class ``foo.bbclass`` that needs to add the value "val" to
+the variable ``FOO``, and a recipe that uses ``foo.bbclass`` as follows: ::
+
+   inherit foo
+   FOO = "initial"
+
+If ``foo.bbclass`` uses the "+=" operator,
+as follows, then the final value of ``FOO`` will be "initial", which is
+not what is desired: ::
+
+   FOO += "val"
+
+If, on the other hand, ``foo.bbclass``
+uses the "_append" operator, then the final value of ``FOO`` will be
+"initial val", as intended: ::
+
+   FOO_append = " val"
+
+.. note::
+
+   It is never necessary to use "+=" together with "_append". The following
+   sequence of assignments appends "barbaz" to FOO: ::
+
+       FOO_append = "bar"
+       FOO_append = "baz"
+
+
+   The only effect of changing the second assignment in the previous
+   example to use "+=" would be to add a space before "baz" in the
+   appended value (due to how the "+=" operator works).
+
+Another advantage of the override style operations is that you can
+combine them with other overrides as described in the
+":ref:`bitbake-user-manual/bitbake-user-manual-metadata:conditional syntax (overrides)`" section.
+
+Variable Flag Syntax
+--------------------
+
+Variable flags are BitBake's implementation of variable properties or
+attributes. It is a way of tagging extra information onto a variable.
+You can find more out about variable flags in general in the
+":ref:`bitbake-user-manual/bitbake-user-manual-metadata:variable flags`" section.
+
+You can define, append, and prepend values to variable flags. All the
+standard syntax operations previously mentioned work for variable flags
+except for override style syntax (i.e. "_prepend", "_append", and
+"_remove").
+
+Here are some examples showing how to set variable flags: ::
+
+   FOO[a] = "abc"
+   FOO[b] = "123"
+   FOO[a] += "456"
+
+The variable ``FOO`` has two flags:
+``[a]`` and ``[b]``. The flags are immediately set to "abc" and "123",
+respectively. The ``[a]`` flag becomes "abc 456".
+
+No need exists to pre-define variable flags. You can simply start using
+them. One extremely common application is to attach some brief
+documentation to a BitBake variable as follows: ::
+
+   CACHE[doc] = "The directory holding the cache of the metadata."
+
+Inline Python Variable Expansion
+--------------------------------
+
+You can use inline Python variable expansion to set variables. Here is
+an example: ::
+
+   DATE = "${@time.strftime('%Y%m%d',time.gmtime())}"
+
+This example results in the ``DATE`` variable being set to the current date.
+
+Probably the most common use of this feature is to extract the value of
+variables from BitBake's internal data dictionary, ``d``. The following
+lines select the values of a package name and its version number,
+respectively: ::
+
+   PN = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[0] or 'defaultpkgname'}"
+   PV = "${@bb.parse.BBHandler.vars_from_file(d.getVar('FILE', False),d)[1] or '1.0'}"
+
+.. note::
+
+   Inline Python expressions work just like variable expansions insofar as the
+   "=" and ":=" operators are concerned. Given the following assignment, foo()
+   is called each time FOO is expanded: ::
+
+      FOO = "${@foo()}"
+
+   Contrast this with the following immediate assignment, where foo() is only
+   called once, while the assignment is parsed: ::
+
+      FOO := "${@foo()}"
+
+For a different way to set variables with Python code during parsing,
+see the
+":ref:`bitbake-user-manual/bitbake-user-manual-metadata:anonymous python functions`" section.
+
+Unsetting variables
+-------------------
+
+It is possible to completely remove a variable or a variable flag from
+BitBake's internal data dictionary by using the "unset" keyword. Here is
+an example: ::
+
+   unset DATE
+   unset do_fetch[noexec]
+
+These two statements remove the ``DATE`` and the ``do_fetch[noexec]`` flag.
+
+Providing Pathnames
+-------------------
+
+When specifying pathnames for use with BitBake, do not use the tilde
+("~") character as a shortcut for your home directory. Doing so might
+cause BitBake to not recognize the path since BitBake does not expand
+this character in the same way a shell would.
+
+Instead, provide a fuller path as the following example illustrates: ::
+
+   BBLAYERS ?= " \
+       /home/scott-lenovo/LayerA \
+   "
+
+Exporting Variables to the Environment
+======================================
+
+You can export variables to the environment of running tasks by using
+the ``export`` keyword. For example, in the following example, the
+``do_foo`` task prints "value from the environment" when run: ::
+
+   export ENV_VARIABLE
+   ENV_VARIABLE = "value from the environment"
+
+   do_foo() {
+       bbplain "$ENV_VARIABLE"
+   }
+
+.. note::
+
+   BitBake does not expand ``$ENV_VARIABLE`` in this case because it lacks the
+   obligatory ``{}`` . Rather, ``$ENV_VARIABLE`` is expanded by the shell.
+
+It does not matter whether ``export ENV_VARIABLE`` appears before or
+after assignments to ``ENV_VARIABLE``.
+
+It is also possible to combine ``export`` with setting a value for the
+variable. Here is an example: ::
+
+   export ENV_VARIABLE = "variable-value"
+
+In the output of ``bitbake -e``, variables that are exported to the
+environment are preceded by "export".
+
+Among the variables commonly exported to the environment are ``CC`` and
+``CFLAGS``, which are picked up by many build systems.
+
+Conditional Syntax (Overrides)
+==============================
+
+BitBake uses :term:`OVERRIDES` to control what
+variables are overridden after BitBake parses recipes and configuration
+files. This section describes how you can use ``OVERRIDES`` as
+conditional metadata, talks about key expansion in relationship to
+``OVERRIDES``, and provides some examples to help with understanding.
+
+Conditional Metadata
+--------------------
+
+You can use ``OVERRIDES`` to conditionally select a specific version of
+a variable and to conditionally append or prepend the value of a
+variable.
+
+.. note::
+
+   Overrides can only use lower-case characters. Additionally,
+   underscores are not permitted in override names as they are used to
+   separate overrides from each other and from the variable name.
+
+-  *Selecting a Variable:* The ``OVERRIDES`` variable is a
+   colon-character-separated list that contains items for which you want
+   to satisfy conditions. Thus, if you have a variable that is
+   conditional on "arm", and "arm" is in ``OVERRIDES``, then the
+   "arm"-specific version of the variable is used rather than the
+   non-conditional version. Here is an example: ::
+
+      OVERRIDES = "architecture:os:machine"
+      TEST = "default"
+      TEST_os = "osspecific"
+      TEST_nooverride = "othercondvalue"
+
+   In this example, the ``OVERRIDES``
+   variable lists three overrides: "architecture", "os", and "machine".
+   The variable ``TEST`` by itself has a default value of "default". You
+   select the os-specific version of the ``TEST`` variable by appending
+   the "os" override to the variable (i.e. ``TEST_os``).
+
+   To better understand this, consider a practical example that assumes
+   an OpenEmbedded metadata-based Linux kernel recipe file. The
+   following lines from the recipe file first set the kernel branch
+   variable ``KBRANCH`` to a default value, then conditionally override
+   that value based on the architecture of the build: ::
+
+      KBRANCH = "standard/base"
+      KBRANCH_qemuarm = "standard/arm-versatile-926ejs"
+      KBRANCH_qemumips = "standard/mti-malta32"
+      KBRANCH_qemuppc = "standard/qemuppc"
+      KBRANCH_qemux86 = "standard/common-pc/base"
+      KBRANCH_qemux86-64 = "standard/common-pc-64/base"
+      KBRANCH_qemumips64 = "standard/mti-malta64"
+
+-  *Appending and Prepending:* BitBake also supports append and prepend
+   operations to variable values based on whether a specific item is
+   listed in ``OVERRIDES``. Here is an example: ::
+
+      DEPENDS = "glibc ncurses"
+      OVERRIDES = "machine:local"
+      DEPENDS_append_machine = "libmad"
+
+   In this example, ``DEPENDS`` becomes "glibc ncurses libmad".
+
+   Again, using an OpenEmbedded metadata-based kernel recipe file as an
+   example, the following lines will conditionally append to the
+   ``KERNEL_FEATURES`` variable based on the architecture: ::
+
+      KERNEL_FEATURES_append = " ${KERNEL_EXTRA_FEATURES}"
+      KERNEL_FEATURES_append_qemux86=" cfg/sound.scc cfg/paravirt_kvm.scc"
+      KERNEL_FEATURES_append_qemux86-64=" cfg/sound.scc cfg/paravirt_kvm.scc"
+
+-  *Setting a Variable for a Single Task:* BitBake supports setting a
+   variable just for the duration of a single task. Here is an example: ::
+
+      FOO_task-configure = "val 1"
+      FOO_task-compile = "val 2"
+
+   In the
+   previous example, ``FOO`` has the value "val 1" while the
+   ``do_configure`` task is executed, and the value "val 2" while the
+   ``do_compile`` task is executed.
+
+   Internally, this is implemented by prepending the task (e.g.
+   "task-compile:") to the value of
+   :term:`OVERRIDES` for the local datastore of the
+   ``do_compile`` task.
+
+   You can also use this syntax with other combinations (e.g.
+   "``_prepend``") as shown in the following example: ::
+
+      EXTRA_OEMAKE_prepend_task-compile = "${PARALLEL_MAKE} "
+
+Key Expansion
+-------------
+
+Key expansion happens when the BitBake datastore is finalized. To better
+understand this, consider the following example: ::
+
+   A${B} = "X"
+   B = "2"
+   A2 = "Y"
+
+In this case, after all the parsing is complete, BitBake expands
+``${B}`` into "2". This expansion causes ``A2``, which was set to "Y"
+before the expansion, to become "X".
+
+.. _variable-interaction-worked-examples:
+
+Examples
+--------
+
+Despite the previous explanations that show the different forms of
+variable definitions, it can be hard to work out exactly what happens
+when variable operators, conditional overrides, and unconditional
+overrides are combined. This section presents some common scenarios
+along with explanations for variable interactions that typically confuse
+users.
+
+There is often confusion concerning the order in which overrides and
+various "append" operators take effect. Recall that an append or prepend
+operation using "_append" and "_prepend" does not result in an immediate
+assignment as would "+=", ".=", "=+", or "=.". Consider the following
+example: ::
+
+   OVERRIDES = "foo"
+   A = "Z"
+   A_foo_append = "X"
+
+For this case,
+``A`` is unconditionally set to "Z" and "X" is unconditionally and
+immediately appended to the variable ``A_foo``. Because overrides have
+not been applied yet, ``A_foo`` is set to "X" due to the append and
+``A`` simply equals "Z".
+
+Applying overrides, however, changes things. Since "foo" is listed in
+``OVERRIDES``, the conditional variable ``A`` is replaced with the "foo"
+version, which is equal to "X". So effectively, ``A_foo`` replaces
+``A``.
+
+This next example changes the order of the override and the append: ::
+
+   OVERRIDES = "foo"
+   A = "Z"
+   A_append_foo = "X"
+
+For this case, before
+overrides are handled, ``A`` is set to "Z" and ``A_append_foo`` is set
+to "X". Once the override for "foo" is applied, however, ``A`` gets
+appended with "X". Consequently, ``A`` becomes "ZX". Notice that spaces
+are not appended.
+
+This next example has the order of the appends and overrides reversed
+back as in the first example: ::
+
+   OVERRIDES = "foo"
+   A = "Y"
+   A_foo_append = "Z"
+   A_foo_append = "X"
+
+For this case, before any overrides are resolved,
+``A`` is set to "Y" using an immediate assignment. After this immediate
+assignment, ``A_foo`` is set to "Z", and then further appended with "X"
+leaving the variable set to "ZX". Finally, applying the override for
+"foo" results in the conditional variable ``A`` becoming "ZX" (i.e.
+``A`` is replaced with ``A_foo``).
+
+This final example mixes in some varying operators: ::
+
+   A = "1"
+   A_append = "2"
+   A_append = "3"
+   A += "4"
+   A .= "5"
+
+For this case, the type of append
+operators are affecting the order of assignments as BitBake passes
+through the code multiple times. Initially, ``A`` is set to "1 45"
+because of the three statements that use immediate operators. After
+these assignments are made, BitBake applies the "_append" operations.
+Those operations result in ``A`` becoming "1 4523".
+
+Sharing Functionality
+=====================
+
+BitBake allows for metadata sharing through include files (``.inc``) and
+class files (``.bbclass``). For example, suppose you have a piece of
+common functionality such as a task definition that you want to share
+between more than one recipe. In this case, creating a ``.bbclass`` file
+that contains the common functionality and then using the ``inherit``
+directive in your recipes to inherit the class would be a common way to
+share the task.
+
+This section presents the mechanisms BitBake provides to allow you to
+share functionality between recipes. Specifically, the mechanisms
+include ``include``, ``inherit``, ``INHERIT``, and ``require``
+directives.
+
+Locating Include and Class Files
+--------------------------------
+
+BitBake uses the :term:`BBPATH` variable to locate
+needed include and class files. Additionally, BitBake searches the
+current directory for ``include`` and ``require`` directives.
+
+.. note::
+
+   The BBPATH variable is analogous to the environment variable PATH .
+
+In order for include and class files to be found by BitBake, they need
+to be located in a "classes" subdirectory that can be found in
+``BBPATH``.
+
+``inherit`` Directive
+---------------------
+
+When writing a recipe or class file, you can use the ``inherit``
+directive to inherit the functionality of a class (``.bbclass``).
+BitBake only supports this directive when used within recipe and class
+files (i.e. ``.bb`` and ``.bbclass``).
+
+The ``inherit`` directive is a rudimentary means of specifying
+functionality contained in class files that your recipes require. For
+example, you can easily abstract out the tasks involved in building a
+package that uses Autoconf and Automake and put those tasks into a class
+file and then have your recipe inherit that class file.
+
+As an example, your recipes could use the following directive to inherit
+an ``autotools.bbclass`` file. The class file would contain common
+functionality for using Autotools that could be shared across recipes: ::
+
+   inherit autotools
+
+In this case, BitBake would search for the directory
+``classes/autotools.bbclass`` in ``BBPATH``.
+
+.. note::
+
+   You can override any values and functions of the inherited class
+   within your recipe by doing so after the "inherit" statement.
+
+If you want to use the directive to inherit multiple classes, separate
+them with spaces. The following example shows how to inherit both the
+``buildhistory`` and ``rm_work`` classes: ::
+
+   inherit buildhistory rm_work
+
+An advantage with the inherit directive as compared to both the
+:ref:`include <bitbake-user-manual/bitbake-user-manual-metadata:\`\`include\`\` directive>` and :ref:`require <bitbake-user-manual/bitbake-user-manual-metadata:\`\`require\`\` directive>`
+directives is that you can inherit class files conditionally. You can
+accomplish this by using a variable expression after the ``inherit``
+statement. Here is an example: ::
+
+   inherit ${VARNAME}
+
+If ``VARNAME`` is
+going to be set, it needs to be set before the ``inherit`` statement is
+parsed. One way to achieve a conditional inherit in this case is to use
+overrides: ::
+
+   VARIABLE = ""
+   VARIABLE_someoverride = "myclass"
+
+Another method is by using anonymous Python. Here is an example: ::
+
+   python () {
+       if condition == value:
+           d.setVar('VARIABLE', 'myclass')
+       else:
+           d.setVar('VARIABLE', '')
+   }
+
+Alternatively, you could use an in-line Python expression in the
+following form: ::
+
+   inherit ${@'classname' if condition else ''}
+   inherit ${@functionname(params)}
+
+In all cases, if the expression evaluates to an
+empty string, the statement does not trigger a syntax error because it
+becomes a no-op.
+
+``include`` Directive
+---------------------
+
+BitBake understands the ``include`` directive. This directive causes
+BitBake to parse whatever file you specify, and to insert that file at
+that location. The directive is much like its equivalent in Make except
+that if the path specified on the include line is a relative path,
+BitBake locates the first file it can find within ``BBPATH``.
+
+The include directive is a more generic method of including
+functionality as compared to the :ref:`inherit <bitbake-user-manual/bitbake-user-manual-metadata:\`\`inherit\`\` directive>`
+directive, which is restricted to class (i.e. ``.bbclass``) files. The
+include directive is applicable for any other kind of shared or
+encapsulated functionality or configuration that does not suit a
+``.bbclass`` file.
+
+As an example, suppose you needed a recipe to include some self-test
+definitions: ::
+
+   include test_defs.inc
+
+.. note::
+
+   The include directive does not produce an error when the file cannot be
+   found.  Consequently, it is recommended that if the file you are including is
+   expected to exist, you should use :ref:`require <require-inclusion>` instead
+   of include . Doing so makes sure that an error is produced if the file cannot
+   be found.
+
+.. _require-inclusion:
+
+``require`` Directive
+---------------------
+
+BitBake understands the ``require`` directive. This directive behaves
+just like the ``include`` directive with the exception that BitBake
+raises a parsing error if the file to be included cannot be found. Thus,
+any file you require is inserted into the file that is being parsed at
+the location of the directive.
+
+The require directive, like the include directive previously described,
+is a more generic method of including functionality as compared to the
+:ref:`inherit <bitbake-user-manual/bitbake-user-manual-metadata:\`\`inherit\`\` directive>` directive, which is restricted to class
+(i.e. ``.bbclass``) files. The require directive is applicable for any
+other kind of shared or encapsulated functionality or configuration that
+does not suit a ``.bbclass`` file.
+
+Similar to how BitBake handles :ref:`include <bitbake-user-manual/bitbake-user-manual-metadata:\`\`include\`\` directive>`, if
+the path specified on the require line is a relative path, BitBake
+locates the first file it can find within ``BBPATH``.
+
+As an example, suppose you have two versions of a recipe (e.g.
+``foo_1.2.2.bb`` and ``foo_2.0.0.bb``) where each version contains some
+identical functionality that could be shared. You could create an
+include file named ``foo.inc`` that contains the common definitions
+needed to build "foo". You need to be sure ``foo.inc`` is located in the
+same directory as your two recipe files as well. Once these conditions
+are set up, you can share the functionality using a ``require``
+directive from within each recipe: ::
+
+   require foo.inc
+
+``INHERIT`` Configuration Directive
+-----------------------------------
+
+When creating a configuration file (``.conf``), you can use the
+:term:`INHERIT` configuration directive to inherit a
+class. BitBake only supports this directive when used within a
+configuration file.
+
+As an example, suppose you needed to inherit a class file called
+``abc.bbclass`` from a configuration file as follows: ::
+
+   INHERIT += "abc"
+
+This configuration directive causes the named class to be inherited at
+the point of the directive during parsing. As with the ``inherit``
+directive, the ``.bbclass`` file must be located in a "classes"
+subdirectory in one of the directories specified in ``BBPATH``.
+
+.. note::
+
+   Because .conf files are parsed first during BitBake's execution, using
+   INHERIT to inherit a class effectively inherits the class globally (i.e. for
+   all recipes).
+
+If you want to use the directive to inherit multiple classes, you can
+provide them on the same line in the ``local.conf`` file. Use spaces to
+separate the classes. The following example shows how to inherit both
+the ``autotools`` and ``pkgconfig`` classes: ::
+
+   INHERIT += "autotools pkgconfig"
+
+Functions
+=========
+
+As with most languages, functions are the building blocks that are used
+to build up operations into tasks. BitBake supports these types of
+functions:
+
+-  *Shell Functions:* Functions written in shell script and executed
+   either directly as functions, tasks, or both. They can also be called
+   by other shell functions.
+
+-  *BitBake-Style Python Functions:* Functions written in Python and
+   executed by BitBake or other Python functions using
+   ``bb.build.exec_func()``.
+
+-  *Python Functions:* Functions written in Python and executed by
+   Python.
+
+-  *Anonymous Python Functions:* Python functions executed automatically
+   during parsing.
+
+Regardless of the type of function, you can only define them in class
+(``.bbclass``) and recipe (``.bb`` or ``.inc``) files.
+
+Shell Functions
+---------------
+
+Functions written in shell script and executed either directly as
+functions, tasks, or both. They can also be called by other shell
+functions. Here is an example shell function definition: ::
+
+   some_function () {
+       echo "Hello World"
+   }
+
+When you create these types of functions in
+your recipe or class files, you need to follow the shell programming
+rules. The scripts are executed by ``/bin/sh``, which may not be a bash
+shell but might be something such as ``dash``. You should not use
+Bash-specific script (bashisms).
+
+Overrides and override-style operators like ``_append`` and ``_prepend``
+can also be applied to shell functions. Most commonly, this application
+would be used in a ``.bbappend`` file to modify functions in the main
+recipe. It can also be used to modify functions inherited from classes.
+
+As an example, consider the following: ::
+
+   do_foo() {
+       bbplain first
+       fn
+   }
+
+   fn_prepend() {
+       bbplain second
+   }
+
+   fn() {
+       bbplain third
+   }
+
+   do_foo_append() {
+       bbplain fourth
+   }
+
+Running ``do_foo`` prints the following: ::
+
+   recipename do_foo: first
+   recipename do_foo: second
+   recipename do_foo: third
+   recipename do_foo: fourth
+
+.. note::
+
+   Overrides and override-style operators can be applied to any shell
+   function, not just :ref:`tasks <bitbake-user-manual/bitbake-user-manual-metadata:tasks>`.
+
+You can use the ``bitbake -e`` recipename command to view the final
+assembled function after all overrides have been applied.
+
+BitBake-Style Python Functions
+------------------------------
+
+These functions are written in Python and executed by BitBake or other
+Python functions using ``bb.build.exec_func()``.
+
+An example BitBake function is: ::
+
+   python some_python_function () {
+       d.setVar("TEXT", "Hello World")
+       print d.getVar("TEXT")
+   }
+
+Because the
+Python "bb" and "os" modules are already imported, you do not need to
+import these modules. Also in these types of functions, the datastore
+("d") is a global variable and is always automatically available.
+
+.. note::
+
+   Variable expressions (e.g.  ``${X}`` ) are no longer expanded within Python
+   functions. This behavior is intentional in order to allow you to freely set
+   variable values to expandable expressions without having them expanded
+   prematurely. If you do wish to expand a variable within a Python function,
+   use ``d.getVar("X")`` . Or, for more complicated expressions, use ``d.expand()``.
+
+Similar to shell functions, you can also apply overrides and
+override-style operators to BitBake-style Python functions.
+
+As an example, consider the following: ::
+
+   python do_foo_prepend() {
+       bb.plain("first")
+   }
+
+   python do_foo() {
+       bb.plain("second")
+   }
+
+   python do_foo_append() {
+       bb.plain("third")
+   }
+
+Running ``do_foo`` prints the following: ::
+
+   recipename do_foo: first
+   recipename do_foo: second
+   recipename do_foo: third
+
+You can use the ``bitbake -e`` recipename command to view
+the final assembled function after all overrides have been applied.
+
+Python Functions
+----------------
+
+These functions are written in Python and are executed by other Python
+code. Examples of Python functions are utility functions that you intend
+to call from in-line Python or from within other Python functions. Here
+is an example: ::
+
+   def get_depends(d):
+       if d.getVar('SOMECONDITION'):
+           return "dependencywithcond"
+       else:
+           return "dependency"
+
+   SOMECONDITION = "1"
+   DEPENDS = "${@get_depends(d)}"
+
+This would result in ``DEPENDS`` containing ``dependencywithcond``.
+
+Here are some things to know about Python functions:
+
+-  Python functions can take parameters.
+
+-  The BitBake datastore is not automatically available. Consequently,
+   you must pass it in as a parameter to the function.
+
+-  The "bb" and "os" Python modules are automatically available. You do
+   not need to import them.
+
+BitBake-Style Python Functions Versus Python Functions
+------------------------------------------------------
+
+Following are some important differences between BitBake-style Python
+functions and regular Python functions defined with "def":
+
+-  Only BitBake-style Python functions can be :ref:`tasks <bitbake-user-manual/bitbake-user-manual-metadata:tasks>`.
+
+-  Overrides and override-style operators can only be applied to
+   BitBake-style Python functions.
+
+-  Only regular Python functions can take arguments and return values.
+
+-  :ref:`Variable flags <bitbake-user-manual/bitbake-user-manual-metadata:variable flags>` such as
+   ``[dirs]``, ``[cleandirs]``, and ``[lockfiles]`` can be used on BitBake-style
+   Python functions, but not on regular Python functions.
+
+-  BitBake-style Python functions generate a separate
+   ``${``\ :term:`T`\ ``}/run.``\ function-name\ ``.``\ pid
+   script that is executed to run the function, and also generate a log
+   file in ``${T}/log.``\ function-name\ ``.``\ pid if they are executed
+   as tasks.
+
+   Regular Python functions execute "inline" and do not generate any
+   files in ``${T}``.
+
+-  Regular Python functions are called with the usual Python syntax.
+   BitBake-style Python functions are usually tasks and are called
+   directly by BitBake, but can also be called manually from Python code
+   by using the ``bb.build.exec_func()`` function. Here is an example: ::
+
+      bb.build.exec_func("my_bitbake_style_function", d)
+
+   .. note::
+
+      ``bb.build.exec_func()`` can also be used to run shell functions from Python
+      code. If you want to run a shell function before a Python function within
+      the same task, then you can use a parent helper Python function that
+      starts by running the shell function with ``bb.build.exec_func()`` and then
+      runs the Python code.
+
+   To detect errors from functions executed with
+   ``bb.build.exec_func()``, you can catch the ``bb.build.FuncFailed``
+   exception.
+
+   .. note::
+
+      Functions in metadata (recipes and classes) should not themselves raise
+      ``bb.build.FuncFailed``. Rather, ``bb.build.FuncFailed`` should be viewed as a
+      general indicator that the called function failed by raising an
+      exception. For example, an exception raised by ``bb.fatal()`` will be caught
+      inside ``bb.build.exec_func()``, and a ``bb.build.FuncFailed`` will be raised in
+      response.
+
+Due to their simplicity, you should prefer regular Python functions over
+BitBake-style Python functions unless you need a feature specific to
+BitBake-style Python functions. Regular Python functions in metadata are
+a more recent invention than BitBake-style Python functions, and older
+code tends to use ``bb.build.exec_func()`` more often.
+
+Anonymous Python Functions
+--------------------------
+
+Sometimes it is useful to set variables or perform other operations
+programmatically during parsing. To do this, you can define special
+Python functions, called anonymous Python functions, that run at the end
+of parsing. For example, the following conditionally sets a variable
+based on the value of another variable: ::
+
+   python () {
+       if d.getVar('SOMEVAR') == 'value':
+           d.setVar('ANOTHERVAR', 'value2')
+   }
+
+An equivalent way to mark a function as an anonymous function is to give it
+the name "__anonymous", rather than no name.
+
+Anonymous Python functions always run at the end of parsing, regardless
+of where they are defined. If a recipe contains many anonymous
+functions, they run in the same order as they are defined within the
+recipe. As an example, consider the following snippet: ::
+
+   python () {
+       d.setVar('FOO', 'foo 2')
+   }
+
+   FOO = "foo 1"
+
+   python () {
+       d.appendVar('BAR',' bar 2')
+   }
+
+   BAR = "bar 1"
+
+The previous example is conceptually
+equivalent to the following snippet: ::
+
+   FOO = "foo 1"
+   BAR = "bar 1"
+   FOO = "foo 2"
+   BAR += "bar 2"
+
+``FOO`` ends up with the value "foo 2", and
+``BAR`` with the value "bar 1 bar 2". Just as in the second snippet, the
+values set for the variables within the anonymous functions become
+available to tasks, which always run after parsing.
+
+Overrides and override-style operators such as "``_append``" are applied
+before anonymous functions run. In the following example, ``FOO`` ends
+up with the value "foo from anonymous": ::
+
+   FOO = "foo"
+   FOO_append = " from outside"
+
+   python () {
+       d.setVar("FOO", "foo from anonymous")
+   }
+
+For methods
+you can use with anonymous Python functions, see the
+":ref:`bitbake-user-manual/bitbake-user-manual-metadata:functions you can call from within python`"
+section. For a different method to run Python code during parsing, see
+the ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:inline python variable expansion`" section.
+
+Flexible Inheritance for Class Functions
+----------------------------------------
+
+Through coding techniques and the use of ``EXPORT_FUNCTIONS``, BitBake
+supports exporting a function from a class such that the class function
+appears as the default implementation of the function, but can still be
+called if a recipe inheriting the class needs to define its own version
+of the function.
+
+To understand the benefits of this feature, consider the basic scenario
+where a class defines a task function and your recipe inherits the
+class. In this basic scenario, your recipe inherits the task function as
+defined in the class. If desired, your recipe can add to the start and
+end of the function by using the "_prepend" or "_append" operations
+respectively, or it can redefine the function completely. However, if it
+redefines the function, there is no means for it to call the class
+version of the function. ``EXPORT_FUNCTIONS`` provides a mechanism that
+enables the recipe's version of the function to call the original
+version of the function.
+
+To make use of this technique, you need the following things in place:
+
+-  The class needs to define the function as follows: ::
+
+      classname_functionname
+
+   For example, if you have a class file
+   ``bar.bbclass`` and a function named ``do_foo``, the class must
+   define the function as follows: ::
+
+      bar_do_foo
+
+-  The class needs to contain the ``EXPORT_FUNCTIONS`` statement as
+   follows: ::
+
+      EXPORT_FUNCTIONS functionname
+
+   For example, continuing with
+   the same example, the statement in the ``bar.bbclass`` would be as
+   follows: ::
+
+      EXPORT_FUNCTIONS do_foo
+
+-  You need to call the function appropriately from within your recipe.
+   Continuing with the same example, if your recipe needs to call the
+   class version of the function, it should call ``bar_do_foo``.
+   Assuming ``do_foo`` was a shell function and ``EXPORT_FUNCTIONS`` was
+   used as above, the recipe's function could conditionally call the
+   class version of the function as follows: ::
+
+      do_foo() {
+          if [ somecondition ] ; then
+              bar_do_foo
+          else
+              # Do something else
+          fi
+      }
+
+   To call your modified version of the function as defined in your recipe,
+   call it as ``do_foo``.
+
+With these conditions met, your single recipe can freely choose between
+the original function as defined in the class file and the modified
+function in your recipe. If you do not set up these conditions, you are
+limited to using one function or the other.
+
+Tasks
+=====
+
+Tasks are BitBake execution units that make up the steps that BitBake
+can run for a given recipe. Tasks are only supported in recipes and
+classes (i.e. in ``.bb`` files and files included or inherited from
+``.bb`` files). By convention, tasks have names that start with "do\_".
+
+Promoting a Function to a Task
+------------------------------
+
+Tasks are either :ref:`shell functions <bitbake-user-manual/bitbake-user-manual-metadata:shell functions>` or
+:ref:`BitBake-style Python functions <bitbake-user-manual/bitbake-user-manual-metadata:bitbake-style python functions>`
+that have been promoted to tasks by using the ``addtask`` command. The
+``addtask`` command can also optionally describe dependencies between
+the task and other tasks. Here is an example that shows how to define a
+task and declare some dependencies: ::
+
+   python do_printdate () {
+       import time
+       print time.strftime('%Y%m%d', time.gmtime())
+   }
+   addtask printdate after do_fetch before do_build
+
+The first argument to ``addtask`` is the name
+of the function to promote to a task. If the name does not start with
+"do\_", "do\_" is implicitly added, which enforces the convention that all
+task names start with "do\_".
+
+In the previous example, the ``do_printdate`` task becomes a dependency
+of the ``do_build`` task, which is the default task (i.e. the task run
+by the ``bitbake`` command unless another task is specified explicitly).
+Additionally, the ``do_printdate`` task becomes dependent upon the
+``do_fetch`` task. Running the ``do_build`` task results in the
+``do_printdate`` task running first.
+
+.. note::
+
+   If you try out the previous example, you might see that the
+   ``do_printdate``
+   task is only run the first time you build the recipe with the
+   ``bitbake``
+   command. This is because BitBake considers the task "up-to-date"
+   after that initial run. If you want to force the task to always be
+   rerun for experimentation purposes, you can make BitBake always
+   consider the task "out-of-date" by using the
+   :ref:`[nostamp] <bitbake-user-manual/bitbake-user-manual-metadata:Variable Flags>`
+   variable flag, as follows: ::
+
+      do_printdate[nostamp] = "1"
+
+   You can also explicitly run the task and provide the
+   -f option as follows: ::
+
+      $ bitbake recipe -c printdate -f
+
+   When manually selecting a task to run with the bitbake ``recipe
+   -c task`` command, you can omit the "do\_" prefix as part of the task
+   name.
+
+You might wonder about the practical effects of using ``addtask``
+without specifying any dependencies as is done in the following example: ::
+
+   addtask printdate
+
+In this example, assuming dependencies have not been
+added through some other means, the only way to run the task is by
+explicitly selecting it with ``bitbake`` recipe ``-c printdate``. You
+can use the ``do_listtasks`` task to list all tasks defined in a recipe
+as shown in the following example: ::
+
+   $ bitbake recipe -c listtasks
+
+For more information on task dependencies, see the
+":ref:`bitbake-user-manual/bitbake-user-manual-execution:dependencies`" section.
+
+See the ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:variable flags`" section for information
+on variable flags you can use with tasks.
+
+Deleting a Task
+---------------
+
+As well as being able to add tasks, you can delete them. Simply use the
+``deltask`` command to delete a task. For example, to delete the example
+task used in the previous sections, you would use: ::
+
+   deltask printdate
+
+If you delete a task using the ``deltask`` command and the task has
+dependencies, the dependencies are not reconnected. For example, suppose
+you have three tasks named ``do_a``, ``do_b``, and ``do_c``.
+Furthermore, ``do_c`` is dependent on ``do_b``, which in turn is
+dependent on ``do_a``. Given this scenario, if you use ``deltask`` to
+delete ``do_b``, the implicit dependency relationship between ``do_c``
+and ``do_a`` through ``do_b`` no longer exists, and ``do_c``
+dependencies are not updated to include ``do_a``. Thus, ``do_c`` is free
+to run before ``do_a``.
+
+If you want dependencies such as these to remain intact, use the
+``[noexec]`` varflag to disable the task instead of using the
+``deltask`` command to delete it: ::
+
+   do_b[noexec] = "1"
+
+Passing Information Into the Build Task Environment
+---------------------------------------------------
+
+When running a task, BitBake tightly controls the shell execution
+environment of the build tasks to make sure unwanted contamination from
+the build machine cannot influence the build.
+
+.. note::
+
+   By default, BitBake cleans the environment to include only those
+   things exported or listed in its whitelist to ensure that the build
+   environment is reproducible and consistent. You can prevent this
+   "cleaning" by setting the :term:`BB_PRESERVE_ENV` variable.
+
+Consequently, if you do want something to get passed into the build task
+environment, you must take these two steps:
+
+#. Tell BitBake to load what you want from the environment into the
+   datastore. You can do so through the
+   :term:`BB_ENV_WHITELIST` and
+   :term:`BB_ENV_EXTRAWHITE` variables. For
+   example, assume you want to prevent the build system from accessing
+   your ``$HOME/.ccache`` directory. The following command "whitelists"
+   the environment variable ``CCACHE_DIR`` causing BitBake to allow that
+   variable into the datastore: ::
+
+      export BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE CCACHE_DIR"
+
+#. Tell BitBake to export what you have loaded into the datastore to the
+   task environment of every running task. Loading something from the
+   environment into the datastore (previous step) only makes it
+   available in the datastore. To export it to the task environment of
+   every running task, use a command similar to the following in your
+   local configuration file ``local.conf`` or your distribution
+   configuration file: ::
+
+      export CCACHE_DIR
+
+   .. note::
+
+      A side effect of the previous steps is that BitBake records the
+      variable as a dependency of the build process in things like the
+      setscene checksums. If doing so results in unnecessary rebuilds of
+      tasks, you can whitelist the variable so that the setscene code
+      ignores the dependency when it creates checksums.
+
+Sometimes, it is useful to be able to obtain information from the
+original execution environment. BitBake saves a copy of the original
+environment into a special variable named :term:`BB_ORIGENV`.
+
+The ``BB_ORIGENV`` variable returns a datastore object that can be
+queried using the standard datastore operators such as
+``getVar(, False)``. The datastore object is useful, for example, to
+find the original ``DISPLAY`` variable. Here is an example: ::
+
+   origenv = d.getVar("BB_ORIGENV", False)
+   bar = origenv.getVar("BAR", False)
+
+The previous example returns ``BAR`` from the original execution
+environment.
+
+Variable Flags
+==============
+
+Variable flags (varflags) help control a task's functionality and
+dependencies. BitBake reads and writes varflags to the datastore using
+the following command forms: ::
+
+   variable = d.getVarFlags("variable")
+   self.d.setVarFlags("FOO", {"func": True})
+
+When working with varflags, the same syntax, with the exception of
+overrides, applies. In other words, you can set, append, and prepend
+varflags just like variables. See the
+":ref:`bitbake-user-manual/bitbake-user-manual-metadata:variable flag syntax`" section for details.
+
+BitBake has a defined set of varflags available for recipes and classes.
+Tasks support a number of these flags which control various
+functionality of the task:
+
+-  ``[cleandirs]``: Empty directories that should be created before
+   the task runs. Directories that already exist are removed and
+   recreated to empty them.
+
+-  ``[depends]``: Controls inter-task dependencies. See the
+   :term:`DEPENDS` variable and the
+   ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:inter-task
+   dependencies`" section for more information.
+
+-  ``[deptask]``: Controls task build-time dependencies. See the
+   :term:`DEPENDS` variable and the ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:build dependencies`" section for more information.
+
+-  ``[dirs]``: Directories that should be created before the task
+   runs. Directories that already exist are left as is. The last
+   directory listed is used as the current working directory for the
+   task.
+
+-  ``[lockfiles]``: Specifies one or more lockfiles to lock while the
+   task executes. Only one task may hold a lockfile, and any task that
+   attempts to lock an already locked file will block until the lock is
+   released. You can use this variable flag to accomplish mutual
+   exclusion.
+
+-  ``[noexec]``: When set to "1", marks the task as being empty, with
+   no execution required. You can use the ``[noexec]`` flag to set up
+   tasks as dependency placeholders, or to disable tasks defined
+   elsewhere that are not needed in a particular recipe.
+
+-  ``[nostamp]``: When set to "1", tells BitBake to not generate a
+   stamp file for a task, which implies the task should always be
+   executed.
+
+   .. caution::
+
+      Any task that depends (possibly indirectly) on a ``[nostamp]`` task will
+      always be executed as well. This can cause unnecessary rebuilding if you
+      are not careful.
+
+-  ``[number_threads]``: Limits tasks to a specific number of
+   simultaneous threads during execution. This varflag is useful when
+   your build host has a large number of cores but certain tasks need to
+   be rate-limited due to various kinds of resource constraints (e.g. to
+   avoid network throttling). ``number_threads`` works similarly to the
+   :term:`BB_NUMBER_THREADS` variable but is task-specific.
+
+   Set the value globally. For example, the following makes sure the
+   ``do_fetch`` task uses no more than two simultaneous execution
+   threads: do_fetch[number_threads] = "2"
+
+   .. warning::
+
+      -  Setting the varflag in individual recipes rather than globally
+         can result in unpredictable behavior.
+
+      -  Setting the varflag to a value greater than the value used in
+         the ``BB_NUMBER_THREADS`` variable causes ``number_threads`` to
+         have no effect.
+
+-  ``[postfuncs]``: List of functions to call after the completion of
+   the task.
+
+-  ``[prefuncs]``: List of functions to call before the task executes.
+
+-  ``[rdepends]``: Controls inter-task runtime dependencies. See the
+   :term:`RDEPENDS` variable, the
+   :term:`RRECOMMENDS` variable, and the
+   ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:inter-task dependencies`" section for
+   more information.
+
+-  ``[rdeptask]``: Controls task runtime dependencies. See the
+   :term:`RDEPENDS` variable, the
+   :term:`RRECOMMENDS` variable, and the
+   ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:runtime dependencies`" section for more
+   information.
+
+-  ``[recideptask]``: When set in conjunction with ``recrdeptask``,
+   specifies a task that should be inspected for additional
+   dependencies.
+
+-  ``[recrdeptask]``: Controls task recursive runtime dependencies.
+   See the :term:`RDEPENDS` variable, the
+   :term:`RRECOMMENDS` variable, and the
+   ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:recursive dependencies`" section for
+   more information.
+
+-  ``[stamp-extra-info]``: Extra stamp information to append to the
+   task's stamp. As an example, OpenEmbedded uses this flag to allow
+   machine-specific tasks.
+
+-  ``[umask]``: The umask to run the task under.
+
+Several varflags are useful for controlling how signatures are
+calculated for variables. For more information on this process, see the
+":ref:`bitbake-user-manual/bitbake-user-manual-execution:checksums (signatures)`" section.
+
+-  ``[vardeps]``: Specifies a space-separated list of additional
+   variables to add to a variable's dependencies for the purposes of
+   calculating its signature. Adding variables to this list is useful,
+   for example, when a function refers to a variable in a manner that
+   does not allow BitBake to automatically determine that the variable
+   is referred to.
+
+-  ``[vardepsexclude]``: Specifies a space-separated list of variables
+   that should be excluded from a variable's dependencies for the
+   purposes of calculating its signature.
+
+-  ``[vardepvalue]``: If set, instructs BitBake to ignore the actual
+   value of the variable and instead use the specified value when
+   calculating the variable's signature.
+
+-  ``[vardepvalueexclude]``: Specifies a pipe-separated list of
+   strings to exclude from the variable's value when calculating the
+   variable's signature.
+
+Events
+======
+
+BitBake allows installation of event handlers within recipe and class
+files. Events are triggered at certain points during operation, such as
+the beginning of operation against a given recipe (i.e. ``*.bb``), the
+start of a given task, a task failure, a task success, and so forth. The
+intent is to make it easy to do things like email notification on build
+failures.
+
+Following is an example event handler that prints the name of the event
+and the content of the ``FILE`` variable: ::
+
+   addhandler myclass_eventhandler
+   python myclass_eventhandler() {
+       from bb.event import getName
+       print("The name of the Event is %s" % getName(e))
+       print("The file we run for is %s" % d.getVar('FILE'))
+   }
+   myclass_eventhandler[eventmask] = "bb.event.BuildStarted
+   bb.event.BuildCompleted"
+
+In the previous example, an eventmask has been
+set so that the handler only sees the "BuildStarted" and
+"BuildCompleted" events. This event handler gets called every time an
+event matching the eventmask is triggered. A global variable "e" is
+defined, which represents the current event. With the ``getName(e)``
+method, you can get the name of the triggered event. The global
+datastore is available as "d". In legacy code, you might see "e.data"
+used to get the datastore. However, realize that "e.data" is deprecated
+and you should use "d" going forward.
+
+The context of the datastore is appropriate to the event in question.
+For example, "BuildStarted" and "BuildCompleted" events run before any
+tasks are executed so would be in the global configuration datastore
+namespace. No recipe-specific metadata exists in that namespace. The
+"BuildStarted" and "BuildCompleted" events also run in the main
+cooker/server process rather than any worker context. Thus, any changes
+made to the datastore would be seen by other cooker/server events within
+the current build but not seen outside of that build or in any worker
+context. Task events run in the actual tasks in question consequently
+have recipe-specific and task-specific contents. These events run in the
+worker context and are discarded at the end of task execution.
+
+During a standard build, the following common events might occur. The
+following events are the most common kinds of events that most metadata
+might have an interest in viewing:
+
+-  ``bb.event.ConfigParsed()``: Fired when the base configuration; which
+   consists of ``bitbake.conf``, ``base.bbclass`` and any global
+   ``INHERIT`` statements; has been parsed. You can see multiple such
+   events when each of the workers parse the base configuration or if
+   the server changes configuration and reparses. Any given datastore
+   only has one such event executed against it, however. If
+   ```BB_INVALIDCONF`` <#>`__ is set in the datastore by the event
+   handler, the configuration is reparsed and a new event triggered,
+   allowing the metadata to update configuration.
+
+-  ``bb.event.HeartbeatEvent()``: Fires at regular time intervals of one
+   second. You can configure the interval time using the
+   ``BB_HEARTBEAT_EVENT`` variable. The event's "time" attribute is the
+   ``time.time()`` value when the event is triggered. This event is
+   useful for activities such as system state monitoring.
+
+-  ``bb.event.ParseStarted()``: Fired when BitBake is about to start
+   parsing recipes. This event's "total" attribute represents the number
+   of recipes BitBake plans to parse.
+
+-  ``bb.event.ParseProgress()``: Fired as parsing progresses. This
+   event's "current" attribute is the number of recipes parsed as well
+   as the "total" attribute.
+
+-  ``bb.event.ParseCompleted()``: Fired when parsing is complete. This
+   event's "cached", "parsed", "skipped", "virtuals", "masked", and
+   "errors" attributes provide statistics for the parsing results.
+
+-  ``bb.event.BuildStarted()``: Fired when a new build starts. BitBake
+   fires multiple "BuildStarted" events (one per configuration) when
+   multiple configuration (multiconfig) is enabled.
+
+-  ``bb.build.TaskStarted()``: Fired when a task starts. This event's
+   "taskfile" attribute points to the recipe from which the task
+   originates. The "taskname" attribute, which is the task's name,
+   includes the ``do_`` prefix, and the "logfile" attribute point to
+   where the task's output is stored. Finally, the "time" attribute is
+   the task's execution start time.
+
+-  ``bb.build.TaskInvalid()``: Fired if BitBake tries to execute a task
+   that does not exist.
+
+-  ``bb.build.TaskFailedSilent()``: Fired for setscene tasks that fail
+   and should not be presented to the user verbosely.
+
+-  ``bb.build.TaskFailed()``: Fired for normal tasks that fail.
+
+-  ``bb.build.TaskSucceeded()``: Fired when a task successfully
+   completes.
+
+-  ``bb.event.BuildCompleted()``: Fired when a build finishes.
+
+-  ``bb.cooker.CookerExit()``: Fired when the BitBake server/cooker
+   shuts down. This event is usually only seen by the UIs as a sign they
+   should also shutdown.
+
+This next list of example events occur based on specific requests to the
+server. These events are often used to communicate larger pieces of
+information from the BitBake server to other parts of BitBake such as
+user interfaces:
+
+-  ``bb.event.TreeDataPreparationStarted()``
+-  ``bb.event.TreeDataPreparationProgress()``
+-  ``bb.event.TreeDataPreparationCompleted()``
+-  ``bb.event.DepTreeGenerated()``
+-  ``bb.event.CoreBaseFilesFound()``
+-  ``bb.event.ConfigFilePathFound()``
+-  ``bb.event.FilesMatchingFound()``
+-  ``bb.event.ConfigFilesFound()``
+-  ``bb.event.TargetsTreeGenerated()``
+
+.. _variants-class-extension-mechanism:
+
+Variants - Class Extension Mechanism
+====================================
+
+BitBake supports two features that facilitate creating from a single
+recipe file multiple incarnations of that recipe file where all
+incarnations are buildable. These features are enabled through the
+:term:`BBCLASSEXTEND` and :term:`BBVERSIONS` variables.
+
+.. note::
+
+   The mechanism for this class extension is extremely specific to the
+   implementation. Usually, the recipe's :term:`PROVIDES` , :term:`PN` , and
+   :term:`DEPENDS` variables would need to be modified by the extension
+   class. For specific examples, see the OE-Core native , nativesdk , and
+   multilib classes.
+
+-  ``BBCLASSEXTEND``: This variable is a space separated list of
+   classes used to "extend" the recipe for each variant. Here is an
+   example that results in a second incarnation of the current recipe
+   being available. This second incarnation will have the "native" class
+   inherited. ::
+
+      BBCLASSEXTEND = "native"
+
+-  ``BBVERSIONS``: This variable allows a single recipe to build
+   multiple versions of a project from a single recipe file. You can
+   also specify conditional metadata (using the
+   :term:`OVERRIDES` mechanism) for a single
+   version, or an optionally named range of versions. Here is an
+   example: ::
+
+      BBVERSIONS = "1.0 2.0 git"
+      SRC_URI_git = "git://someurl/somepath.git"
+
+      BBVERSIONS = "1.0.[0-6]:1.0.0+ 1.0.[7-9]:1.0.7+"
+      SRC_URI_append_1.0.7+ = "file://some_patch_which_the_new_versions_need.patch;patch=1"
+
+   The name of the range defaults to the original version of the recipe. For
+   example, in OpenEmbedded, the recipe file ``foo_1.0.0+.bb`` creates a default
+   name range of ``1.0.0+``. This is useful because the range name is not only
+   placed into overrides, but it is also made available for the metadata to use
+   in the variable that defines the base recipe versions for use in ``file://``
+   search paths (:term:`FILESPATH`).
+
+Dependencies
+============
+
+To allow for efficient parallel processing, BitBake handles dependencies
+at the task level. Dependencies can exist both between tasks within a
+single recipe and between tasks in different recipes. Following are
+examples of each:
+
+-  For tasks within a single recipe, a recipe's ``do_configure`` task
+   might need to complete before its ``do_compile`` task can run.
+
+-  For tasks in different recipes, one recipe's ``do_configure`` task
+   might require another recipe's ``do_populate_sysroot`` task to finish
+   first such that the libraries and headers provided by the other
+   recipe are available.
+
+This section describes several ways to declare dependencies. Remember,
+even though dependencies are declared in different ways, they are all
+simply dependencies between tasks.
+
+.. _dependencies-internal-to-the-bb-file:
+
+Dependencies Internal to the ``.bb`` File
+-----------------------------------------
+
+BitBake uses the ``addtask`` directive to manage dependencies that are
+internal to a given recipe file. You can use the ``addtask`` directive
+to indicate when a task is dependent on other tasks or when other tasks
+depend on that recipe. Here is an example: ::
+
+   addtask printdate after do_fetch before do_build
+
+In this example, the ``do_printdate`` task
+depends on the completion of the ``do_fetch`` task, and the ``do_build``
+task depends on the completion of the ``do_printdate`` task.
+
+.. note::
+
+   For a task to run, it must be a direct or indirect dependency of some
+   other task that is scheduled to run.
+
+   For illustration, here are some examples:
+
+   -  The directive ``addtask mytask before do_configure`` causes
+      ``do_mytask`` to run before ``do_configure`` runs. Be aware that
+      ``do_mytask`` still only runs if its :ref:`input
+      checksum <bitbake-user-manual/bitbake-user-manual-execution:checksums (signatures)>` has changed since the last time it was
+      run. Changes to the input checksum of ``do_mytask`` also
+      indirectly cause ``do_configure`` to run.
+
+   -  The directive ``addtask mytask after do_configure`` by itself
+      never causes ``do_mytask`` to run. ``do_mytask`` can still be run
+      manually as follows: ::
+
+         $ bitbake recipe -c mytask
+
+      Declaring ``do_mytask`` as a dependency of some other task that is
+      scheduled to run also causes it to run. Regardless, the task runs after
+      ``do_configure``.
+
+Build Dependencies
+------------------
+
+BitBake uses the :term:`DEPENDS` variable to manage
+build time dependencies. The ``[deptask]`` varflag for tasks signifies
+the task of each item listed in ``DEPENDS`` that must complete before
+that task can be executed. Here is an example: ::
+
+   do_configure[deptask] = "do_populate_sysroot"
+
+In this example, the ``do_populate_sysroot`` task
+of each item in ``DEPENDS`` must complete before ``do_configure`` can
+execute.
+
+Runtime Dependencies
+--------------------
+
+BitBake uses the :term:`PACKAGES`, :term:`RDEPENDS`, and :term:`RRECOMMENDS`
+variables to manage runtime dependencies.
+
+The ``PACKAGES`` variable lists runtime packages. Each of those packages
+can have ``RDEPENDS`` and ``RRECOMMENDS`` runtime dependencies. The
+``[rdeptask]`` flag for tasks is used to signify the task of each item
+runtime dependency which must have completed before that task can be
+executed. ::
+
+   do_package_qa[rdeptask] = "do_packagedata"
+
+In the previous
+example, the ``do_packagedata`` task of each item in ``RDEPENDS`` must
+have completed before ``do_package_qa`` can execute.
+Although ``RDEPENDS`` contains entries from the
+runtime dependency namespace, BitBake knows how to map them back
+to the build-time dependency namespace, in which the tasks are defined.
+
+Recursive Dependencies
+----------------------
+
+BitBake uses the ``[recrdeptask]`` flag to manage recursive task
+dependencies. BitBake looks through the build-time and runtime
+dependencies of the current recipe, looks through the task's inter-task
+dependencies, and then adds dependencies for the listed task. Once
+BitBake has accomplished this, it recursively works through the
+dependencies of those tasks. Iterative passes continue until all
+dependencies are discovered and added.
+
+The ``[recrdeptask]`` flag is most commonly used in high-level recipes
+that need to wait for some task to finish "globally". For example,
+``image.bbclass`` has the following: ::
+
+   do_rootfs[recrdeptask] += "do_packagedata"
+
+This statement says that the ``do_packagedata`` task of
+the current recipe and all recipes reachable (by way of dependencies)
+from the image recipe must run before the ``do_rootfs`` task can run.
+
+BitBake allows a task to recursively depend on itself by
+referencing itself in the task list: ::
+
+   do_a[recrdeptask] = "do_a do_b"
+
+In the same way as before, this means that the ``do_a``
+and ``do_b`` tasks of the current recipe and all
+recipes reachable (by way of dependencies) from the recipe
+must run before the ``do_a`` task can run. In this
+case BitBake will ignore the current recipe's ``do_a``
+task circular dependency on itself.
+
+Inter-Task Dependencies
+-----------------------
+
+BitBake uses the ``[depends]`` flag in a more generic form to manage
+inter-task dependencies. This more generic form allows for
+inter-dependency checks for specific tasks rather than checks for the
+data in ``DEPENDS``. Here is an example: ::
+
+   do_patch[depends] = "quilt-native:do_populate_sysroot"
+
+In this example, the ``do_populate_sysroot`` task of the target ``quilt-native``
+must have completed before the ``do_patch`` task can execute.
+
+The ``[rdepends]`` flag works in a similar way but takes targets in the
+runtime namespace instead of the build-time dependency namespace.
+
+Functions You Can Call From Within Python
+=========================================
+
+BitBake provides many functions you can call from within Python
+functions. This section lists the most commonly used functions, and
+mentions where to find others.
+
+Functions for Accessing Datastore Variables
+-------------------------------------------
+
+It is often necessary to access variables in the BitBake datastore using
+Python functions. The BitBake datastore has an API that allows you this
+access. Here is a list of available operations:
+
+.. list-table::
+   :widths: auto
+   :header-rows: 1
+
+   * - *Operation*
+     - *Description*
+   * - ``d.getVar("X", expand)``
+     - Returns the value of variable "X". Using "expand=True" expands the
+       value. Returns "None" if the variable "X" does not exist.
+   * - ``d.setVar("X", "value")``
+     - Sets the variable "X" to "value"
+   * - ``d.appendVar("X", "value")``
+     - Adds "value" to the end of the variable "X". Acts like ``d.setVar("X",
+       "value")`` if the variable "X" does not exist.
+   * - ``d.prependVar("X", "value")``
+     - Adds "value" to the start of the variable "X". Acts like
+       ``d.setVar("X","value")`` if the variable "X" does not exist.
+   * - ``d.delVar("X")``
+     - Deletes the variable "X" from the datastore. Does nothing if the variable
+       "X" does not exist.
+   * - ``d.renameVar("X", "Y")``
+     - Renames the variable "X" to "Y". Does nothing if the variable "X" does
+       not exist.
+   * - ``d.getVarFlag("X", flag, expand)``
+     - Returns the value of variable "X". Using "expand=True" expands the
+       value. Returns "None" if either the variable "X" or the named flag does
+       not exist.
+   * - ``d.setVarFlag("X", flag, "value")``
+     - Sets the named flag for variable "X" to "value".
+   * - ``d.appendVarFlag("X", flag, "value")``
+     - Appends "value" to the named flag on the variable "X". Acts like
+       ``d.setVarFlag("X", flag, "value")`` if the named flag does not exist.
+   * - ``d.prependVarFlag("X", flag, "value")``
+     - Prepends "value" to the named flag on the variable "X". Acts like
+       ``d.setVarFlag("X", flag, "value")`` if the named flag does not exist.
+   * - ``d.delVarFlag("X", flag)``
+     - Deletes the named flag on the variable "X" from the datastore.
+   * - ``d.setVarFlags("X", flagsdict)``
+     - Sets the flags specified in the ``flagsdict()``
+       parameter. ``setVarFlags`` does not clear previous flags. Think of this
+       operation as ``addVarFlags``.
+   * - ``d.getVarFlags("X")``
+     - Returns a ``flagsdict`` of the flags for the variable "X". Returns "None"
+       if the variable "X" does not exist.
+   * - ``d.delVarFlags("X")``
+     - Deletes all the flags for the variable "X". Does nothing if the variable
+       "X" does not exist.
+   * - ``d.expand(expression)``
+     - Expands variable references in the specified string
+       expression. References to variables that do not exist are left as is. For
+       example, ``d.expand("foo ${X}")`` expands to the literal string "foo
+       ${X}" if the variable "X" does not exist.
+
+Other Functions
+---------------
+
+You can find many other functions that can be called from Python by
+looking at the source code of the ``bb`` module, which is in
+``bitbake/lib/bb``. For example, ``bitbake/lib/bb/utils.py`` includes
+the commonly used functions ``bb.utils.contains()`` and
+``bb.utils.mkdirhier()``, which come with docstrings.
+
+Task Checksums and Setscene
+===========================
+
+BitBake uses checksums (or signatures) along with the setscene to
+determine if a task needs to be run. This section describes the process.
+To help understand how BitBake does this, the section assumes an
+OpenEmbedded metadata-based example.
+
+These checksums are stored in :term:`STAMP`. You can
+examine the checksums using the following BitBake command: ::
+
+   $ bitbake-dumpsigs
+
+This command returns the signature data in a readable
+format that allows you to examine the inputs used when the OpenEmbedded
+build system generates signatures. For example, using
+``bitbake-dumpsigs`` allows you to examine the ``do_compile`` task's
+"sigdata" for a C application (e.g. ``bash``). Running the command also
+reveals that the "CC" variable is part of the inputs that are hashed.
+Any changes to this variable would invalidate the stamp and cause the
+``do_compile`` task to run.
+
+The following list describes related variables:
+
+-  :term:`BB_HASHCHECK_FUNCTION`:
+   Specifies the name of the function to call during the "setscene" part
+   of the task's execution in order to validate the list of task hashes.
+
+-  :term:`BB_SETSCENE_DEPVALID`:
+   Specifies a function BitBake calls that determines whether BitBake
+   requires a setscene dependency to be met.
+
+-  :term:`BB_SETSCENE_VERIFY_FUNCTION2`:
+   Specifies a function to call that verifies the list of planned task
+   execution before the main task execution happens.
+
+-  :term:`BB_STAMP_POLICY`: Defines the mode
+   for comparing timestamps of stamp files.
+
+-  :term:`BB_STAMP_WHITELIST`: Lists stamp
+   files that are looked at when the stamp policy is "whitelist".
+
+-  :term:`BB_TASKHASH`: Within an executing task,
+   this variable holds the hash of the task as returned by the currently
+   enabled signature generator.
+
+-  :term:`STAMP`: The base path to create stamp files.
+
+-  :term:`STAMPCLEAN`: Again, the base path to
+   create stamp files but can use wildcards for matching a range of
+   files for clean operations.
+
+Wildcard Support in Variables
+=============================
+
+Support for wildcard use in variables varies depending on the context in
+which it is used. For example, some variables and file names allow
+limited use of wildcards through the "``%``" and "``*``" characters.
+Other variables or names support Python's
+`glob <https://docs.python.org/3/library/glob.html>`_ syntax,
+`fnmatch <https://docs.python.org/3/library/fnmatch.html#module-fnmatch>`_
+syntax, or
+`Regular Expression (re) <https://docs.python.org/3/library/re.html>`_
+syntax.
+
+For variables that have wildcard suport, the documentation describes
+which form of wildcard, its use, and its limitations.

+ 1372 - 0
openembedded-core/bitbake/doc/bitbake-user-manual/bitbake-user-manual-ref-variables.rst

@@ -0,0 +1,1372 @@
+.. SPDX-License-Identifier: CC-BY-2.5
+
+==================
+Variables Glossary
+==================
+
+|
+
+This chapter lists common variables used by BitBake and gives an
+overview of their function and contents.
+
+.. note::
+
+   Following are some points regarding the variables listed in this
+   glossary:
+
+   -  The variables listed in this glossary are specific to BitBake.
+      Consequently, the descriptions are limited to that context.
+
+   -  Also, variables exist in other systems that use BitBake (e.g. The
+      Yocto Project and OpenEmbedded) that have names identical to those
+      found in this glossary. For such cases, the variables in those
+      systems extend the functionality of the variable as it is
+      described here in this glossary.
+
+   -  Finally, there are variables mentioned in this glossary that do
+      not appear in the BitBake glossary. These other variables are
+      variables used in systems that use BitBake.
+
+.. glossary::
+
+   :term:`ASSUME_PROVIDED`
+      Lists recipe names (:term:`PN` values) BitBake does not
+      attempt to build. Instead, BitBake assumes these recipes have already
+      been built.
+
+      In OpenEmbedded-Core, ``ASSUME_PROVIDED`` mostly specifies native
+      tools that should not be built. An example is ``git-native``, which
+      when specified allows for the Git binary from the host to be used
+      rather than building ``git-native``.
+
+   :term:`B`
+      The directory in which BitBake executes functions during a recipe's
+      build process.
+
+   :term:`BB_ALLOWED_NETWORKS`
+      Specifies a space-delimited list of hosts that the fetcher is allowed
+      to use to obtain the required source code. Following are
+      considerations surrounding this variable:
+
+      -  This host list is only used if
+         :term:`BB_NO_NETWORK` is either not set or
+         set to "0".
+
+      -  Limited support for the "``*``" wildcard character for matching
+         against the beginning of host names exists. For example, the
+         following setting matches ``git.gnu.org``, ``ftp.gnu.org``, and
+         ``foo.git.gnu.org``. ::
+
+            BB_ALLOWED_NETWORKS = "\*.gnu.org"
+
+         .. important::
+
+            The use of the "``*``" character only works at the beginning of
+            a host name and it must be isolated from the remainder of the
+            host name. You cannot use the wildcard character in any other
+            location of the name or combined with the front part of the
+            name.
+
+            For example, ``*.foo.bar`` is supported, while ``*aa.foo.bar``
+            is not.
+
+      -  Mirrors not in the host list are skipped and logged in debug.
+
+      -  Attempts to access networks not in the host list cause a failure.
+
+      Using ``BB_ALLOWED_NETWORKS`` in conjunction with
+      :term:`PREMIRRORS` is very useful. Adding the
+      host you want to use to ``PREMIRRORS`` results in the source code
+      being fetched from an allowed location and avoids raising an error
+      when a host that is not allowed is in a
+      :term:`SRC_URI` statement. This is because the
+      fetcher does not attempt to use the host listed in ``SRC_URI`` after
+      a successful fetch from the ``PREMIRRORS`` occurs.
+
+   :term:`BB_CONSOLELOG`
+      Specifies the path to a log file into which BitBake's user interface
+      writes output during the build.
+
+   :term:`BB_CURRENTTASK`
+      Contains the name of the currently running task. The name does not
+      include the ``do_`` prefix.
+
+   :term:`BB_DANGLINGAPPENDS_WARNONLY`
+      Defines how BitBake handles situations where an append file
+      (``.bbappend``) has no corresponding recipe file (``.bb``). This
+      condition often occurs when layers get out of sync (e.g. ``oe-core``
+      bumps a recipe version and the old recipe no longer exists and the
+      other layer has not been updated to the new version of the recipe
+      yet).
+
+      The default fatal behavior is safest because it is the sane reaction
+      given something is out of sync. It is important to realize when your
+      changes are no longer being applied.
+
+   :term:`BB_DEFAULT_TASK`
+      The default task to use when none is specified (e.g. with the ``-c``
+      command line option). The task name specified should not include the
+      ``do_`` prefix.
+
+   :term:`BB_DISKMON_DIRS`
+      Monitors disk space and available inodes during the build and allows
+      you to control the build based on these parameters.
+
+      Disk space monitoring is disabled by default. When setting this
+      variable, use the following form: ::
+
+         BB_DISKMON_DIRS = "<action>,<dir>,<threshold> [...]"
+
+         where:
+
+            <action> is:
+               ABORT:     Immediately abort the build when
+                          a threshold is broken.
+               STOPTASKS: Stop the build after the currently
+                          executing tasks have finished when
+                          a threshold is broken.
+               WARN:      Issue a warning but continue the
+                          build when a threshold is broken.
+                          Subsequent warnings are issued as
+                          defined by the
+                          BB_DISKMON_WARNINTERVAL variable,
+                          which must be defined.
+
+            <dir> is:
+               Any directory you choose. You can specify one or
+               more directories to monitor by separating the
+               groupings with a space.  If two directories are
+               on the same device, only the first directory
+               is monitored.
+
+            <threshold> is:
+               Either the minimum available disk space,
+               the minimum number of free inodes, or
+               both.  You must specify at least one.  To
+               omit one or the other, simply omit the value.
+               Specify the threshold using G, M, K for Gbytes,
+               Mbytes, and Kbytes, respectively. If you do
+               not specify G, M, or K, Kbytes is assumed by
+               default.  Do not use GB, MB, or KB.
+
+      Here are some examples: ::
+
+         BB_DISKMON_DIRS = "ABORT,${TMPDIR},1G,100K WARN,${SSTATE_DIR},1G,100K"
+         BB_DISKMON_DIRS = "STOPTASKS,${TMPDIR},1G"
+         BB_DISKMON_DIRS = "ABORT,${TMPDIR},,100K"
+
+      The first example works only if you also set the
+      :term:`BB_DISKMON_WARNINTERVAL`
+      variable. This example causes the build system to immediately abort
+      when either the disk space in ``${TMPDIR}`` drops below 1 Gbyte or
+      the available free inodes drops below 100 Kbytes. Because two
+      directories are provided with the variable, the build system also
+      issues a warning when the disk space in the ``${SSTATE_DIR}``
+      directory drops below 1 Gbyte or the number of free inodes drops
+      below 100 Kbytes. Subsequent warnings are issued during intervals as
+      defined by the ``BB_DISKMON_WARNINTERVAL`` variable.
+
+      The second example stops the build after all currently executing
+      tasks complete when the minimum disk space in the ``${TMPDIR}``
+      directory drops below 1 Gbyte. No disk monitoring occurs for the free
+      inodes in this case.
+
+      The final example immediately aborts the build when the number of
+      free inodes in the ``${TMPDIR}`` directory drops below 100 Kbytes. No
+      disk space monitoring for the directory itself occurs in this case.
+
+   :term:`BB_DISKMON_WARNINTERVAL`
+      Defines the disk space and free inode warning intervals.
+
+      If you are going to use the ``BB_DISKMON_WARNINTERVAL`` variable, you
+      must also use the :term:`BB_DISKMON_DIRS`
+      variable and define its action as "WARN". During the build,
+      subsequent warnings are issued each time disk space or number of free
+      inodes further reduces by the respective interval.
+
+      If you do not provide a ``BB_DISKMON_WARNINTERVAL`` variable and you
+      do use ``BB_DISKMON_DIRS`` with the "WARN" action, the disk
+      monitoring interval defaults to the following:
+      BB_DISKMON_WARNINTERVAL = "50M,5K"
+
+      When specifying the variable in your configuration file, use the
+      following form: ::
+
+         BB_DISKMON_WARNINTERVAL = "<disk_space_interval>,<disk_inode_interval>"
+
+         where:
+
+            <disk_space_interval> is:
+               An interval of memory expressed in either
+               G, M, or K for Gbytes, Mbytes, or Kbytes,
+               respectively. You cannot use GB, MB, or KB.
+
+            <disk_inode_interval> is:
+               An interval of free inodes expressed in either
+               G, M, or K for Gbytes, Mbytes, or Kbytes,
+               respectively. You cannot use GB, MB, or KB.
+
+      Here is an example: ::
+
+         BB_DISKMON_DIRS = "WARN,${SSTATE_DIR},1G,100K"
+         BB_DISKMON_WARNINTERVAL = "50M,5K"
+
+      These variables cause BitBake to
+      issue subsequent warnings each time the available disk space further
+      reduces by 50 Mbytes or the number of free inodes further reduces by
+      5 Kbytes in the ``${SSTATE_DIR}`` directory. Subsequent warnings
+      based on the interval occur each time a respective interval is
+      reached beyond the initial warning (i.e. 1 Gbytes and 100 Kbytes).
+
+   :term:`BB_ENV_WHITELIST`
+      Specifies the internal whitelist of variables to allow through from
+      the external environment into BitBake's datastore. If the value of
+      this variable is not specified (which is the default), the following
+      list is used: :term:`BBPATH`, :term:`BB_PRESERVE_ENV`,
+      :term:`BB_ENV_WHITELIST`, and :term:`BB_ENV_EXTRAWHITE`.
+
+      .. note::
+
+         You must set this variable in the external environment in order
+         for it to work.
+
+   :term:`BB_ENV_EXTRAWHITE`
+      Specifies an additional set of variables to allow through (whitelist)
+      from the external environment into BitBake's datastore. This list of
+      variables are on top of the internal list set in
+      :term:`BB_ENV_WHITELIST`.
+
+      .. note::
+
+         You must set this variable in the external environment in order
+         for it to work.
+
+   :term:`BB_FETCH_PREMIRRORONLY`
+      When set to "1", causes BitBake's fetcher module to only search
+      :term:`PREMIRRORS` for files. BitBake will not
+      search the main :term:`SRC_URI` or
+      :term:`MIRRORS`.
+
+   :term:`BB_FILENAME`
+      Contains the filename of the recipe that owns the currently running
+      task. For example, if the ``do_fetch`` task that resides in the
+      ``my-recipe.bb`` is executing, the ``BB_FILENAME`` variable contains
+      "/foo/path/my-recipe.bb".
+
+   :term:`BBFILES_DYNAMIC`
+      Activates content depending on presence of identified layers.  You
+      identify the layers by the collections that the layers define.
+
+      Use the ``BBFILES_DYNAMIC`` variable to avoid ``.bbappend`` files whose
+      corresponding ``.bb`` file is in a layer that attempts to modify other
+      layers through ``.bbappend`` but does not want to introduce a hard
+      dependency on those other layers.
+
+      Additionally you can prefix the rule with "!" to add ``.bbappend`` and
+      ``.bb`` files in case a layer is not present.  Use this avoid hard
+      dependency on those other layers.
+
+      Use the following form for ``BBFILES_DYNAMIC``: ::
+
+         collection_name:filename_pattern
+
+      The following example identifies two collection names and two filename
+      patterns: ::
+
+         BBFILES_DYNAMIC += "\
+             clang-layer:${LAYERDIR}/bbappends/meta-clang/*/*/*.bbappend \
+             core:${LAYERDIR}/bbappends/openembedded-core/meta/*/*/*.bbappend \
+         "
+
+      When the collection name is prefixed with "!" it will add the file pattern in case
+      the layer is absent: ::
+
+         BBFILES_DYNAMIC += "\
+             !clang-layer:${LAYERDIR}/backfill/meta-clang/*/*/*.bb \
+         "
+
+      This next example shows an error message that occurs because invalid
+      entries are found, which cause parsing to abort: ::
+
+         ERROR: BBFILES_DYNAMIC entries must be of the form {!}<collection name>:<filename pattern>, not:
+         /work/my-layer/bbappends/meta-security-isafw/*/*/*.bbappend
+         /work/my-layer/bbappends/openembedded-core/meta/*/*/*.bbappend
+
+   :term:`BB_GENERATE_MIRROR_TARBALLS`
+      Causes tarballs of the Git repositories, including the Git metadata,
+      to be placed in the :term:`DL_DIR` directory. Anyone
+      wishing to create a source mirror would want to enable this variable.
+
+      For performance reasons, creating and placing tarballs of the Git
+      repositories is not the default action by BitBake. ::
+
+         BB_GENERATE_MIRROR_TARBALLS = "1"
+
+   :term:`BB_HASHCONFIG_WHITELIST`
+      Lists variables that are excluded from base configuration checksum,
+      which is used to determine if the cache can be reused.
+
+      One of the ways BitBake determines whether to re-parse the main
+      metadata is through checksums of the variables in the datastore of
+      the base configuration data. There are variables that you typically
+      want to exclude when checking whether or not to re-parse and thus
+      rebuild the cache. As an example, you would usually exclude ``TIME``
+      and ``DATE`` because these variables are always changing. If you did
+      not exclude them, BitBake would never reuse the cache.
+
+   :term:`BB_HASHBASE_WHITELIST`
+      Lists variables that are excluded from checksum and dependency data.
+      Variables that are excluded can therefore change without affecting
+      the checksum mechanism. A common example would be the variable for
+      the path of the build. BitBake's output should not (and usually does
+      not) depend on the directory in which it was built.
+
+   :term:`BB_HASHCHECK_FUNCTION`
+      Specifies the name of the function to call during the "setscene" part
+      of the task's execution in order to validate the list of task hashes.
+      The function returns the list of setscene tasks that should be
+      executed.
+
+      At this point in the execution of the code, the objective is to
+      quickly verify if a given setscene function is likely to work or not.
+      It's easier to check the list of setscene functions in one pass than
+      to call many individual tasks. The returned list need not be
+      completely accurate. A given setscene task can still later fail.
+      However, the more accurate the data returned, the more efficient the
+      build will be.
+
+   :term:`BB_INVALIDCONF`
+      Used in combination with the ``ConfigParsed`` event to trigger
+      re-parsing the base metadata (i.e. all the recipes). The
+      ``ConfigParsed`` event can set the variable to trigger the re-parse.
+      You must be careful to avoid recursive loops with this functionality.
+
+   :term:`BB_LOGCONFIG`
+      Specifies the name of a config file that contains the user logging
+      configuration. See
+      :ref:`bitbake-user-manual/bitbake-user-manual-execution:logging`
+      for additional information
+
+   :term:`BB_LOGFMT`
+      Specifies the name of the log files saved into
+      ``${``\ :term:`T`\ ``}``. By default, the ``BB_LOGFMT``
+      variable is undefined and the log file names get created using the
+      following form: ::
+
+         log.{task}.{pid}
+
+      If you want to force log files to take a specific name, you can set this
+      variable in a configuration file.
+
+   :term:`BB_NICE_LEVEL`
+      Allows BitBake to run at a specific priority (i.e. nice level).
+      System permissions usually mean that BitBake can reduce its priority
+      but not raise it again. See :term:`BB_TASK_NICE_LEVEL` for
+      additional information.
+
+   :term:`BB_NO_NETWORK`
+      Disables network access in the BitBake fetcher modules. With this
+      access disabled, any command that attempts to access the network
+      becomes an error.
+
+      Disabling network access is useful for testing source mirrors,
+      running builds when not connected to the Internet, and when operating
+      in certain kinds of firewall environments.
+
+   :term:`BB_NUMBER_THREADS`
+      The maximum number of tasks BitBake should run in parallel at any one
+      time. If your host development system supports multiple cores, a good
+      rule of thumb is to set this variable to twice the number of cores.
+
+   :term:`BB_NUMBER_PARSE_THREADS`
+      Sets the number of threads BitBake uses when parsing. By default, the
+      number of threads is equal to the number of cores on the system.
+
+   :term:`BB_ORIGENV`
+      Contains a copy of the original external environment in which BitBake
+      was run. The copy is taken before any whitelisted variable values are
+      filtered into BitBake's datastore.
+
+      .. note::
+
+         The contents of this variable is a datastore object that can be
+         queried using the normal datastore operations.
+
+   :term:`BB_PRESERVE_ENV`
+      Disables whitelisting and instead allows all variables through from
+      the external environment into BitBake's datastore.
+
+      .. note::
+
+         You must set this variable in the external environment in order
+         for it to work.
+
+   :term:`BB_RUNFMT`
+      Specifies the name of the executable script files (i.e. run files)
+      saved into ``${``\ :term:`T`\ ``}``. By default, the
+      ``BB_RUNFMT`` variable is undefined and the run file names get
+      created using the following form: ::
+
+         run.{task}.{pid}
+
+      If you want to force run files to take a specific name, you can set this
+      variable in a configuration file.
+
+   :term:`BB_RUNTASK`
+      Contains the name of the currently executing task. The value includes
+      the "do\_" prefix. For example, if the currently executing task is
+      ``do_config``, the value is "do_config".
+
+   :term:`BB_SCHEDULER`
+      Selects the name of the scheduler to use for the scheduling of
+      BitBake tasks. Three options exist:
+
+      -  *basic* - The basic framework from which everything derives. Using
+         this option causes tasks to be ordered numerically as they are
+         parsed.
+
+      -  *speed* - Executes tasks first that have more tasks depending on
+         them. The "speed" option is the default.
+
+      -  *completion* - Causes the scheduler to try to complete a given
+         recipe once its build has started.
+
+   :term:`BB_SCHEDULERS`
+      Defines custom schedulers to import. Custom schedulers need to be
+      derived from the ``RunQueueScheduler`` class.
+
+      For information how to select a scheduler, see the
+      :term:`BB_SCHEDULER` variable.
+
+   :term:`BB_SETSCENE_DEPVALID`
+      Specifies a function BitBake calls that determines whether BitBake
+      requires a setscene dependency to be met.
+
+      When running a setscene task, BitBake needs to know which
+      dependencies of that setscene task also need to be run. Whether
+      dependencies also need to be run is highly dependent on the metadata.
+      The function specified by this variable returns a "True" or "False"
+      depending on whether the dependency needs to be met.
+
+   :term:`BB_SETSCENE_VERIFY_FUNCTION2`
+      Specifies a function to call that verifies the list of planned task
+      execution before the main task execution happens. The function is
+      called once BitBake has a list of setscene tasks that have run and
+      either succeeded or failed.
+
+      The function allows for a task list check to see if they make sense.
+      Even if BitBake was planning to skip a task, the returned value of
+      the function can force BitBake to run the task, which is necessary
+      under certain metadata defined circumstances.
+
+   :term:`BB_SIGNATURE_EXCLUDE_FLAGS`
+      Lists variable flags (varflags) that can be safely excluded from
+      checksum and dependency data for keys in the datastore. When
+      generating checksum or dependency data for keys in the datastore, the
+      flags set against that key are normally included in the checksum.
+
+      For more information on varflags, see the
+      ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:variable flags`"
+      section.
+
+   :term:`BB_SIGNATURE_HANDLER`
+      Defines the name of the signature handler BitBake uses. The signature
+      handler defines the way stamp files are created and handled, if and
+      how the signature is incorporated into the stamps, and how the
+      signature itself is generated.
+
+      A new signature handler can be added by injecting a class derived
+      from the ``SignatureGenerator`` class into the global namespace.
+
+   :term:`BB_SRCREV_POLICY`
+      Defines the behavior of the fetcher when it interacts with source
+      control systems and dynamic source revisions. The
+      ``BB_SRCREV_POLICY`` variable is useful when working without a
+      network.
+
+      The variable can be set using one of two policies:
+
+      -  *cache* - Retains the value the system obtained previously rather
+         than querying the source control system each time.
+
+      -  *clear* - Queries the source controls system every time. With this
+         policy, there is no cache. The "clear" policy is the default.
+
+   :term:`BB_STAMP_POLICY`
+      Defines the mode used for how timestamps of stamp files are compared.
+      You can set the variable to one of the following modes:
+
+      -  *perfile* - Timestamp comparisons are only made between timestamps
+         of a specific recipe. This is the default mode.
+
+      -  *full* - Timestamp comparisons are made for all dependencies.
+
+      -  *whitelist* - Identical to "full" mode except timestamp
+         comparisons are made for recipes listed in the
+         :term:`BB_STAMP_WHITELIST` variable.
+
+      .. note::
+
+         Stamp policies are largely obsolete with the introduction of
+         setscene tasks.
+
+   :term:`BB_STAMP_WHITELIST`
+      Lists files whose stamp file timestamps are compared when the stamp
+      policy mode is set to "whitelist". For information on stamp policies,
+      see the :term:`BB_STAMP_POLICY` variable.
+
+   :term:`BB_STRICT_CHECKSUM`
+      Sets a more strict checksum mechanism for non-local URLs. Setting
+      this variable to a value causes BitBake to report an error if it
+      encounters a non-local URL that does not have at least one checksum
+      specified.
+
+   :term:`BB_TASK_IONICE_LEVEL`
+      Allows adjustment of a task's Input/Output priority. During
+      Autobuilder testing, random failures can occur for tasks due to I/O
+      starvation. These failures occur during various QEMU runtime
+      timeouts. You can use the ``BB_TASK_IONICE_LEVEL`` variable to adjust
+      the I/O priority of these tasks.
+
+      .. note::
+
+         This variable works similarly to the :term:`BB_TASK_NICE_LEVEL`
+         variable except with a task's I/O priorities.
+
+      Set the variable as follows: ::
+
+         BB_TASK_IONICE_LEVEL = "class.prio"
+
+      For *class*, the default value is "2", which is a best effort. You can use
+      "1" for realtime and "3" for idle. If you want to use realtime, you
+      must have superuser privileges.
+
+      For *prio*, you can use any value from "0", which is the highest
+      priority, to "7", which is the lowest. The default value is "4". You
+      do not need any special privileges to use this range of priority
+      values.
+
+      .. note::
+
+         In order for your I/O priority settings to take effect, you need the
+         Completely Fair Queuing (CFQ) Scheduler selected for the backing block
+         device. To select the scheduler, use the following command form where
+         device is the device (e.g. sda, sdb, and so forth): ::
+
+            $ sudo sh -c "echo cfq > /sys/block/device/queu/scheduler"
+
+   :term:`BB_TASK_NICE_LEVEL`
+      Allows specific tasks to change their priority (i.e. nice level).
+
+      You can use this variable in combination with task overrides to raise
+      or lower priorities of specific tasks. For example, on the `Yocto
+      Project <http://www.yoctoproject.org>`__ autobuilder, QEMU emulation
+      in images is given a higher priority as compared to build tasks to
+      ensure that images do not suffer timeouts on loaded systems.
+
+   :term:`BB_TASKHASH`
+      Within an executing task, this variable holds the hash of the task as
+      returned by the currently enabled signature generator.
+
+   :term:`BB_VERBOSE_LOGS`
+      Controls how verbose BitBake is during builds. If set, shell scripts
+      echo commands and shell script output appears on standard out
+      (stdout).
+
+   :term:`BB_WORKERCONTEXT`
+      Specifies if the current context is executing a task. BitBake sets
+      this variable to "1" when a task is being executed. The value is not
+      set when the task is in server context during parsing or event
+      handling.
+
+   :term:`BBCLASSEXTEND`
+      Allows you to extend a recipe so that it builds variants of the
+      software. Some examples of these variants for recipes from the
+      OpenEmbedded-Core metadata are "natives" such as ``quilt-native``,
+      which is a copy of Quilt built to run on the build system; "crosses"
+      such as ``gcc-cross``, which is a compiler built to run on the build
+      machine but produces binaries that run on the target ``MACHINE``;
+      "nativesdk", which targets the SDK machine instead of ``MACHINE``;
+      and "mulitlibs" in the form "``multilib:``\ multilib_name".
+
+      To build a different variant of the recipe with a minimal amount of
+      code, it usually is as simple as adding the variable to your recipe.
+      Here are two examples. The "native" variants are from the
+      OpenEmbedded-Core metadata: ::
+
+         BBCLASSEXTEND =+ "native nativesdk"
+         BBCLASSEXTEND =+ "multilib:multilib_name"
+
+      .. note::
+
+         Internally, the ``BBCLASSEXTEND`` mechanism generates recipe
+         variants by rewriting variable values and applying overrides such
+         as ``_class-native``. For example, to generate a native version of
+         a recipe, a :term:`DEPENDS` on "foo" is
+         rewritten to a ``DEPENDS`` on "foo-native".
+
+         Even when using ``BBCLASSEXTEND``, the recipe is only parsed once.
+         Parsing once adds some limitations. For example, it is not
+         possible to include a different file depending on the variant,
+         since ``include`` statements are processed when the recipe is
+         parsed.
+
+   :term:`BBDEBUG`
+      Sets the BitBake debug output level to a specific value as
+      incremented by the ``-D`` command line option.
+
+      .. note::
+
+         You must set this variable in the external environment in order
+         for it to work.
+
+   :term:`BBFILE_COLLECTIONS`
+      Lists the names of configured layers. These names are used to find
+      the other ``BBFILE_*`` variables. Typically, each layer appends its
+      name to this variable in its ``conf/layer.conf`` file.
+
+   :term:`BBFILE_PATTERN`
+      Variable that expands to match files from
+      :term:`BBFILES` in a particular layer. This
+      variable is used in the ``conf/layer.conf`` file and must be suffixed
+      with the name of the specific layer (e.g.
+      ``BBFILE_PATTERN_emenlow``).
+
+   :term:`BBFILE_PRIORITY`
+      Assigns the priority for recipe files in each layer.
+
+      This variable is useful in situations where the same recipe appears
+      in more than one layer. Setting this variable allows you to
+      prioritize a layer against other layers that contain the same recipe
+      - effectively letting you control the precedence for the multiple
+      layers. The precedence established through this variable stands
+      regardless of a recipe's version (:term:`PV` variable).
+      For example, a layer that has a recipe with a higher ``PV`` value but
+      for which the ``BBFILE_PRIORITY`` is set to have a lower precedence
+      still has a lower precedence.
+
+      A larger value for the ``BBFILE_PRIORITY`` variable results in a
+      higher precedence. For example, the value 6 has a higher precedence
+      than the value 5. If not specified, the ``BBFILE_PRIORITY`` variable
+      is set based on layer dependencies (see the ``LAYERDEPENDS`` variable
+      for more information. The default priority, if unspecified for a
+      layer with no dependencies, is the lowest defined priority + 1 (or 1
+      if no priorities are defined).
+
+      .. tip::
+
+         You can use the command bitbake-layers show-layers to list all
+         configured layers along with their priorities.
+
+   :term:`BBFILES`
+      A space-separated list of recipe files BitBake uses to build
+      software.
+
+      When specifying recipe files, you can pattern match using Python's
+      `glob <https://docs.python.org/3/library/glob.html>`_ syntax.
+      For details on the syntax, see the documentation by following the
+      previous link.
+
+   :term:`BBINCLUDED`
+      Contains a space-separated list of all of all files that BitBake's
+      parser included during parsing of the current file.
+
+   :term:`BBINCLUDELOGS`
+      If set to a value, enables printing the task log when reporting a
+      failed task.
+
+   :term:`BBINCLUDELOGS_LINES`
+      If :term:`BBINCLUDELOGS` is set, specifies
+      the maximum number of lines from the task log file to print when
+      reporting a failed task. If you do not set ``BBINCLUDELOGS_LINES``,
+      the entire log is printed.
+
+   :term:`BBLAYERS`
+      Lists the layers to enable during the build. This variable is defined
+      in the ``bblayers.conf`` configuration file in the build directory.
+      Here is an example: ::
+
+         BBLAYERS = " \
+             /home/scottrif/poky/meta \
+             /home/scottrif/poky/meta-yocto \
+             /home/scottrif/poky/meta-yocto-bsp \
+             /home/scottrif/poky/meta-mykernel \
+         "
+
+      This example enables four layers, one of which is a custom, user-defined
+      layer named ``meta-mykernel``.
+
+   :term:`BBLAYERS_FETCH_DIR`
+      Sets the base location where layers are stored. This setting is used
+      in conjunction with ``bitbake-layers layerindex-fetch`` and tells
+      ``bitbake-layers`` where to place the fetched layers.
+
+   :term:`BBMASK`
+      Prevents BitBake from processing recipes and recipe append files.
+
+      You can use the ``BBMASK`` variable to "hide" these ``.bb`` and
+      ``.bbappend`` files. BitBake ignores any recipe or recipe append
+      files that match any of the expressions. It is as if BitBake does not
+      see them at all. Consequently, matching files are not parsed or
+      otherwise used by BitBake.
+
+      The values you provide are passed to Python's regular expression
+      compiler. Consequently, the syntax follows Python's Regular
+      Expression (re) syntax. The expressions are compared against the full
+      paths to the files. For complete syntax information, see Python's
+      documentation at http://docs.python.org/3/library/re.html.
+
+      The following example uses a complete regular expression to tell
+      BitBake to ignore all recipe and recipe append files in the
+      ``meta-ti/recipes-misc/`` directory: ::
+
+         BBMASK = "meta-ti/recipes-misc/"
+
+      If you want to mask out multiple directories or recipes, you can
+      specify multiple regular expression fragments. This next example
+      masks out multiple directories and individual recipes: ::
+
+         BBMASK += "/meta-ti/recipes-misc/ meta-ti/recipes-ti/packagegroup/"
+         BBMASK += "/meta-oe/recipes-support/"
+         BBMASK += "/meta-foo/.*/openldap"
+         BBMASK += "opencv.*\.bbappend"
+         BBMASK += "lzma"
+
+      .. note::
+
+         When specifying a directory name, use the trailing slash character
+         to ensure you match just that directory name.
+
+   :term:`BBMULTICONFIG`
+      Enables BitBake to perform multiple configuration builds and lists
+      each separate configuration (multiconfig). You can use this variable
+      to cause BitBake to build multiple targets where each target has a
+      separate configuration. Define ``BBMULTICONFIG`` in your
+      ``conf/local.conf`` configuration file.
+
+      As an example, the following line specifies three multiconfigs, each
+      having a separate configuration file: ::
+
+         BBMULTIFONFIG = "configA configB configC"
+
+      Each configuration file you use must reside in the
+      build directory within a directory named ``conf/multiconfig`` (e.g.
+      build_directory\ ``/conf/multiconfig/configA.conf``).
+
+      For information on how to use ``BBMULTICONFIG`` in an environment
+      that supports building targets with multiple configurations, see the
+      ":ref:`bitbake-user-manual/bitbake-user-manual-intro:executing a multiple configuration build`"
+      section.
+
+   :term:`BBPATH`
+      Used by BitBake to locate class (``.bbclass``) and configuration
+      (``.conf``) files. This variable is analogous to the ``PATH``
+      variable.
+
+      If you run BitBake from a directory outside of the build directory,
+      you must be sure to set ``BBPATH`` to point to the build directory.
+      Set the variable as you would any environment variable and then run
+      BitBake: ::
+
+         $ BBPATH="build_directory"
+         $ export BBPATH
+         $ bitbake target
+
+   :term:`BBSERVER`
+      Points to the server that runs memory-resident BitBake. The variable
+      is only used when you employ memory-resident BitBake.
+
+   :term:`BBTARGETS`
+      Allows you to use a configuration file to add to the list of
+      command-line target recipes you want to build.
+
+   :term:`BBVERSIONS`
+      Allows a single recipe to build multiple versions of a project from a
+      single recipe file. You also able to specify conditional metadata
+      using the :term:`OVERRIDES` mechanism for a
+      single version or for an optionally named range of versions.
+
+      For more information on ``BBVERSIONS``, see the
+      ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:variants - class extension mechanism`"
+      section.
+
+   :term:`BITBAKE_UI`
+      Used to specify the UI module to use when running BitBake. Using this
+      variable is equivalent to using the ``-u`` command-line option.
+
+      .. note::
+
+         You must set this variable in the external environment in order
+         for it to work.
+
+   :term:`BUILDNAME`
+      A name assigned to the build. The name defaults to a datetime stamp
+      of when the build was started but can be defined by the metadata.
+
+   :term:`BZRDIR`
+      The directory in which files checked out of a Bazaar system are
+      stored.
+
+   :term:`CACHE`
+      Specifies the directory BitBake uses to store a cache of the metadata
+      so it does not need to be parsed every time BitBake is started.
+
+   :term:`CVSDIR`
+      The directory in which files checked out under the CVS system are
+      stored.
+
+   :term:`DEFAULT_PREFERENCE`
+      Specifies a weak bias for recipe selection priority.
+
+      The most common usage of this is variable is to set it to "-1" within
+      a recipe for a development version of a piece of software. Using the
+      variable in this way causes the stable version of the recipe to build
+      by default in the absence of ``PREFERRED_VERSION`` being used to
+      build the development version.
+
+      .. note::
+
+         The bias provided by DEFAULT_PREFERENCE is weak and is overridden by
+         :term:`BBFILE_PRIORITY` if that variable is different between two
+         layers that contain different versions of the same recipe.
+
+   :term:`DEPENDS`
+      Lists a recipe's build-time dependencies (i.e. other recipe files).
+
+      Consider this simple example for two recipes named "a" and "b" that
+      produce similarly named packages. In this example, the ``DEPENDS``
+      statement appears in the "a" recipe: ::
+
+         DEPENDS = "b"
+
+      Here, the dependency is such that the ``do_configure`` task for recipe "a"
+      depends on the ``do_populate_sysroot`` task of recipe "b". This means
+      anything that recipe "b" puts into sysroot is available when recipe "a" is
+      configuring itself.
+
+      For information on runtime dependencies, see the :term:`RDEPENDS`
+      variable.
+
+   :term:`DESCRIPTION`
+      A long description for the recipe.
+
+   :term:`DL_DIR`
+      The central download directory used by the build process to store
+      downloads. By default, ``DL_DIR`` gets files suitable for mirroring for
+      everything except Git repositories. If you want tarballs of Git
+      repositories, use the :term:`BB_GENERATE_MIRROR_TARBALLS` variable.
+
+   :term:`EXCLUDE_FROM_WORLD`
+      Directs BitBake to exclude a recipe from world builds (i.e.
+      ``bitbake world``). During world builds, BitBake locates, parses and
+      builds all recipes found in every layer exposed in the
+      ``bblayers.conf`` configuration file.
+
+      To exclude a recipe from a world build using this variable, set the
+      variable to "1" in the recipe.
+
+      .. note::
+
+         Recipes added to ``EXCLUDE_FROM_WORLD`` may still be built during a world
+         build in order to satisfy dependencies of other recipes. Adding a
+         recipe to ``EXCLUDE_FROM_WORLD`` only ensures that the recipe is not
+         explicitly added to the list of build targets in a world build.
+
+   :term:`FAKEROOT`
+      Contains the command to use when running a shell script in a fakeroot
+      environment. The ``FAKEROOT`` variable is obsolete and has been
+      replaced by the other ``FAKEROOT*`` variables. See these entries in
+      the glossary for more information.
+
+   :term:`FAKEROOTBASEENV`
+      Lists environment variables to set when executing the command defined
+      by :term:`FAKEROOTCMD` that starts the
+      bitbake-worker process in the fakeroot environment.
+
+   :term:`FAKEROOTCMD`
+      Contains the command that starts the bitbake-worker process in the
+      fakeroot environment.
+
+   :term:`FAKEROOTDIRS`
+      Lists directories to create before running a task in the fakeroot
+      environment.
+
+   :term:`FAKEROOTENV`
+      Lists environment variables to set when running a task in the
+      fakeroot environment. For additional information on environment
+      variables and the fakeroot environment, see the
+      :term:`FAKEROOTBASEENV` variable.
+
+   :term:`FAKEROOTNOENV`
+      Lists environment variables to set when running a task that is not in
+      the fakeroot environment. For additional information on environment
+      variables and the fakeroot environment, see the
+      :term:`FAKEROOTENV` variable.
+
+   :term:`FETCHCMD`
+      Defines the command the BitBake fetcher module executes when running
+      fetch operations. You need to use an override suffix when you use the
+      variable (e.g. ``FETCHCMD_git`` or ``FETCHCMD_svn``).
+
+   :term:`FILE`
+      Points at the current file. BitBake sets this variable during the
+      parsing process to identify the file being parsed. BitBake also sets
+      this variable when a recipe is being executed to identify the recipe
+      file.
+
+   :term:`FILESPATH`
+      Specifies directories BitBake uses when searching for patches and
+      files. The "local" fetcher module uses these directories when
+      handling ``file://`` URLs. The variable behaves like a shell ``PATH``
+      environment variable. The value is a colon-separated list of
+      directories that are searched left-to-right in order.
+
+   :term:`GITDIR`
+      The directory in which a local copy of a Git repository is stored
+      when it is cloned.
+
+   :term:`HGDIR`
+      The directory in which files checked out of a Mercurial system are
+      stored.
+
+   :term:`HOMEPAGE`
+      Website where more information about the software the recipe is
+      building can be found.
+
+   :term:`INHERIT`
+      Causes the named class or classes to be inherited globally. Anonymous
+      functions in the class or classes are not executed for the base
+      configuration and in each individual recipe. The OpenEmbedded build
+      system ignores changes to ``INHERIT`` in individual recipes.
+
+      For more information on ``INHERIT``, see the
+      ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:\`\`inherit\`\` configuration directive`"
+      section.
+
+   :term:`LAYERDEPENDS`
+      Lists the layers, separated by spaces, upon which this recipe
+      depends. Optionally, you can specify a specific layer version for a
+      dependency by adding it to the end of the layer name with a colon,
+      (e.g. "anotherlayer:3" to be compared against
+      :term:`LAYERVERSION`\ ``_anotherlayer`` in
+      this case). BitBake produces an error if any dependency is missing or
+      the version numbers do not match exactly (if specified).
+
+      You use this variable in the ``conf/layer.conf`` file. You must also
+      use the specific layer name as a suffix to the variable (e.g.
+      ``LAYERDEPENDS_mylayer``).
+
+   :term:`LAYERDIR`
+      When used inside the ``layer.conf`` configuration file, this variable
+      provides the path of the current layer. This variable is not
+      available outside of ``layer.conf`` and references are expanded
+      immediately when parsing of the file completes.
+
+   :term:`LAYERDIR_RE`
+      When used inside the ``layer.conf`` configuration file, this variable
+      provides the path of the current layer, escaped for use in a regular
+      expression (:term:`BBFILE_PATTERN`). This
+      variable is not available outside of ``layer.conf`` and references
+      are expanded immediately when parsing of the file completes.
+
+   :term:`LAYERVERSION`
+      Optionally specifies the version of a layer as a single number. You
+      can use this variable within
+      :term:`LAYERDEPENDS` for another layer in
+      order to depend on a specific version of the layer.
+
+      You use this variable in the ``conf/layer.conf`` file. You must also
+      use the specific layer name as a suffix to the variable (e.g.
+      ``LAYERDEPENDS_mylayer``).
+
+   :term:`LICENSE`
+      The list of source licenses for the recipe.
+
+   :term:`MIRRORS`
+      Specifies additional paths from which BitBake gets source code. When
+      the build system searches for source code, it first tries the local
+      download directory. If that location fails, the build system tries
+      locations defined by :term:`PREMIRRORS`, the
+      upstream source, and then locations specified by ``MIRRORS`` in that
+      order.
+
+   :term:`MULTI_PROVIDER_WHITELIST`
+      Allows you to suppress BitBake warnings caused when building two
+      separate recipes that provide the same output.
+
+      BitBake normally issues a warning when building two different recipes
+      where each provides the same output. This scenario is usually
+      something the user does not want. However, cases do exist where it
+      makes sense, particularly in the ``virtual/*`` namespace. You can use
+      this variable to suppress BitBake's warnings.
+
+      To use the variable, list provider names (e.g. recipe names,
+      ``virtual/kernel``, and so forth).
+
+   :term:`OVERRIDES`
+      BitBake uses ``OVERRIDES`` to control what variables are overridden
+      after BitBake parses recipes and configuration files.
+
+      Following is a simple example that uses an overrides list based on
+      machine architectures: OVERRIDES = "arm:x86:mips:powerpc" You can
+      find information on how to use ``OVERRIDES`` in the
+      ":ref:`bitbake-user-manual/bitbake-user-manual-metadata:conditional syntax
+      (overrides)`" section.
+
+   :term:`P4DIR`
+      The directory in which a local copy of a Perforce depot is stored
+      when it is fetched.
+
+   :term:`PACKAGES`
+      The list of packages the recipe creates.
+
+   :term:`PACKAGES_DYNAMIC`
+      A promise that your recipe satisfies runtime dependencies for
+      optional modules that are found in other recipes.
+      ``PACKAGES_DYNAMIC`` does not actually satisfy the dependencies, it
+      only states that they should be satisfied. For example, if a hard,
+      runtime dependency (:term:`RDEPENDS`) of another
+      package is satisfied during the build through the
+      ``PACKAGES_DYNAMIC`` variable, but a package with the module name is
+      never actually produced, then the other package will be broken.
+
+   :term:`PE`
+      The epoch of the recipe. By default, this variable is unset. The
+      variable is used to make upgrades possible when the versioning scheme
+      changes in some backwards incompatible way.
+
+   :term:`PERSISTENT_DIR`
+      Specifies the directory BitBake uses to store data that should be
+      preserved between builds. In particular, the data stored is the data
+      that uses BitBake's persistent data API and the data used by the PR
+      Server and PR Service.
+
+   :term:`PF`
+      Specifies the recipe or package name and includes all version and
+      revision numbers (i.e. ``eglibc-2.13-r20+svnr15508/`` and
+      ``bash-4.2-r1/``).
+
+   :term:`PN`
+      The recipe name.
+
+   :term:`PR`
+      The revision of the recipe.
+
+   :term:`PREFERRED_PROVIDER`
+      Determines which recipe should be given preference when multiple
+      recipes provide the same item. You should always suffix the variable
+      with the name of the provided item, and you should set it to the
+      :term:`PN` of the recipe to which you want to give
+      precedence. Some examples: ::
+
+         PREFERRED_PROVIDER_virtual/kernel ?= "linux-yocto"
+         PREFERRED_PROVIDER_virtual/xserver = "xserver-xf86"
+         PREFERRED_PROVIDER_virtual/libgl ?= "mesa"
+
+   :term:`PREFERRED_PROVIDERS`
+      Determines which recipe should be given preference for cases where
+      multiple recipes provide the same item. Functionally,
+      ``PREFERRED_PROVIDERS`` is identical to
+      :term:`PREFERRED_PROVIDER`. However, the ``PREFERRED_PROVIDERS`` variable
+      lets you define preferences for multiple situations using the following
+      form: ::
+
+         PREFERRED_PROVIDERS = "xxx:yyy aaa:bbb ..."
+
+      This form is a convenient replacement for the following: ::
+
+         PREFERRED_PROVIDER_xxx = "yyy"
+         PREFERRED_PROVIDER_aaa = "bbb"
+
+   :term:`PREFERRED_VERSION`
+      If there are multiple versions of recipes available, this variable
+      determines which recipe should be given preference. You must always
+      suffix the variable with the :term:`PN` you want to
+      select, and you should set :term:`PV` accordingly for
+      precedence.
+
+      The ``PREFERRED_VERSION`` variable supports limited wildcard use
+      through the "``%``" character. You can use the character to match any
+      number of characters, which can be useful when specifying versions
+      that contain long revision numbers that potentially change. Here are
+      two examples: ::
+
+         PREFERRED_VERSION_python = "2.7.3"
+         PREFERRED_VERSION_linux-yocto = "4.12%"
+
+      .. important::
+
+         The use of the " % " character is limited in that it only works at the
+         end of the string. You cannot use the wildcard character in any other
+         location of the string.
+
+   :term:`PREMIRRORS`
+      Specifies additional paths from which BitBake gets source code. When
+      the build system searches for source code, it first tries the local
+      download directory. If that location fails, the build system tries
+      locations defined by ``PREMIRRORS``, the upstream source, and then
+      locations specified by :term:`MIRRORS` in that order.
+
+      Typically, you would add a specific server for the build system to
+      attempt before any others by adding something like the following to
+      your configuration: ::
+
+         PREMIRRORS_prepend = "\
+         git://.*/.* http://www.yoctoproject.org/sources/ \n \
+         ftp://.*/.* http://www.yoctoproject.org/sources/ \n \
+         http://.*/.* http://www.yoctoproject.org/sources/ \n \
+         https://.*/.* http://www.yoctoproject.org/sources/ \n"
+
+      These changes cause the build system to intercept Git, FTP, HTTP, and
+      HTTPS requests and direct them to the ``http://`` sources mirror. You can
+      use ``file://`` URLs to point to local directories or network shares as
+      well.
+
+   :term:`PROVIDES`
+      A list of aliases by which a particular recipe can be known. By
+      default, a recipe's own ``PN`` is implicitly already in its
+      ``PROVIDES`` list. If a recipe uses ``PROVIDES``, the additional
+      aliases are synonyms for the recipe and can be useful satisfying
+      dependencies of other recipes during the build as specified by
+      ``DEPENDS``.
+
+      Consider the following example ``PROVIDES`` statement from a recipe
+      file ``libav_0.8.11.bb``: ::
+
+         PROVIDES += "libpostproc"
+
+      The ``PROVIDES`` statement results in the "libav" recipe also being known
+      as "libpostproc".
+
+      In addition to providing recipes under alternate names, the
+      ``PROVIDES`` mechanism is also used to implement virtual targets. A
+      virtual target is a name that corresponds to some particular
+      functionality (e.g. a Linux kernel). Recipes that provide the
+      functionality in question list the virtual target in ``PROVIDES``.
+      Recipes that depend on the functionality in question can include the
+      virtual target in :term:`DEPENDS` to leave the
+      choice of provider open.
+
+      Conventionally, virtual targets have names on the form
+      "virtual/function" (e.g. "virtual/kernel"). The slash is simply part
+      of the name and has no syntactical significance.
+
+   :term:`PRSERV_HOST`
+      The network based :term:`PR` service host and port.
+
+      Following is an example of how the ``PRSERV_HOST`` variable is set: ::
+
+         PRSERV_HOST = "localhost:0"
+
+      You must set the variable if you want to automatically start a local PR
+      service. You can set ``PRSERV_HOST`` to other values to use a remote PR
+      service.
+
+   :term:`PV`
+      The version of the recipe.
+
+   :term:`RDEPENDS`
+      Lists a package's runtime dependencies (i.e. other packages) that
+      must be installed in order for the built package to run correctly. If
+      a package in this list cannot be found during the build, you will get
+      a build error.
+
+      Because the ``RDEPENDS`` variable applies to packages being built,
+      you should always use the variable in a form with an attached package
+      name. For example, suppose you are building a development package
+      that depends on the ``perl`` package. In this case, you would use the
+      following ``RDEPENDS`` statement: ::
+
+         RDEPENDS_${PN}-dev += "perl"
+
+      In the example, the development package depends on the ``perl`` package.
+      Thus, the ``RDEPENDS`` variable has the ``${PN}-dev`` package name as part
+      of the variable.
+
+      BitBake supports specifying versioned dependencies. Although the
+      syntax varies depending on the packaging format, BitBake hides these
+      differences from you. Here is the general syntax to specify versions
+      with the ``RDEPENDS`` variable: ::
+
+         RDEPENDS_${PN} = "package (operator version)"
+
+      For ``operator``, you can specify the following: ::
+
+         =
+         <
+         >
+         <=
+         >=
+
+      For example, the following sets up a dependency on version 1.2 or
+      greater of the package ``foo``: ::
+
+         RDEPENDS_${PN} = "foo (>= 1.2)"
+
+      For information on build-time dependencies, see the :term:`DEPENDS`
+      variable.
+
+   :term:`REPODIR`
+      The directory in which a local copy of a ``google-repo`` directory is
+      stored when it is synced.
+
+   :term:`RPROVIDES`
+      A list of package name aliases that a package also provides. These
+      aliases are useful for satisfying runtime dependencies of other
+      packages both during the build and on the target (as specified by
+      ``RDEPENDS``).
+
+      As with all package-controlling variables, you must always use the
+      variable in conjunction with a package name override. Here is an
+      example: ::
+
+         RPROVIDES_${PN} = "widget-abi-2"
+
+   :term:`RRECOMMENDS`
+      A list of packages that extends the usability of a package being
+      built. The package being built does not depend on this list of
+      packages in order to successfully build, but needs them for the
+      extended usability. To specify runtime dependencies for packages, see
+      the ``RDEPENDS`` variable.
+
+      BitBake supports specifying versioned recommends. Although the syntax
+      varies depending on the packaging format, BitBake hides these
+      differences from you. Here is the general syntax to specify versions
+      with the ``RRECOMMENDS`` variable: ::
+
+         RRECOMMENDS_${PN} = "package (operator version)"
+
+      For ``operator``, you can specify the following: ::
+
+         =
+         <
+         >
+         <=
+         >=
+
+      For example, the following sets up a recommend on version
+      1.2 or greater of the package ``foo``: ::
+
+         RRECOMMENDS_${PN} = "foo (>= 1.2)"
+
+   :term:`SECTION`
+      The section in which packages should be categorized.
+
+   :term:`SRC_URI`
+      The list of source files - local or remote. This variable tells
+      BitBake which bits to pull for the build and how to pull them. For
+      example, if the recipe or append file needs to fetch a single tarball
+      from the Internet, the recipe or append file uses a ``SRC_URI`` entry
+      that specifies that tarball. On the other hand, if the recipe or
+      append file needs to fetch a tarball and include a custom file, the
+      recipe or append file needs an ``SRC_URI`` variable that specifies
+      all those sources.
+
+      The following list explains the available URI protocols:
+
+      -  ``file://`` : Fetches files, which are usually files shipped
+         with the metadata, from the local machine. The path is relative to
+         the :term:`FILESPATH` variable.
+
+      -  ``bzr://`` : Fetches files from a Bazaar revision control
+         repository.
+
+      -  ``git://`` : Fetches files from a Git revision control
+         repository.
+
+      -  ``osc://`` : Fetches files from an OSC (OpenSUSE Build service)
+         revision control repository.
+
+      -  ``repo://`` : Fetches files from a repo (Git) repository.
+
+      -  ``http://`` : Fetches files from the Internet using HTTP.
+
+      -  ``https://`` : Fetches files from the Internet using HTTPS.
+
+      -  ``ftp://`` : Fetches files from the Internet using FTP.
+
+      -  ``cvs://`` : Fetches files from a CVS revision control
+         repository.
+
+      -  ``hg://`` : Fetches files from a Mercurial (``hg``) revision
+         control repository.
+
+      -  ``p4://`` : Fetches files from a Perforce (``p4``) revision
+         control repository.
+
+      -  ``ssh://`` : Fetches files from a secure shell.
+
+      -  ``svn://`` : Fetches files from a Subversion (``svn``) revision
+         control repository.
+
+      Here are some additional options worth mentioning:
+
+      -  ``unpack`` : Controls whether or not to unpack the file if it is
+         an archive. The default action is to unpack the file.
+
+      -  ``subdir`` : Places the file (or extracts its contents) into the
+         specified subdirectory. This option is useful for unusual tarballs
+         or other archives that do not have their files already in a
+         subdirectory within the archive.
+
+      -  ``name`` : Specifies a name to be used for association with
+         ``SRC_URI`` checksums when you have more than one file specified
+         in ``SRC_URI``.
+
+      -  ``downloadfilename`` : Specifies the filename used when storing
+         the downloaded file.
+
+   :term:`SRCDATE`
+      The date of the source code used to build the package. This variable
+      applies only if the source was fetched from a Source Code Manager
+      (SCM).
+
+   :term:`SRCREV`
+      The revision of the source code used to build the package. This
+      variable applies only when using Subversion, Git, Mercurial and
+      Bazaar. If you want to build a fixed revision and you want to avoid
+      performing a query on the remote repository every time BitBake parses
+      your recipe, you should specify a ``SRCREV`` that is a full revision
+      identifier and not just a tag.
+
+   :term:`SRCREV_FORMAT`
+      Helps construct valid :term:`SRCREV` values when
+      multiple source controlled URLs are used in
+      :term:`SRC_URI`.
+
+      The system needs help constructing these values under these
+      circumstances. Each component in the ``SRC_URI`` is assigned a name
+      and these are referenced in the ``SRCREV_FORMAT`` variable. Consider
+      an example with URLs named "machine" and "meta". In this case,
+      ``SRCREV_FORMAT`` could look like "machine_meta" and those names
+      would have the SCM versions substituted into each position. Only one
+      ``AUTOINC`` placeholder is added and if needed. And, this placeholder
+      is placed at the start of the returned string.
+
+   :term:`STAMP`
+      Specifies the base path used to create recipe stamp files. The path
+      to an actual stamp file is constructed by evaluating this string and
+      then appending additional information.
+
+   :term:`STAMPCLEAN`
+      Specifies the base path used to create recipe stamp files. Unlike the
+      :term:`STAMP` variable, ``STAMPCLEAN`` can contain
+      wildcards to match the range of files a clean operation should
+      remove. BitBake uses a clean operation to remove any other stamps it
+      should be removing when creating a new stamp.
+
+   :term:`SUMMARY`
+      A short summary for the recipe, which is 72 characters or less.
+
+   :term:`SVNDIR`
+      The directory in which files checked out of a Subversion system are
+      stored.
+
+   :term:`T`
+      Points to a directory were BitBake places temporary files, which
+      consist mostly of task logs and scripts, when building a particular
+      recipe.
+
+   :term:`TOPDIR`
+      Points to the build directory. BitBake automatically sets this
+      variable.

BIN
openembedded-core/bitbake/doc/bitbake-user-manual/figures/bb_multiconfig_files.png


BIN
openembedded-core/bitbake/doc/bitbake-user-manual/figures/bitbake-title.png


+ 142 - 0
openembedded-core/bitbake/doc/bitbake.1

@@ -0,0 +1,142 @@
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH BITBAKE 1 "November 19, 2006"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+BitBake \- simple tool for the execution of tasks
+.SH SYNOPSIS
+.B bitbake
+.RI [ options ] " packagenames"
+.br
+.SH DESCRIPTION
+This manual page documents briefly the
+.B bitbake
+command.
+.PP
+.\" TeX users may be more comfortable with the \fB<whatever>\fP and
+.\" \fI<whatever>\fP escape sequences to invode bold face and italics, 
+.\" respectively.
+\fBbitbake\fP is a program that executes the specified task (default is 'build')
+for a given set of BitBake files.
+.br
+It expects that BBFILES is defined, which is a space separated list of files to
+be executed. BBFILES does support wildcards.
+.br
+Default BBFILES are the .bb files in the current directory.
+.SH OPTIONS
+This program follow the usual GNU command line syntax, with long
+options starting with two dashes (`-').
+.TP
+.B \-h, \-\-help
+Show summary of options.
+.TP
+.B \-\-version
+Show version of program.
+.TP
+.B \-bBUILDFILE, \-\-buildfile=BUILDFILE
+execute the task against this .bb file, rather than a package from BBFILES.
+.TP
+.B \-k, \-\-continue
+continue as much as possible after an error. While the target that failed, and
+those that depend on it, cannot be remade, the other dependencies of these
+targets can be processed all the same.
+.TP
+.B \-a, \-\-tryaltconfigs
+continue with builds by trying to use alternative providers where possible.
+.TP
+.B \-f, \-\-force
+force run of specified cmd, regardless of stamp status
+.TP
+.B \-i, \-\-interactive
+drop into the interactive mode also called the BitBake shell.
+.TP
+.B \-cCMD, \-\-cmd=CMD
+Specify task to execute. Note that this only executes the specified task for
+the providee and the packages it depends on, i.e. 'compile' does not implicitly
+call stage for the dependencies (IOW: use only if you know what you are doing).
+Depending on the base.bbclass a listtasks task is defined and will show
+available tasks.
+.TP
+.B \-rFILE, \-\-read=FILE 
+read the specified file before bitbake.conf
+.TP
+.B \-v, \-\-verbose
+output more chit-chat to the terminal
+.TP
+.B \-D, \-\-debug
+Increase the debug level. You can specify this more than once.
+.TP
+.B \-n, \-\-dry-run
+don't execute, just go through the motions
+.TP
+.B \-p, \-\-parse-only
+quit after parsing the BB files (developers only)
+.TP
+.B \-s, \-\-show-versions
+show current and preferred versions of all packages
+.TP
+.B \-e, \-\-environment
+show the global or per-recipe environment (this is what used to be bbread)
+.TP
+.B \-g, \-\-graphviz
+emit the dependency trees of the specified packages in the dot syntax
+.TP
+.B \-IIGNORED\_DOT\_DEPS, \-\-ignore-deps=IGNORED_DOT_DEPS
+Stop processing at the given list of dependencies when generating dependency
+graphs. This can help to make the graph more appealing
+.TP
+.B \-lDEBUG_DOMAINS, \-\-log-domains=DEBUG_DOMAINS
+Show debug logging for the specified logging domains
+.TP
+.B \-P, \-\-profile
+profile the command and print a report
+.TP
+.B \-uUI, \-\-ui=UI
+User interface to use. Currently, knotty, taskexp or ncurses can be specified as UI.
+.TP
+.B \-tSERVERTYPE, \-\-servertype=SERVERTYPE
+Choose which server to use, none, process or xmlrpc.
+.TP
+.B \-\-revisions-changed
+Set the exit code depending on whether upstream floating revisions have changed or not.
+.TP
+.B \-\-server-only
+Run bitbake without UI,  the frontend can connect with bitbake server itself.
+.TP
+.B \-BBIND, \-\-bind=BIND
+The name/address for the bitbake server to bind to.
+.TP
+.B \-\-no\-setscene
+Do not run any setscene tasks, forces builds.
+
+.SH ENVIRONMENT VARIABLES
+bitbake uses the following environment variables to control its
+operation:
+.TP
+.B BITBAKE_UI
+The bitbake user interface; overridden by the \fB-u\fP commandline option.
+
+.SH AUTHORS
+BitBake was written by 
+Phil Blundell,
+Holger Freyther,
+Chris Larson,
+Mickey Lauer,
+Richard Purdie,
+Holger Schurig
+.PP
+This manual page was written by Marcin Juszkiewicz <marcin@hrw.one.pl>
+for the Debian project (but may be used by others).

+ 100 - 0
openembedded-core/bitbake/doc/conf.py

@@ -0,0 +1,100 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+import datetime
+
+current_version = "dev"
+
+# String used in sidebar
+version = 'Version: ' + current_version
+if current_version == 'dev':
+    version = 'Version: Current Development'
+# Version seen in documentation_options.js and hence in js switchers code
+release = current_version
+
+# -- Project information -----------------------------------------------------
+
+project = 'Bitbake'
+copyright = '2004-%s, Richard Purdie, Chris Larson, and Phil Blundell' \
+    % datetime.datetime.now().year
+author = 'Richard Purdie, Chris Larson, and Phil Blundell'
+
+# external links and substitutions
+extlinks = {
+    'yocto_docs': ('https://docs.yoctoproject.org%s', None),
+    'oe_lists': ('https://lists.openembedded.org%s', None),
+}
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = [
+    'sphinx.ext.autosectionlabel',
+    'sphinx.ext.extlinks',
+]
+autosectionlabel_prefix_document = True
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+# master document name. The default changed from contents to index. so better
+# set it ourselves.
+master_doc = 'index'
+
+# create substitution for project configuration variables
+rst_prolog = """
+.. |project_name| replace:: %s
+.. |copyright| replace:: %s
+.. |author| replace:: %s
+""" % (project, copyright, author)
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages.  See the documentation for
+# a list of builtin themes.
+#
+try:
+    import sphinx_rtd_theme
+    html_theme = 'sphinx_rtd_theme'
+except ImportError:
+    sys.stderr.write("The Sphinx sphinx_rtd_theme HTML theme was not found.\
+    \nPlease make sure to install the sphinx_rtd_theme python package.\n")
+    sys.exit(1)
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['sphinx-static']
+
+# Add customm CSS and JS files
+html_css_files = ['theme_overrides.css']
+html_js_files = ['switchers.js']
+
+# Hide 'Created using Sphinx' text
+html_show_sphinx = False
+
+# Add 'Last updated' on each page
+html_last_updated_fmt = '%b %d, %Y'
+
+# Remove the trailing 'dot' in section numbers
+html_secnumber_suffix = " "

+ 3 - 0
openembedded-core/bitbake/doc/genindex.rst

@@ -0,0 +1,3 @@
+=====
+Index
+=====

+ 38 - 0
openembedded-core/bitbake/doc/index.rst

@@ -0,0 +1,38 @@
+.. SPDX-License-Identifier: CC-BY-2.5
+
+===================
+BitBake User Manual
+===================
+
+|
+
+.. toctree::
+   :caption: Table of Contents
+   :numbered:
+
+   bitbake-user-manual/bitbake-user-manual-intro
+   bitbake-user-manual/bitbake-user-manual-execution
+   bitbake-user-manual/bitbake-user-manual-metadata
+   bitbake-user-manual/bitbake-user-manual-fetching
+   bitbake-user-manual/bitbake-user-manual-ref-variables
+   bitbake-user-manual/bitbake-user-manual-hello
+
+.. toctree::
+   :maxdepth: 1
+   :hidden:
+
+   genindex
+   releases
+
+----
+
+.. include:: <xhtml1-lat1.txt>
+
+| BitBake Community
+| Copyright |copy| |copyright|
+| <bitbake-devel@lists.openembedded.org>
+
+This work is licensed under the Creative Commons Attribution License.  To view a
+copy of this license, visit http://creativecommons.org/licenses/by/2.5/ or send
+a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View,
+California 94041, USA.

+ 130 - 0
openembedded-core/bitbake/doc/releases.rst

@@ -0,0 +1,130 @@
+.. SPDX-License-Identifier: CC-BY-2.5
+
+=========================
+ Current Release Manuals
+=========================
+
+****************************
+3.1 'dunfell' Release Series
+****************************
+
+- :yocto_docs:`3.1 BitBake User Manual </3.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`3.1.1 BitBake User Manual </3.1.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`3.1.2 BitBake User Manual </3.1.2/bitbake-user-manual/bitbake-user-manual.html>`
+
+==========================
+ Previous Release Manuals
+==========================
+
+*************************
+3.0 'zeus' Release Series
+*************************
+
+- :yocto_docs:`3.0 BitBake User Manual </3.0/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`3.0.1 BitBake User Manual </3.0.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`3.0.2 BitBake User Manual </3.0.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`3.0.3 BitBake User Manual </3.0.3/bitbake-user-manual/bitbake-user-manual.html>`
+
+****************************
+2.7 'warrior' Release Series
+****************************
+
+- :yocto_docs:`2.7 BitBake User Manual </2.7/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.7.1 BitBake User Manual </2.7.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.7.2 BitBake User Manual </2.7.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.7.3 BitBake User Manual </2.7.3/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.7.4 BitBake User Manual </2.7.4/bitbake-user-manual/bitbake-user-manual.html>`
+
+*************************
+2.6 'thud' Release Series
+*************************
+
+- :yocto_docs:`2.6 BitBake User Manual </2.6/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.6.1 BitBake User Manual </2.6.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.6.2 BitBake User Manual </2.6.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.6.3 BitBake User Manual </2.6.3/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.6.4 BitBake User Manual </2.6.4/bitbake-user-manual/bitbake-user-manual.html>`
+
+*************************
+2.5 'sumo' Release Series
+*************************
+
+- :yocto_docs:`2.5 BitBake User Manual </2.5/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.5.1 BitBake User Manual </2.5.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.5.2 BitBake User Manual </2.5.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.5.3 BitBake User Manual </2.5.3/bitbake-user-manual/bitbake-user-manual.html>`
+
+**************************
+2.4 'rocko' Release Series
+**************************
+
+- :yocto_docs:`2.4 BitBake User Manual </2.4/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.4.1 BitBake User Manual </2.4.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.4.2 BitBake User Manual </2.4.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.4.3 BitBake User Manual </2.4.3/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.4.4 BitBake User Manual </2.4.4/bitbake-user-manual/bitbake-user-manual.html>`
+
+*************************
+2.3 'pyro' Release Series
+*************************
+
+- :yocto_docs:`2.3 BitBake User Manual </2.3/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.3.1 BitBake User Manual </2.3.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.3.2 BitBake User Manual </2.3.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.3.3 BitBake User Manual </2.3.3/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.3.4 BitBake User Manual </2.3.4/bitbake-user-manual/bitbake-user-manual.html>`
+
+**************************
+2.2 'morty' Release Series
+**************************
+
+- :yocto_docs:`2.2 BitBake User Manual </2.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.2.1 BitBake User Manual </2.2.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.2.2 BitBake User Manual </2.2.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.2.3 BitBake User Manual </2.2.3/bitbake-user-manual/bitbake-user-manual.html>`
+
+****************************
+2.1 'krogoth' Release Series
+****************************
+
+- :yocto_docs:`2.1 BitBake User Manual </2.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.1.1 BitBake User Manual </2.1.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.1.2 BitBake User Manual </2.1.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.1.3 BitBake User Manual </2.1.3/bitbake-user-manual/bitbake-user-manual.html>`
+
+***************************
+2.0 'jethro' Release Series
+***************************
+
+- :yocto_docs:`1.9 BitBake User Manual </1.9/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.0 BitBake User Manual </2.0/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.0.1 BitBake User Manual </2.0.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.0.2 BitBake User Manual </2.0.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`2.0.3 BitBake User Manual </2.0.3/bitbake-user-manual/bitbake-user-manual.html>`
+
+*************************
+1.8 'fido' Release Series
+*************************
+
+- :yocto_docs:`1.8 BitBake User Manual </1.8/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`1.8.1 BitBake User Manual </1.8.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`1.8.2 BitBake User Manual </1.8.2/bitbake-user-manual/bitbake-user-manual.html>`
+
+**************************
+1.7 'dizzy' Release Series
+**************************
+
+- :yocto_docs:`1.7 BitBake User Manual </1.7/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`1.7.1 BitBake User Manual </1.7.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`1.7.2 BitBake User Manual </1.7.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`1.7.3 BitBake User Manual </1.7.3/bitbake-user-manual/bitbake-user-manual.html>`
+
+**************************
+1.6 'daisy' Release Series
+**************************
+
+- :yocto_docs:`1.6 BitBake User Manual </1.6/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`1.6.1 BitBake User Manual </1.6.1/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`1.6.2 BitBake User Manual </1.6.2/bitbake-user-manual/bitbake-user-manual.html>`
+- :yocto_docs:`1.6.3 BitBake User Manual </1.6.3/bitbake-user-manual/bitbake-user-manual.html>`
+

+ 233 - 0
openembedded-core/bitbake/doc/sphinx-static/switchers.js

@@ -0,0 +1,233 @@
+(function() {
+  'use strict';
+
+  var all_versions = {
+    'dev': 'dev (3.2)',
+    '3.1.2': '3.1.2',
+    '3.0.3': '3.0.3',
+    '2.7.4': '2.7.4',
+  };
+
+  var all_doctypes = {
+      'single': 'Individual Webpages',
+      'mega': "All-in-one 'Mega' Manual",
+  };
+
+  // Simple version comparision
+  // Return 1 if a > b
+  // Return -1 if a < b
+  // Return 0 if a == b
+  function ver_compare(a, b) {
+    if (a == "dev") {
+       return 1;
+    }
+
+    if (a === b) {
+       return 0;
+    }
+
+    var a_components = a.split(".");
+    var b_components = b.split(".");
+
+    var len = Math.min(a_components.length, b_components.length);
+
+    // loop while the components are equal
+    for (var i = 0; i < len; i++) {
+        // A bigger than B
+        if (parseInt(a_components[i]) > parseInt(b_components[i])) {
+            return 1;
+        }
+
+        // B bigger than A
+        if (parseInt(a_components[i]) < parseInt(b_components[i])) {
+            return -1;
+        }
+    }
+
+    // If one's a prefix of the other, the longer one is greater.
+    if (a_components.length > b_components.length) {
+        return 1;
+    }
+
+    if (a_components.length < b_components.length) {
+        return -1;
+    }
+
+    // Otherwise they are the same.
+    return 0;
+  }
+
+  function build_version_select(current_series, current_version) {
+    var buf = ['<select>'];
+
+    $.each(all_versions, function(version, title) {
+      var series = version.substr(0, 3);
+      if (series == current_series) {
+        if (version == current_version)
+            buf.push('<option value="' + version + '" selected="selected">' + title + '</option>');
+        else
+            buf.push('<option value="' + version + '">' + title + '</option>');
+
+        if (version != current_version)
+            buf.push('<option value="' + current_version + '" selected="selected">' + current_version + '</option>');
+      } else {
+        buf.push('<option value="' + version + '">' + title + '</option>');
+      }
+    });
+
+    buf.push('</select>');
+    return buf.join('');
+  }
+
+  function build_doctype_select(current_doctype) {
+    var buf = ['<select>'];
+
+    $.each(all_doctypes, function(doctype, title) {
+      if (doctype == current_doctype)
+        buf.push('<option value="' + doctype + '" selected="selected">' +
+                 all_doctypes[current_doctype] + '</option>');
+      else
+        buf.push('<option value="' + doctype + '">' + title + '</option>');
+    });
+    if (!(current_doctype in all_doctypes)) {
+        // In case we're browsing a doctype that is not yet in all_doctypes.
+        buf.push('<option value="' + current_doctype + '" selected="selected">' +
+                 current_doctype + '</option>');
+        all_doctypes[current_doctype] = current_doctype;
+    }
+    buf.push('</select>');
+    return buf.join('');
+  }
+
+  function navigate_to_first_existing(urls) {
+    // Navigate to the first existing URL in urls.
+    var url = urls.shift();
+
+    // Web browsers won't redirect file:// urls to file urls using ajax but
+    // its useful for local testing
+    if (url.startsWith("file://")) {
+      window.location.href = url;
+      return;
+    }
+
+    if (urls.length == 0) {
+      window.location.href = url;
+      return;
+    }
+    $.ajax({
+      url: url,
+      success: function() {
+        window.location.href = url;
+      },
+      error: function() {
+        navigate_to_first_existing(urls);
+      }
+    });
+  }
+
+  function get_docroot_url() {
+    var url = window.location.href;
+    var root = DOCUMENTATION_OPTIONS.URL_ROOT;
+
+    var urlarray = url.split('/');
+    // Trim off anything after '/'
+    urlarray.pop();
+    var depth = (root.match(/\.\.\//g) || []).length;
+    for (var i = 0; i < depth; i++) {
+      urlarray.pop();
+    }
+
+    return urlarray.join('/') + '/';
+  }
+
+  function on_version_switch() {
+    var selected_version = $(this).children('option:selected').attr('value');
+    var url = window.location.href;
+    var current_version = DOCUMENTATION_OPTIONS.VERSION;
+    var docroot = get_docroot_url()
+
+    var new_versionpath = selected_version + '/';
+    if (selected_version == "dev")
+        new_versionpath = '';
+
+    // dev versions have no version prefix
+    if (current_version == "dev") {
+        var new_url = docroot + new_versionpath + url.replace(docroot, "");
+        var fallback_url = docroot + new_versionpath;
+    } else {
+        var new_url = url.replace('/' + current_version + '/', '/' + new_versionpath);
+        var fallback_url = new_url.replace(url.replace(docroot, ""), "");
+    }
+
+    console.log(get_docroot_url())
+    console.log(url + " to url " + new_url);
+    console.log(url + " to fallback " + fallback_url);
+
+    if (new_url != url) {
+      navigate_to_first_existing([
+        new_url,
+        fallback_url,
+        'https://www.yoctoproject.org/docs/',
+      ]);
+    }
+  }
+
+  function on_doctype_switch() {
+    var selected_doctype = $(this).children('option:selected').attr('value');
+    var url = window.location.href;
+    if (selected_doctype == 'mega') {
+      var docroot = get_docroot_url()
+      var current_version = DOCUMENTATION_OPTIONS.VERSION;
+      // Assume manuals before 3.2 are using old docbook mega-manual
+      if (ver_compare(current_version, "3.2") < 0) {
+        var new_url = docroot + "mega-manual/mega-manual.html";
+      } else {
+        var new_url = docroot + "singleindex.html";
+      }
+    } else {
+      var new_url = url.replace("singleindex.html", "index.html")
+    }
+
+    if (new_url != url) {
+      navigate_to_first_existing([
+        new_url,
+        'https://www.yoctoproject.org/docs/',
+      ]);
+    }
+  }
+
+  // Returns the current doctype based upon the url
+  function doctype_segment_from_url(url) {
+    if (url.includes("singleindex") || url.includes("mega-manual"))
+      return "mega";
+    return "single";
+  }
+
+  $(document).ready(function() {
+    var release = DOCUMENTATION_OPTIONS.VERSION;
+    var current_doctype = doctype_segment_from_url(window.location.href);
+    var current_series = release.substr(0, 3);
+    var version_select = build_version_select(current_series, release);
+
+    $('.version_switcher_placeholder').html(version_select);
+    $('.version_switcher_placeholder select').bind('change', on_version_switch);
+
+    var doctype_select = build_doctype_select(current_doctype);
+
+    $('.doctype_switcher_placeholder').html(doctype_select);
+    $('.doctype_switcher_placeholder select').bind('change', on_doctype_switch);
+
+    if (ver_compare(release, "3.1") < 0) {
+      $('#outdated-warning').html('Version ' + release + ' of the project is now considered obsolete, please select and use a more recent version');
+      $('#outdated-warning').css('padding', '.5em');
+    } else if (release != "dev") {
+      $.each(all_versions, function(version, title) {
+        var series = version.substr(0, 3);
+        if (series == current_series && version != release) {
+          $('#outdated-warning').html('This document is for outdated version ' + release + ', you should select the latest release version in this series, ' + version + '.');
+          $('#outdated-warning').css('padding', '.5em');
+        }
+      });
+    }
+  });
+})();

+ 162 - 0
openembedded-core/bitbake/doc/sphinx-static/theme_overrides.css

@@ -0,0 +1,162 @@
+/*
+    SPDX-License-Identifier: CC-BY-2.0-UK
+*/
+
+body {
+  font-family: Verdana, Sans, sans-serif;
+  margin:  0em auto;
+  color: #333;
+}
+
+h1,h2,h3,h4,h5,h6,h7 {
+  font-family: Arial, Sans;
+  color: #00557D;
+  clear: both;
+}
+
+h1 {
+  font-size: 2em;
+  text-align: left;
+  padding: 0em 0em 0em 0em;
+  margin: 2em 0em 0em 0em;
+}
+
+h2.subtitle {
+  margin: 0.10em 0em 3.0em 0em;
+  padding: 0em 0em 0em 0em;
+  font-size: 1.8em;
+  padding-left: 20%;
+  font-weight: normal;
+  font-style: italic;
+}
+
+h2 {
+  margin: 2em 0em 0.66em 0em;
+  padding: 0.5em 0em 0em 0em;
+  font-size: 1.5em;
+  font-weight: bold;
+}
+
+h3.subtitle {
+  margin: 0em 0em 1em 0em;
+  padding: 0em 0em 0em 0em;
+  font-size: 142.14%;
+  text-align: right;
+}
+
+h3 {
+  margin: 1em 0em 0.5em 0em;
+  padding: 1em 0em 0em 0em;
+  font-size: 140%;
+  font-weight: bold;
+}
+
+h4 {
+  margin: 1em 0em 0.5em 0em;
+  padding: 1em 0em 0em 0em;
+  font-size: 120%;
+  font-weight: bold;
+}
+
+h5 {
+  margin: 1em 0em 0.5em 0em;
+  padding: 1em 0em 0em 0em;
+  font-size: 110%;
+  font-weight: bold;
+}
+
+h6 {
+  margin: 1em 0em 0em 0em;
+  padding: 1em 0em 0em 0em;
+  font-size: 110%;
+  font-weight: bold;
+}
+
+em {
+  font-weight: bold;
+}
+
+.pre {
+  font-size: medium;
+  font-family: Courier, monospace;
+}
+
+.wy-nav-content a {
+  text-decoration: underline;
+  color: #444;
+  background: transparent;
+}
+
+.wy-nav-content a:hover {
+  text-decoration: underline;
+  background-color: #dedede;
+}
+
+.wy-nav-content a:visited {
+  color: #444;
+}
+
+[alt='Permalink'] { color: #eee; }
+[alt='Permalink']:hover { color: black; }
+
+@media screen {
+    /* content column
+     *
+     * RTD theme's default is 800px as max width for the content, but we have
+     * tables with tons of columns, which need the full width of the view-port.
+     */
+
+    .wy-nav-content{max-width: none; }
+
+    /* inline literal: drop the borderbox, padding and red color */
+    code, .rst-content tt, .rst-content code {
+        color: inherit;
+        border: none;
+        padding: unset;
+        background: inherit;
+        font-size: 85%;
+    }
+
+    .rst-content tt.literal,.rst-content tt.literal,.rst-content code.literal {
+        color: inherit;
+    }
+
+    /* Admonition should be gray, not blue or green */
+    .rst-content .note .admonition-title,
+    .rst-content .tip .admonition-title,
+    .rst-content .warning .admonition-title,
+    .rst-content .caution .admonition-title,
+    .rst-content .important .admonition-title {
+        background: #f0f0f2;
+        color: #00557D;
+
+    }
+
+    .rst-content .note,
+    .rst-content .tip,
+    .rst-content .important,
+    .rst-content .warning,
+    .rst-content .caution  {
+        background: #f0f0f2;
+    }
+
+    /* Remove the icon in front of note/tip element, and before the logo */
+    .icon-home:before, .rst-content .admonition-title:before {
+        display: none
+    }
+
+    /* a custom informalexample container is used in some doc */
+    .informalexample {
+        border: 1px solid;
+        border-color: #aaa;
+        margin: 1em 0em;
+        padding: 1em;
+        page-break-inside: avoid;
+    }
+
+    /* Remove the blue background in the top left corner, around the logo */
+    .wy-side-nav-search {
+        background: inherit;
+    }
+
+}

BIN
openembedded-core/bitbake/doc/template/Vera.ttf


BIN
openembedded-core/bitbake/doc/template/VeraMoBd.ttf


BIN
openembedded-core/bitbake/doc/template/VeraMono.ttf


BIN
openembedded-core/bitbake/doc/template/draft.png


+ 195 - 0
openembedded-core/bitbake/lib/bb/COW.py

@@ -0,0 +1,195 @@
+#
+# This is a copy on write dictionary and set which abuses classes to try and be nice and fast.
+#
+# Copyright (C) 2006 Tim Ansell
+#
+# Please Note:
+# Be careful when using mutable types (ie Dict and Lists) - operations involving these are SLOW.
+# Assign a file to __warn__ to get warnings about slow operations.
+#
+
+
+import copy
+
+ImmutableTypes = (
+    bool,
+    complex,
+    float,
+    int,
+    tuple,
+    frozenset,
+    str
+)
+
+MUTABLE = "__mutable__"
+
+
+class COWMeta(type):
+    pass
+
+
+class COWDictMeta(COWMeta):
+    __warn__ = False
+    __hasmutable__ = False
+    __marker__ = tuple()
+
+    def __str__(cls):
+        # FIXME: I have magic numbers!
+        return "<COWDict Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) - 3)
+
+    __repr__ = __str__
+
+    def cow(cls):
+        class C(cls):
+            __count__ = cls.__count__ + 1
+
+        return C
+
+    copy = cow
+    __call__ = cow
+
+    def __setitem__(cls, key, value):
+        if value is not None and not isinstance(value, ImmutableTypes):
+            if not isinstance(value, COWMeta):
+                cls.__hasmutable__ = True
+            key += MUTABLE
+        setattr(cls, key, value)
+
+    def __getmutable__(cls, key, readonly=False):
+        nkey = key + MUTABLE
+        try:
+            return cls.__dict__[nkey]
+        except KeyError:
+            pass
+
+        value = getattr(cls, nkey)
+        if readonly:
+            return value
+
+        if not cls.__warn__ is False and not isinstance(value, COWMeta):
+            print("Warning: Doing a copy because %s is a mutable type." % key, file=cls.__warn__)
+        try:
+            value = value.copy()
+        except AttributeError as e:
+            value = copy.copy(value)
+        setattr(cls, nkey, value)
+        return value
+
+    __getmarker__ = []
+
+    def __getreadonly__(cls, key, default=__getmarker__):
+        """
+        Get a value (even if mutable) which you promise not to change.
+        """
+        return cls.__getitem__(key, default, True)
+
+    def __getitem__(cls, key, default=__getmarker__, readonly=False):
+        try:
+            try:
+                value = getattr(cls, key)
+            except AttributeError:
+                value = cls.__getmutable__(key, readonly)
+
+            # This is for values which have been deleted
+            if value is cls.__marker__:
+                raise AttributeError("key %s does not exist." % key)
+
+            return value
+        except AttributeError as e:
+            if not default is cls.__getmarker__:
+                return default
+
+            raise KeyError(str(e))
+
+    def __delitem__(cls, key):
+        cls.__setitem__(key, cls.__marker__)
+
+    def __revertitem__(cls, key):
+        if key not in cls.__dict__:
+            key += MUTABLE
+        delattr(cls, key)
+
+    def __contains__(cls, key):
+        return cls.has_key(key)
+
+    def has_key(cls, key):
+        value = cls.__getreadonly__(key, cls.__marker__)
+        if value is cls.__marker__:
+            return False
+        return True
+
+    def iter(cls, type, readonly=False):
+        for key in dir(cls):
+            if key.startswith("__"):
+                continue
+
+            if key.endswith(MUTABLE):
+                key = key[:-len(MUTABLE)]
+
+            if type == "keys":
+                yield key
+
+            try:
+                if readonly:
+                    value = cls.__getreadonly__(key)
+                else:
+                    value = cls[key]
+            except KeyError:
+                continue
+
+            if type == "values":
+                yield value
+            if type == "items":
+                yield (key, value)
+        return
+
+    def iterkeys(cls):
+        return cls.iter("keys")
+
+    def itervalues(cls, readonly=False):
+        if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
+            print("Warning: If you aren't going to change any of the values call with True.", file=cls.__warn__)
+        return cls.iter("values", readonly)
+
+    def iteritems(cls, readonly=False):
+        if not cls.__warn__ is False and cls.__hasmutable__ and readonly is False:
+            print("Warning: If you aren't going to change any of the values call with True.", file=cls.__warn__)
+        return cls.iter("items", readonly)
+
+
+class COWSetMeta(COWDictMeta):
+    def __str__(cls):
+        # FIXME: I have magic numbers!
+        return "<COWSet Level: %i Current Keys: %i>" % (cls.__count__, len(cls.__dict__) - 3)
+
+    __repr__ = __str__
+
+    def cow(cls):
+        class C(cls):
+            __count__ = cls.__count__ + 1
+
+        return C
+
+    def add(cls, value):
+        COWDictMeta.__setitem__(cls, repr(hash(value)), value)
+
+    def remove(cls, value):
+        COWDictMeta.__delitem__(cls, repr(hash(value)))
+
+    def __in__(cls, value):
+        return repr(hash(value)) in COWDictMeta
+
+    def iterkeys(cls):
+        raise TypeError("sets don't have keys")
+
+    def iteritems(cls):
+        raise TypeError("sets don't have 'items'")
+
+
+# These are the actual classes you use!
+class COWDictBase(metaclass=COWDictMeta):
+    __count__ = 0
+
+
+class COWSetBase(metaclass=COWSetMeta):
+    __count__ = 0

+ 196 - 0
openembedded-core/bitbake/lib/bb/__init__.py

@@ -0,0 +1,196 @@
+#
+# BitBake Build System Python Library
+#
+# Copyright (C) 2003  Holger Schurig
+# Copyright (C) 2003, 2004  Chris Larson
+#
+# Based on Gentoo's portage.py.
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+__version__ = "1.48.0"
+
+import sys
+if sys.version_info < (3, 5, 0):
+    raise RuntimeError("Sorry, python 3.5.0 or later is required for this version of bitbake")
+
+
+class BBHandledException(Exception):
+    """
+    The big dilemma for generic bitbake code is what information to give the user
+    when an exception occurs. Any exception inheriting this base exception class
+    has already provided information to the user via some 'fired' message type such as
+    an explicitly fired event using bb.fire, or a bb.error message. If bitbake 
+    encounters an exception derived from this class, no backtrace or other information 
+    will be given to the user, its assumed the earlier event provided the relevant information.
+    """
+    pass
+
+import os
+import logging
+
+
+class NullHandler(logging.Handler):
+    def emit(self, record):
+        pass
+
+class BBLoggerMixin(object):
+    def __init__(self, *args, **kwargs):
+        # Does nothing to allow calling super() from derived classes
+        pass
+
+    def setup_bblogger(self, name):
+        if name.split(".")[0] == "BitBake":
+            self.debug = self.bbdebug
+
+    def bbdebug(self, level, msg, *args, **kwargs):
+        loglevel = logging.DEBUG - level + 1
+        if not bb.event.worker_pid:
+            if self.name in bb.msg.loggerDefaultDomains and loglevel > (bb.msg.loggerDefaultDomains[self.name]):
+                return
+            if loglevel > bb.msg.loggerDefaultLogLevel:
+                return
+        return self.log(loglevel, msg, *args, **kwargs)
+
+    def plain(self, msg, *args, **kwargs):
+        return self.log(logging.INFO + 1, msg, *args, **kwargs)
+
+    def verbose(self, msg, *args, **kwargs):
+        return self.log(logging.INFO - 1, msg, *args, **kwargs)
+
+    def verbnote(self, msg, *args, **kwargs):
+        return self.log(logging.INFO + 2, msg, *args, **kwargs)
+
+Logger = logging.getLoggerClass()
+class BBLogger(Logger, BBLoggerMixin):
+    def __init__(self, name, *args, **kwargs):
+        self.setup_bblogger(name)
+        super().__init__(name, *args, **kwargs)
+
+logging.raiseExceptions = False
+logging.setLoggerClass(BBLogger)
+
+class BBLoggerAdapter(logging.LoggerAdapter, BBLoggerMixin):
+    def __init__(self, logger, *args, **kwargs):
+        self.setup_bblogger(logger.name)
+        super().__init__(logger, *args, **kwargs)
+
+    if sys.version_info < (3, 6):
+        # These properties were added in Python 3.6. Add them in older versions
+        # for compatibility
+        @property
+        def manager(self):
+            return self.logger.manager
+
+        @manager.setter
+        def manager(self, value):
+            self.logger.manager = value
+
+        @property
+        def name(self):
+            return self.logger.name
+
+        def __repr__(self):
+            logger = self.logger
+            level = logger.getLevelName(logger.getEffectiveLevel())
+            return '<%s %s (%s)>' % (self.__class__.__name__, logger.name, level)
+
+logging.LoggerAdapter = BBLoggerAdapter
+
+logger = logging.getLogger("BitBake")
+logger.addHandler(NullHandler())
+logger.setLevel(logging.DEBUG - 2)
+
+mainlogger = logging.getLogger("BitBake.Main")
+
+class PrefixLoggerAdapter(logging.LoggerAdapter):
+    def __init__(self, prefix, logger):
+        super().__init__(logger, {})
+        self.__msg_prefix = prefix
+
+    def process(self, msg, kwargs):
+        return "%s%s" %(self.__msg_prefix, msg), kwargs
+
+# This has to be imported after the setLoggerClass, as the import of bb.msg
+# can result in construction of the various loggers.
+import bb.msg
+
+from bb import fetch2 as fetch
+sys.modules['bb.fetch'] = sys.modules['bb.fetch2']
+
+# Messaging convenience functions
+def plain(*args):
+    mainlogger.plain(''.join(args))
+
+def debug(lvl, *args):
+    if isinstance(lvl, str):
+        mainlogger.warning("Passed invalid debug level '%s' to bb.debug", lvl)
+        args = (lvl,) + args
+        lvl = 1
+    mainlogger.debug(lvl, ''.join(args))
+
+def note(*args):
+    mainlogger.info(''.join(args))
+
+#
+# A higher prioity note which will show on the console but isn't a warning
+#
+# Something is happening the user should be aware of but they probably did
+# something to make it happen
+#
+def verbnote(*args):
+    mainlogger.verbnote(''.join(args))
+
+#
+# Warnings - things the user likely needs to pay attention to and fix
+#
+def warn(*args):
+    mainlogger.warning(''.join(args))
+
+def error(*args, **kwargs):
+    mainlogger.error(''.join(args), extra=kwargs)
+
+def fatal(*args, **kwargs):
+    mainlogger.critical(''.join(args), extra=kwargs)
+    raise BBHandledException()
+
+def deprecated(func, name=None, advice=""):
+    """This is a decorator which can be used to mark functions
+    as deprecated. It will result in a warning being emitted
+    when the function is used."""
+    import warnings
+
+    if advice:
+        advice = ": %s" % advice
+    if name is None:
+        name = func.__name__
+
+    def newFunc(*args, **kwargs):
+        warnings.warn("Call to deprecated function %s%s." % (name,
+                                                             advice),
+                      category=DeprecationWarning,
+                      stacklevel=2)
+        return func(*args, **kwargs)
+    newFunc.__name__ = func.__name__
+    newFunc.__doc__ = func.__doc__
+    newFunc.__dict__.update(func.__dict__)
+    return newFunc
+
+# For compatibility
+def deprecate_import(current, modulename, fromlist, renames = None):
+    """Import objects from one module into another, wrapping them with a DeprecationWarning"""
+    import sys
+
+    module = __import__(modulename, fromlist = fromlist)
+    for position, objname in enumerate(fromlist):
+        obj = getattr(module, objname)
+        newobj = deprecated(obj, "{0}.{1}".format(current, objname),
+                            "Please use {0}.{1} instead".format(modulename, objname))
+        if renames:
+            newname = renames[position]
+        else:
+            newname = objname
+
+        setattr(sys.modules[current], newname, newobj)
+

+ 1025 - 0
openembedded-core/bitbake/lib/bb/build.py

@@ -0,0 +1,1025 @@
+#
+# BitBake 'Build' implementation
+#
+# Core code for function execution and task handling in the
+# BitBake build tools.
+#
+# Copyright (C) 2003, 2004  Chris Larson
+#
+# Based on Gentoo's portage.py.
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Based on functions from the base bb module, Copyright 2003 Holger Schurig
+
+import os
+import sys
+import logging
+import glob
+import itertools
+import time
+import re
+import stat
+import bb
+import bb.msg
+import bb.process
+import bb.progress
+from bb import data, event, utils
+
+bblogger = logging.getLogger('BitBake')
+logger = logging.getLogger('BitBake.Build')
+
+verboseShellLogging = False
+verboseStdoutLogging = False
+
+__mtime_cache = {}
+
+def cached_mtime_noerror(f):
+    if f not in __mtime_cache:
+        try:
+            __mtime_cache[f] = os.stat(f)[stat.ST_MTIME]
+        except OSError:
+            return 0
+    return __mtime_cache[f]
+
+def reset_cache():
+    global __mtime_cache
+    __mtime_cache = {}
+
+# When we execute a Python function, we'd like certain things
+# in all namespaces, hence we add them to __builtins__.
+# If we do not do this and use the exec globals, they will
+# not be available to subfunctions.
+if hasattr(__builtins__, '__setitem__'):
+    builtins = __builtins__
+else:
+    builtins = __builtins__.__dict__
+
+builtins['bb'] = bb
+builtins['os'] = os
+
+class TaskBase(event.Event):
+    """Base class for task events"""
+
+    def __init__(self, t, fn, logfile, d):
+        self._task = t
+        self._fn = fn
+        self._package = d.getVar("PF")
+        self._mc = d.getVar("BB_CURRENT_MC")
+        self.taskfile = d.getVar("FILE")
+        self.taskname = self._task
+        self.logfile = logfile
+        self.time = time.time()
+        self.pn = d.getVar("PN")
+        self.pv = d.getVar("PV")
+        event.Event.__init__(self)
+        self._message = "recipe %s: task %s: %s" % (d.getVar("PF"), t, self.getDisplayName())
+
+    def getTask(self):
+        return self._task
+
+    def setTask(self, task):
+        self._task = task
+
+    def getDisplayName(self):
+        return bb.event.getName(self)[4:]
+
+    task = property(getTask, setTask, None, "task property")
+
+class TaskStarted(TaskBase):
+    """Task execution started"""
+    def __init__(self, t, fn, logfile, taskflags, d):
+        super(TaskStarted, self).__init__(t, fn, logfile, d)
+        self.taskflags = taskflags
+
+class TaskSucceeded(TaskBase):
+    """Task execution completed"""
+
+class TaskFailed(TaskBase):
+    """Task execution failed"""
+
+    def __init__(self, task, fn, logfile, metadata, errprinted = False):
+        self.errprinted = errprinted
+        super(TaskFailed, self).__init__(task, fn, logfile, metadata)
+
+class TaskFailedSilent(TaskBase):
+    """Task execution failed (silently)"""
+    def getDisplayName(self):
+        # Don't need to tell the user it was silent
+        return "Failed"
+
+class TaskInvalid(TaskBase):
+
+    def __init__(self, task, fn, metadata):
+        super(TaskInvalid, self).__init__(task, fn, None, metadata)
+        self._message = "No such task '%s'" % task
+
+class TaskProgress(event.Event):
+    """
+    Task made some progress that could be reported to the user, usually in
+    the form of a progress bar or similar.
+    NOTE: this class does not inherit from TaskBase since it doesn't need
+    to - it's fired within the task context itself, so we don't have any of
+    the context information that you do in the case of the other events.
+    The event PID can be used to determine which task it came from.
+    The progress value is normally 0-100, but can also be negative
+    indicating that progress has been made but we aren't able to determine
+    how much.
+    The rate is optional, this is simply an extra string to display to the
+    user if specified.
+    """
+    def __init__(self, progress, rate=None):
+        self.progress = progress
+        self.rate = rate
+        event.Event.__init__(self)
+
+
+class LogTee(object):
+    def __init__(self, logger, outfile):
+        self.outfile = outfile
+        self.logger = logger
+        self.name = self.outfile.name
+
+    def write(self, string):
+        self.logger.plain(string)
+        self.outfile.write(string)
+
+    def __enter__(self):
+        self.outfile.__enter__()
+        return self
+
+    def __exit__(self, *excinfo):
+        self.outfile.__exit__(*excinfo)
+
+    def __repr__(self):
+        return '<LogTee {0}>'.format(self.name)
+
+    def flush(self):
+        self.outfile.flush()
+
+
+class StdoutNoopContextManager:
+    """
+    This class acts like sys.stdout, but adds noop __enter__ and __exit__ methods.
+    """
+    def __enter__(self):
+        return sys.stdout
+
+    def __exit__(self, *exc_info):
+        pass
+
+    def write(self, string):
+        return sys.stdout.write(string)
+
+    def flush(self):
+        sys.stdout.flush()
+
+    @property
+    def name(self):
+        return sys.stdout.name
+
+
+def exec_func(func, d, dirs = None):
+    """Execute a BB 'function'"""
+
+    try:
+        oldcwd = os.getcwd()
+    except:
+        oldcwd = None
+
+    flags = d.getVarFlags(func)
+    cleandirs = flags.get('cleandirs') if flags else None
+    if cleandirs:
+        for cdir in d.expand(cleandirs).split():
+            bb.utils.remove(cdir, True)
+            bb.utils.mkdirhier(cdir)
+
+    if flags and dirs is None:
+        dirs = flags.get('dirs')
+        if dirs:
+            dirs = d.expand(dirs).split()
+
+    if dirs:
+        for adir in dirs:
+            bb.utils.mkdirhier(adir)
+        adir = dirs[-1]
+    else:
+        adir = None
+
+    body = d.getVar(func, False)
+    if not body:
+        if body is None:
+            logger.warning("Function %s doesn't exist", func)
+        return
+
+    ispython = flags.get('python')
+
+    lockflag = flags.get('lockfiles')
+    if lockflag:
+        lockfiles = [f for f in d.expand(lockflag).split()]
+    else:
+        lockfiles = None
+
+    tempdir = d.getVar('T')
+
+    # or func allows items to be executed outside of the normal
+    # task set, such as buildhistory
+    task = d.getVar('BB_RUNTASK') or func
+    if task == func:
+        taskfunc = task
+    else:
+        taskfunc = "%s.%s" % (task, func)
+
+    runfmt = d.getVar('BB_RUNFMT') or "run.{func}.{pid}"
+    runfn = runfmt.format(taskfunc=taskfunc, task=task, func=func, pid=os.getpid())
+    runfile = os.path.join(tempdir, runfn)
+    bb.utils.mkdirhier(os.path.dirname(runfile))
+
+    # Setup the courtesy link to the runfn, only for tasks
+    # we create the link 'just' before the run script is created
+    # if we create it after, and if the run script fails, then the
+    # link won't be created as an exception would be fired.
+    if task == func:
+        runlink = os.path.join(tempdir, 'run.{0}'.format(task))
+        if runlink:
+            bb.utils.remove(runlink)
+
+            try:
+                os.symlink(runfn, runlink)
+            except OSError:
+                pass
+
+    with bb.utils.fileslocked(lockfiles):
+        if ispython:
+            exec_func_python(func, d, runfile, cwd=adir)
+        else:
+            exec_func_shell(func, d, runfile, cwd=adir)
+
+    try:
+        curcwd = os.getcwd()
+    except:
+        curcwd = None
+
+    if oldcwd and curcwd != oldcwd:
+        try:
+            bb.warn("Task %s changed cwd to %s" % (func, curcwd))
+            os.chdir(oldcwd)
+        except:
+            pass
+
+_functionfmt = """
+{function}(d)
+"""
+logformatter = bb.msg.BBLogFormatter("%(levelname)s: %(message)s")
+def exec_func_python(func, d, runfile, cwd=None):
+    """Execute a python BB 'function'"""
+
+    code = _functionfmt.format(function=func)
+    bb.utils.mkdirhier(os.path.dirname(runfile))
+    with open(runfile, 'w') as script:
+        bb.data.emit_func_python(func, script, d)
+
+    if cwd:
+        try:
+            olddir = os.getcwd()
+        except OSError as e:
+            bb.warn("%s: Cannot get cwd: %s" % (func, e))
+            olddir = None
+        os.chdir(cwd)
+
+    bb.debug(2, "Executing python function %s" % func)
+
+    try:
+        text = "def %s(d):\n%s" % (func, d.getVar(func, False))
+        fn = d.getVarFlag(func, "filename", False)
+        lineno = int(d.getVarFlag(func, "lineno", False))
+        bb.methodpool.insert_method(func, text, fn, lineno - 1)
+
+        comp = utils.better_compile(code, func, "exec_python_func() autogenerated")
+        utils.better_exec(comp, {"d": d}, code, "exec_python_func() autogenerated")
+    finally:
+        bb.debug(2, "Python function %s finished" % func)
+
+        if cwd and olddir:
+            try:
+                os.chdir(olddir)
+            except OSError as e:
+                bb.warn("%s: Cannot restore cwd %s: %s" % (func, olddir, e))
+
+def shell_trap_code():
+    return '''#!/bin/sh\n
+__BITBAKE_LAST_LINE=0
+
+# Emit a useful diagnostic if something fails:
+bb_sh_exit_handler() {
+    ret=$?
+    if [ "$ret" != 0 ]; then
+        echo "WARNING: exit code $ret from a shell command."
+    fi
+    exit $ret
+}
+
+bb_bash_exit_handler() {
+    ret=$?
+    { set +x; } > /dev/null
+    trap "" DEBUG
+    if [ "$ret" != 0 ]; then
+        echo "WARNING: ${BASH_SOURCE[0]}:${__BITBAKE_LAST_LINE} exit $ret from '$1'"
+
+        echo "WARNING: Backtrace (BB generated script): "
+        for i in $(seq 1 $((${#FUNCNAME[@]} - 1))); do
+            if [ "$i" -eq 1 ]; then
+                echo -e "\t#$((i)): ${FUNCNAME[$i]}, ${BASH_SOURCE[$((i-1))]}, line ${__BITBAKE_LAST_LINE}"
+            else
+                echo -e "\t#$((i)): ${FUNCNAME[$i]}, ${BASH_SOURCE[$((i-1))]}, line ${BASH_LINENO[$((i-1))]}"
+            fi
+        done
+    fi
+    exit $ret
+}
+
+bb_bash_debug_handler() {
+    local line=${BASH_LINENO[0]}
+    # For some reason the DEBUG trap trips with lineno=1 when scripts exit; ignore it
+    if [ "$line" -eq 1 ]; then
+        return
+    fi
+
+    # Track the line number of commands as they execute. This is so we can have access to the failing line number
+    # in the EXIT trap. See http://gnu-bash.2382.n7.nabble.com/trap-echo-quot-trap-exit-on-LINENO-quot-EXIT-gt-wrong-linenumber-td3666.html
+    if [ "${FUNCNAME[1]}" != "bb_bash_exit_handler" ]; then
+        __BITBAKE_LAST_LINE=$line
+    fi
+}
+
+case $BASH_VERSION in
+"") trap 'bb_sh_exit_handler' 0
+    set -e
+    ;;
+*)  trap 'bb_bash_exit_handler "$BASH_COMMAND"' 0
+    trap '{ bb_bash_debug_handler; } 2>/dev/null' DEBUG
+    set -e
+    shopt -s extdebug
+    ;;
+esac
+'''
+
+def create_progress_handler(func, progress, logfile, d):
+    if progress == 'percent':
+        # Use default regex
+        return bb.progress.BasicProgressHandler(d, outfile=logfile)
+    elif progress.startswith('percent:'):
+        # Use specified regex
+        return bb.progress.BasicProgressHandler(d, regex=progress.split(':', 1)[1], outfile=logfile)
+    elif progress.startswith('outof:'):
+        # Use specified regex
+        return bb.progress.OutOfProgressHandler(d, regex=progress.split(':', 1)[1], outfile=logfile)
+    elif progress.startswith("custom:"):
+        # Use a custom progress handler that was injected via OE_EXTRA_IMPORTS or __builtins__
+        import functools
+        from types import ModuleType
+
+        parts = progress.split(":", 2)
+        _, cls, otherargs = parts[0], parts[1], (parts[2] or None) if parts[2:] else None
+        if cls:
+            def resolve(x, y):
+                if not x:
+                    return None
+                if isinstance(x, ModuleType):
+                    return getattr(x, y, None)
+                return x.get(y)
+            cls_obj = functools.reduce(resolve, cls.split("."), bb.utils._context)
+            if not cls_obj:
+                # Fall-back on __builtins__
+                cls_obj = functools.reduce(resolve, cls.split("."), __builtins__)
+            if cls_obj:
+                return cls_obj(d, outfile=logfile, otherargs=otherargs)
+            bb.warn('%s: unknown custom progress handler in task progress varflag value "%s", ignoring' % (func, cls))
+    else:
+        bb.warn('%s: invalid task progress varflag value "%s", ignoring' % (func, progress))
+
+    return logfile
+
+def exec_func_shell(func, d, runfile, cwd=None):
+    """Execute a shell function from the metadata
+
+    Note on directory behavior.  The 'dirs' varflag should contain a list
+    of the directories you need created prior to execution.  The last
+    item in the list is where we will chdir/cd to.
+    """
+
+    # Don't let the emitted shell script override PWD
+    d.delVarFlag('PWD', 'export')
+
+    with open(runfile, 'w') as script:
+        script.write(shell_trap_code())
+
+        bb.data.emit_func(func, script, d)
+
+        if verboseShellLogging or bb.utils.to_boolean(d.getVar("BB_VERBOSE_LOGS", False)):
+            script.write("set -x\n")
+        if cwd:
+            script.write("cd '%s'\n" % cwd)
+        script.write("%s\n" % func)
+        script.write('''
+# cleanup
+ret=$?
+trap '' 0
+exit $ret
+''')
+
+    os.chmod(runfile, 0o775)
+
+    cmd = runfile
+    if d.getVarFlag(func, 'fakeroot', False):
+        fakerootcmd = d.getVar('FAKEROOT')
+        if fakerootcmd:
+            cmd = [fakerootcmd, runfile]
+
+    if verboseStdoutLogging:
+        logfile = LogTee(logger, StdoutNoopContextManager())
+    else:
+        logfile = StdoutNoopContextManager()
+
+    progress = d.getVarFlag(func, 'progress')
+    if progress:
+        try:
+            logfile = create_progress_handler(func, progress, logfile, d)
+        except:
+            from traceback import format_exc
+            logger.error("Failed to create progress handler")
+            logger.error(format_exc())
+            raise
+
+    fifobuffer = bytearray()
+    def readfifo(data):
+        nonlocal fifobuffer
+        fifobuffer.extend(data)
+        while fifobuffer:
+            message, token, nextmsg = fifobuffer.partition(b"\00")
+            if token:
+                splitval = message.split(b' ', 1)
+                cmd = splitval[0].decode("utf-8")
+                if len(splitval) > 1:
+                    value = splitval[1].decode("utf-8")
+                else:
+                    value = ''
+                if cmd == 'bbplain':
+                    bb.plain(value)
+                elif cmd == 'bbnote':
+                    bb.note(value)
+                elif cmd == 'bbverbnote':
+                    bb.verbnote(value)
+                elif cmd == 'bbwarn':
+                    bb.warn(value)
+                elif cmd == 'bberror':
+                    bb.error(value)
+                elif cmd == 'bbfatal':
+                    # The caller will call exit themselves, so bb.error() is
+                    # what we want here rather than bb.fatal()
+                    bb.error(value)
+                elif cmd == 'bbfatal_log':
+                    bb.error(value, forcelog=True)
+                elif cmd == 'bbdebug':
+                    splitval = value.split(' ', 1)
+                    level = int(splitval[0])
+                    value = splitval[1]
+                    bb.debug(level, value)
+                else:
+                    bb.warn("Unrecognised command '%s' on FIFO" % cmd)
+                fifobuffer = nextmsg
+            else:
+                break
+
+    tempdir = d.getVar('T')
+    fifopath = os.path.join(tempdir, 'fifo.%s' % os.getpid())
+    if os.path.exists(fifopath):
+        os.unlink(fifopath)
+    os.mkfifo(fifopath)
+    with open(fifopath, 'r+b', buffering=0) as fifo:
+        try:
+            bb.debug(2, "Executing shell function %s" % func)
+            with open(os.devnull, 'r+') as stdin, logfile:
+                bb.process.run(cmd, shell=False, stdin=stdin, log=logfile, extrafiles=[(fifo,readfifo)])
+        except bb.process.ExecutionError as exe:
+            # Find the backtrace that the shell trap generated
+            backtrace_marker_regex = re.compile(r"WARNING: Backtrace \(BB generated script\)")
+            stdout_lines = (exe.stdout or "").split("\n")
+            backtrace_start_line = None
+            for i, line in enumerate(reversed(stdout_lines)):
+                if backtrace_marker_regex.search(line):
+                    backtrace_start_line = len(stdout_lines) - i
+                    break
+
+            # Read the backtrace frames, starting at the location we just found
+            backtrace_entry_regex = re.compile(r"#(?P<frameno>\d+): (?P<funcname>[^\s]+), (?P<file>.+?), line ("
+                                               r"?P<lineno>\d+)")
+            backtrace_frames = []
+            if backtrace_start_line:
+                for line in itertools.islice(stdout_lines, backtrace_start_line, None):
+                    match = backtrace_entry_regex.search(line)
+                    if match:
+                        backtrace_frames.append(match.groupdict())
+
+            with open(runfile, "r") as script:
+                script_lines = [line.rstrip() for line in script.readlines()]
+
+            # For each backtrace frame, search backwards in the script (from the line number called out by the frame),
+            # to find the comment that emit_vars injected when it wrote the script. This will give us the metadata
+            # filename (e.g. .bb or .bbclass) and line number where the shell function was originally defined.
+            script_metadata_comment_regex = re.compile(r"# line: (?P<lineno>\d+), file: (?P<file>.+)")
+            better_frames = []
+            # Skip the very last frame since it's just the call to the shell task in the body of the script
+            for frame in backtrace_frames[:-1]:
+                # Check whether the frame corresponds to a function defined in the script vs external script.
+                if os.path.samefile(frame["file"], runfile):
+                    # Search backwards from the frame lineno to locate the comment that BB injected
+                    i = int(frame["lineno"]) - 1
+                    while i >= 0:
+                        match = script_metadata_comment_regex.match(script_lines[i])
+                        if match:
+                            # Calculate the relative line in the function itself
+                            relative_line_in_function = int(frame["lineno"]) - i - 2
+                            # Calculate line in the function as declared in the metadata
+                            metadata_function_line = relative_line_in_function + int(match["lineno"])
+                            better_frames.append("#{frameno}: {funcname}, {file}, line {lineno}".format(
+                                frameno=frame["frameno"],
+                                funcname=frame["funcname"],
+                                file=match["file"],
+                                lineno=metadata_function_line
+                            ))
+                            break
+                        i -= 1
+                else:
+                    better_frames.append("#{frameno}: {funcname}, {file}, line {lineno}".format(**frame))
+
+            if better_frames:
+                better_frames = ("\t{0}".format(frame) for frame in better_frames)
+                exe.extra_message = "\nBacktrace (metadata-relative locations):\n{0}".format("\n".join(better_frames))
+            raise
+        finally:
+            os.unlink(fifopath)
+
+    bb.debug(2, "Shell function %s finished" % func)
+
+def _task_data(fn, task, d):
+    localdata = bb.data.createCopy(d)
+    localdata.setVar('BB_FILENAME', fn)
+    localdata.setVar('BB_CURRENTTASK', task[3:])
+    localdata.setVar('OVERRIDES', 'task-%s:%s' %
+                     (task[3:].replace('_', '-'), d.getVar('OVERRIDES', False)))
+    localdata.finalize()
+    bb.data.expandKeys(localdata)
+    return localdata
+
+def _exec_task(fn, task, d, quieterr):
+    """Execute a BB 'task'
+
+    Execution of a task involves a bit more setup than executing a function,
+    running it with its own local metadata, and with some useful variables set.
+    """
+    if not d.getVarFlag(task, 'task', False):
+        event.fire(TaskInvalid(task, d), d)
+        logger.error("No such task: %s" % task)
+        return 1
+
+    logger.debug(1, "Executing task %s", task)
+
+    localdata = _task_data(fn, task, d)
+    tempdir = localdata.getVar('T')
+    if not tempdir:
+        bb.fatal("T variable not set, unable to build")
+
+    # Change nice level if we're asked to
+    nice = localdata.getVar("BB_TASK_NICE_LEVEL")
+    if nice:
+        curnice = os.nice(0)
+        nice = int(nice) - curnice
+        newnice = os.nice(nice)
+        logger.debug(1, "Renice to %s " % newnice)
+    ionice = localdata.getVar("BB_TASK_IONICE_LEVEL")
+    if ionice:
+        try:
+            cls, prio = ionice.split(".", 1)
+            bb.utils.ioprio_set(os.getpid(), int(cls), int(prio))
+        except:
+            bb.warn("Invalid ionice level %s" % ionice)
+
+    bb.utils.mkdirhier(tempdir)
+
+    # Determine the logfile to generate
+    logfmt = localdata.getVar('BB_LOGFMT') or 'log.{task}.{pid}'
+    logbase = logfmt.format(task=task, pid=os.getpid())
+
+    # Document the order of the tasks...
+    logorder = os.path.join(tempdir, 'log.task_order')
+    try:
+        with open(logorder, 'a') as logorderfile:
+            logorderfile.write('{0} ({1}): {2}\n'.format(task, os.getpid(), logbase))
+    except OSError:
+        logger.exception("Opening log file '%s'", logorder)
+        pass
+
+    # Setup the courtesy link to the logfn
+    loglink = os.path.join(tempdir, 'log.{0}'.format(task))
+    logfn = os.path.join(tempdir, logbase)
+    if loglink:
+        bb.utils.remove(loglink)
+
+        try:
+           os.symlink(logbase, loglink)
+        except OSError:
+           pass
+
+    prefuncs = localdata.getVarFlag(task, 'prefuncs', expand=True)
+    postfuncs = localdata.getVarFlag(task, 'postfuncs', expand=True)
+
+    class ErrorCheckHandler(logging.Handler):
+        def __init__(self):
+            self.triggered = False
+            logging.Handler.__init__(self, logging.ERROR)
+        def emit(self, record):
+            if getattr(record, 'forcelog', False):
+                self.triggered = False
+            else:
+                self.triggered = True
+
+    # Handle logfiles
+    try:
+        bb.utils.mkdirhier(os.path.dirname(logfn))
+        logfile = open(logfn, 'w')
+    except OSError:
+        logger.exception("Opening log file '%s'", logfn)
+        pass
+
+    # Dup the existing fds so we dont lose them
+    osi = [os.dup(sys.stdin.fileno()), sys.stdin.fileno()]
+    oso = [os.dup(sys.stdout.fileno()), sys.stdout.fileno()]
+    ose = [os.dup(sys.stderr.fileno()), sys.stderr.fileno()]
+
+    # Replace those fds with our own
+    with open('/dev/null', 'r') as si:
+        os.dup2(si.fileno(), osi[1])
+    os.dup2(logfile.fileno(), oso[1])
+    os.dup2(logfile.fileno(), ose[1])
+
+    # Ensure Python logging goes to the logfile
+    handler = logging.StreamHandler(logfile)
+    handler.setFormatter(logformatter)
+    # Always enable full debug output into task logfiles
+    handler.setLevel(logging.DEBUG - 2)
+    bblogger.addHandler(handler)
+
+    errchk = ErrorCheckHandler()
+    bblogger.addHandler(errchk)
+
+    localdata.setVar('BB_LOGFILE', logfn)
+    localdata.setVar('BB_RUNTASK', task)
+    localdata.setVar('BB_TASK_LOGGER', bblogger)
+
+    flags = localdata.getVarFlags(task)
+
+    try:
+        try:
+            event.fire(TaskStarted(task, fn, logfn, flags, localdata), localdata)
+        except (bb.BBHandledException, SystemExit):
+            return 1
+
+        try:
+            for func in (prefuncs or '').split():
+                exec_func(func, localdata)
+            exec_func(task, localdata)
+            for func in (postfuncs or '').split():
+                exec_func(func, localdata)
+        except bb.BBHandledException:
+            event.fire(TaskFailed(task, fn, logfn, localdata, True), localdata)
+            return 1
+        except Exception as exc:
+            if quieterr:
+                event.fire(TaskFailedSilent(task, fn, logfn, localdata), localdata)
+            else:
+                errprinted = errchk.triggered
+                logger.error(str(exc))
+                event.fire(TaskFailed(task, fn, logfn, localdata, errprinted), localdata)
+            return 1
+    finally:
+        sys.stdout.flush()
+        sys.stderr.flush()
+
+        bblogger.removeHandler(handler)
+
+        # Restore the backup fds
+        os.dup2(osi[0], osi[1])
+        os.dup2(oso[0], oso[1])
+        os.dup2(ose[0], ose[1])
+
+        # Close the backup fds
+        os.close(osi[0])
+        os.close(oso[0])
+        os.close(ose[0])
+
+        logfile.close()
+        if os.path.exists(logfn) and os.path.getsize(logfn) == 0:
+            logger.debug(2, "Zero size logfn %s, removing", logfn)
+            bb.utils.remove(logfn)
+            bb.utils.remove(loglink)
+    event.fire(TaskSucceeded(task, fn, logfn, localdata), localdata)
+
+    if not localdata.getVarFlag(task, 'nostamp', False) and not localdata.getVarFlag(task, 'selfstamp', False):
+        make_stamp(task, localdata)
+
+    return 0
+
+def exec_task(fn, task, d, profile = False):
+    try:
+        quieterr = False
+        if d.getVarFlag(task, "quieterrors", False) is not None:
+            quieterr = True
+
+        if profile:
+            profname = "profile-%s.log" % (d.getVar("PN") + "-" + task)
+            try:
+                import cProfile as profile
+            except:
+                import profile
+            prof = profile.Profile()
+            ret = profile.Profile.runcall(prof, _exec_task, fn, task, d, quieterr)
+            prof.dump_stats(profname)
+            bb.utils.process_profilelog(profname)
+
+            return ret
+        else:
+            return _exec_task(fn, task, d, quieterr)
+
+    except Exception:
+        from traceback import format_exc
+        if not quieterr:
+            logger.error("Build of %s failed" % (task))
+            logger.error(format_exc())
+            failedevent = TaskFailed(task, None, d, True)
+            event.fire(failedevent, d)
+        return 1
+
+def stamp_internal(taskname, d, file_name, baseonly=False, noextra=False):
+    """
+    Internal stamp helper function
+    Makes sure the stamp directory exists
+    Returns the stamp path+filename
+
+    In the bitbake core, d can be a CacheData and file_name will be set.
+    When called in task context, d will be a data store, file_name will not be set
+    """
+    taskflagname = taskname
+    if taskname.endswith("_setscene") and taskname != "do_setscene":
+        taskflagname = taskname.replace("_setscene", "")
+
+    if file_name:
+        stamp = d.stamp[file_name]
+        extrainfo = d.stamp_extrainfo[file_name].get(taskflagname) or ""
+    else:
+        stamp = d.getVar('STAMP')
+        file_name = d.getVar('BB_FILENAME')
+        extrainfo = d.getVarFlag(taskflagname, 'stamp-extra-info') or ""
+
+    if baseonly:
+        return stamp
+    if noextra:
+        extrainfo = ""
+
+    if not stamp:
+        return
+
+    stamp = bb.parse.siggen.stampfile(stamp, file_name, taskname, extrainfo)
+
+    stampdir = os.path.dirname(stamp)
+    if cached_mtime_noerror(stampdir) == 0:
+        bb.utils.mkdirhier(stampdir)
+
+    return stamp
+
+def stamp_cleanmask_internal(taskname, d, file_name):
+    """
+    Internal stamp helper function to generate stamp cleaning mask
+    Returns the stamp path+filename
+
+    In the bitbake core, d can be a CacheData and file_name will be set.
+    When called in task context, d will be a data store, file_name will not be set
+    """
+    taskflagname = taskname
+    if taskname.endswith("_setscene") and taskname != "do_setscene":
+        taskflagname = taskname.replace("_setscene", "")
+
+    if file_name:
+        stamp = d.stampclean[file_name]
+        extrainfo = d.stamp_extrainfo[file_name].get(taskflagname) or ""
+    else:
+        stamp = d.getVar('STAMPCLEAN')
+        file_name = d.getVar('BB_FILENAME')
+        extrainfo = d.getVarFlag(taskflagname, 'stamp-extra-info') or ""
+
+    if not stamp:
+        return []
+
+    cleanmask = bb.parse.siggen.stampcleanmask(stamp, file_name, taskname, extrainfo)
+
+    return [cleanmask, cleanmask.replace(taskflagname, taskflagname + "_setscene")]
+
+def make_stamp(task, d, file_name = None):
+    """
+    Creates/updates a stamp for a given task
+    (d can be a data dict or dataCache)
+    """
+    cleanmask = stamp_cleanmask_internal(task, d, file_name)
+    for mask in cleanmask:
+        for name in glob.glob(mask):
+            # Preserve sigdata files in the stamps directory
+            if "sigdata" in name or "sigbasedata" in name:
+                continue
+            # Preserve taint files in the stamps directory
+            if name.endswith('.taint'):
+                continue
+            os.unlink(name)
+
+    stamp = stamp_internal(task, d, file_name)
+    # Remove the file and recreate to force timestamp
+    # change on broken NFS filesystems
+    if stamp:
+        bb.utils.remove(stamp)
+        open(stamp, "w").close()
+
+    # If we're in task context, write out a signature file for each task
+    # as it completes
+    if not task.endswith("_setscene") and task != "do_setscene" and not file_name:
+        stampbase = stamp_internal(task, d, None, True)
+        file_name = d.getVar('BB_FILENAME')
+        bb.parse.siggen.dump_sigtask(file_name, task, stampbase, True)
+
+def del_stamp(task, d, file_name = None):
+    """
+    Removes a stamp for a given task
+    (d can be a data dict or dataCache)
+    """
+    stamp = stamp_internal(task, d, file_name)
+    bb.utils.remove(stamp)
+
+def write_taint(task, d, file_name = None):
+    """
+    Creates a "taint" file which will force the specified task and its
+    dependents to be re-run the next time by influencing the value of its
+    taskhash.
+    (d can be a data dict or dataCache)
+    """
+    import uuid
+    if file_name:
+        taintfn = d.stamp[file_name] + '.' + task + '.taint'
+    else:
+        taintfn = d.getVar('STAMP') + '.' + task + '.taint'
+    bb.utils.mkdirhier(os.path.dirname(taintfn))
+    # The specific content of the taint file is not really important,
+    # we just need it to be random, so a random UUID is used
+    with open(taintfn, 'w') as taintf:
+        taintf.write(str(uuid.uuid4()))
+
+def stampfile(taskname, d, file_name = None, noextra=False):
+    """
+    Return the stamp for a given task
+    (d can be a data dict or dataCache)
+    """
+    return stamp_internal(taskname, d, file_name, noextra=noextra)
+
+def add_tasks(tasklist, d):
+    task_deps = d.getVar('_task_deps', False)
+    if not task_deps:
+        task_deps = {}
+    if not 'tasks' in task_deps:
+        task_deps['tasks'] = []
+    if not 'parents' in task_deps:
+        task_deps['parents'] = {}
+
+    for task in tasklist:
+        task = d.expand(task)
+
+        d.setVarFlag(task, 'task', 1)
+
+        if not task in task_deps['tasks']:
+            task_deps['tasks'].append(task)
+
+        flags = d.getVarFlags(task)
+        def getTask(name):
+            if not name in task_deps:
+                task_deps[name] = {}
+            if name in flags:
+                deptask = d.expand(flags[name])
+                task_deps[name][task] = deptask
+        getTask('mcdepends')
+        getTask('depends')
+        getTask('rdepends')
+        getTask('deptask')
+        getTask('rdeptask')
+        getTask('recrdeptask')
+        getTask('recideptask')
+        getTask('nostamp')
+        getTask('fakeroot')
+        getTask('noexec')
+        getTask('umask')
+        task_deps['parents'][task] = []
+        if 'deps' in flags:
+            for dep in flags['deps']:
+                # Check and warn for "addtask task after foo" while foo does not exist
+                #if not dep in tasklist:
+                #    bb.warn('%s: dependent task %s for %s does not exist' % (d.getVar('PN'), dep, task))
+                dep = d.expand(dep)
+                task_deps['parents'][task].append(dep)
+
+    # don't assume holding a reference
+    d.setVar('_task_deps', task_deps)
+
+def addtask(task, before, after, d):
+    if task[:3] != "do_":
+        task = "do_" + task
+
+    d.setVarFlag(task, "task", 1)
+    bbtasks = d.getVar('__BBTASKS', False) or []
+    if task not in bbtasks:
+        bbtasks.append(task)
+    d.setVar('__BBTASKS', bbtasks)
+
+    existing = d.getVarFlag(task, "deps", False) or []
+    if after is not None:
+        # set up deps for function
+        for entry in after.split():
+            if entry not in existing:
+                existing.append(entry)
+    d.setVarFlag(task, "deps", existing)
+    if before is not None:
+        # set up things that depend on this func
+        for entry in before.split():
+            existing = d.getVarFlag(entry, "deps", False) or []
+            if task not in existing:
+                d.setVarFlag(entry, "deps", [task] + existing)
+
+def deltask(task, d):
+    if task[:3] != "do_":
+        task = "do_" + task
+
+    bbtasks = d.getVar('__BBTASKS', False) or []
+    if task in bbtasks:
+        bbtasks.remove(task)
+        d.delVarFlag(task, 'task')
+        d.setVar('__BBTASKS', bbtasks)
+
+    d.delVarFlag(task, 'deps')
+    for bbtask in d.getVar('__BBTASKS', False) or []:
+        deps = d.getVarFlag(bbtask, 'deps', False) or []
+        if task in deps:
+            deps.remove(task)
+            d.setVarFlag(bbtask, 'deps', deps)
+
+def preceedtask(task, with_recrdeptasks, d):
+    """
+    Returns a set of tasks in the current recipe which were specified as
+    precondition by the task itself ("after") or which listed themselves
+    as precondition ("before"). Preceeding tasks specified via the
+    "recrdeptask" are included in the result only if requested. Beware
+    that this may lead to the task itself being listed.
+    """
+    preceed = set()
+
+    # Ignore tasks which don't exist
+    tasks = d.getVar('__BBTASKS', False)
+    if task not in tasks:
+        return preceed
+
+    preceed.update(d.getVarFlag(task, 'deps') or [])
+    if with_recrdeptasks:
+        recrdeptask = d.getVarFlag(task, 'recrdeptask')
+        if recrdeptask:
+            preceed.update(recrdeptask.split())
+    return preceed
+
+def tasksbetween(task_start, task_end, d):
+    """
+    Return the list of tasks between two tasks in the current recipe,
+    where task_start is to start at and task_end is the task to end at
+    (and task_end has a dependency chain back to task_start).
+    """
+    outtasks = []
+    tasks = list(filter(lambda k: d.getVarFlag(k, "task"), d.keys()))
+    def follow_chain(task, endtask, chain=None):
+        if not chain:
+            chain = []
+        chain.append(task)
+        for othertask in tasks:
+            if othertask == task:
+                continue
+            if task == endtask:
+                for ctask in chain:
+                    if ctask not in outtasks:
+                        outtasks.append(ctask)
+            else:
+                deps = d.getVarFlag(othertask, 'deps', False)
+                if task in deps:
+                    follow_chain(othertask, endtask, chain)
+        chain.pop()
+    follow_chain(task_start, task_end)
+    return outtasks

+ 1023 - 0
openembedded-core/bitbake/lib/bb/cache.py

@@ -0,0 +1,1023 @@
+#
+# BitBake Cache implementation
+#
+# Caching of bitbake variables before task execution
+
+# Copyright (C) 2006        Richard Purdie
+# Copyright (C) 2012        Intel Corporation
+
+# but small sections based on code from bin/bitbake:
+# Copyright (C) 2003, 2004  Chris Larson
+# Copyright (C) 2003, 2004  Phil Blundell
+# Copyright (C) 2003 - 2005 Michael 'Mickey' Lauer
+# Copyright (C) 2005        Holger Hans Peter Freyther
+# Copyright (C) 2005        ROAD GmbH
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import os
+import logging
+import pickle
+from collections import defaultdict, Mapping
+import bb.utils
+from bb import PrefixLoggerAdapter
+import re
+
+logger = logging.getLogger("BitBake.Cache")
+
+__cache_version__ = "153"
+
+def getCacheFile(path, filename, mc, data_hash):
+    mcspec = ''
+    if mc:
+        mcspec = ".%s" % mc
+    return os.path.join(path, filename + mcspec + "." + data_hash)
+
+# RecipeInfoCommon defines common data retrieving methods
+# from meta data for caches. CoreRecipeInfo as well as other
+# Extra RecipeInfo needs to inherit this class
+class RecipeInfoCommon(object):
+
+    @classmethod
+    def listvar(cls, var, metadata):
+        return cls.getvar(var, metadata).split()
+
+    @classmethod
+    def intvar(cls, var, metadata):
+        return int(cls.getvar(var, metadata) or 0)
+
+    @classmethod
+    def depvar(cls, var, metadata):
+        return bb.utils.explode_deps(cls.getvar(var, metadata))
+
+    @classmethod
+    def pkgvar(cls, var, packages, metadata):
+        return dict((pkg, cls.depvar("%s_%s" % (var, pkg), metadata))
+                    for pkg in packages)
+
+    @classmethod
+    def taskvar(cls, var, tasks, metadata):
+        return dict((task, cls.getvar("%s_task-%s" % (var, task), metadata))
+                    for task in tasks)
+
+    @classmethod
+    def flaglist(cls, flag, varlist, metadata, squash=False):
+        out_dict = dict((var, metadata.getVarFlag(var, flag))
+                    for var in varlist)
+        if squash:
+            return dict((k,v) for (k,v) in out_dict.items() if v)
+        else:
+            return out_dict
+
+    @classmethod
+    def getvar(cls, var, metadata, expand = True):
+        return metadata.getVar(var, expand) or ''
+
+
+class CoreRecipeInfo(RecipeInfoCommon):
+    __slots__ = ()
+
+    cachefile = "bb_cache.dat"
+
+    def __init__(self, filename, metadata):
+        self.file_depends = metadata.getVar('__depends', False)
+        self.timestamp = bb.parse.cached_mtime(filename)
+        self.variants = self.listvar('__VARIANTS', metadata) + ['']
+        self.appends = self.listvar('__BBAPPEND', metadata)
+        self.nocache = self.getvar('BB_DONT_CACHE', metadata)
+
+        self.provides  = self.depvar('PROVIDES', metadata)
+        self.rprovides = self.depvar('RPROVIDES', metadata)
+        self.pn = self.getvar('PN', metadata) or bb.parse.vars_from_file(filename,metadata)[0]
+        self.packages = self.listvar('PACKAGES', metadata)
+        if not self.packages:
+            self.packages.append(self.pn)
+        self.packages_dynamic = self.listvar('PACKAGES_DYNAMIC', metadata)
+
+        self.skipreason = self.getvar('__SKIPPED', metadata)
+        if self.skipreason:
+            self.skipped = True
+            return
+
+        self.tasks = metadata.getVar('__BBTASKS', False)
+
+        self.basetaskhashes = self.taskvar('BB_BASEHASH', self.tasks, metadata)
+        self.hashfilename = self.getvar('BB_HASHFILENAME', metadata)
+
+        self.task_deps = metadata.getVar('_task_deps', False) or {'tasks': [], 'parents': {}}
+
+        self.skipped = False
+        self.pe = self.getvar('PE', metadata)
+        self.pv = self.getvar('PV', metadata)
+        self.pr = self.getvar('PR', metadata)
+        self.defaultpref = self.intvar('DEFAULT_PREFERENCE', metadata)
+        self.not_world = self.getvar('EXCLUDE_FROM_WORLD', metadata)
+        self.stamp = self.getvar('STAMP', metadata)
+        self.stampclean = self.getvar('STAMPCLEAN', metadata)
+        self.stamp_extrainfo = self.flaglist('stamp-extra-info', self.tasks, metadata)
+        self.file_checksums = self.flaglist('file-checksums', self.tasks, metadata, True)
+        self.depends          = self.depvar('DEPENDS', metadata)
+        self.rdepends         = self.depvar('RDEPENDS', metadata)
+        self.rrecommends      = self.depvar('RRECOMMENDS', metadata)
+        self.rprovides_pkg    = self.pkgvar('RPROVIDES', self.packages, metadata)
+        self.rdepends_pkg     = self.pkgvar('RDEPENDS', self.packages, metadata)
+        self.rrecommends_pkg  = self.pkgvar('RRECOMMENDS', self.packages, metadata)
+        self.inherits         = self.getvar('__inherit_cache', metadata, expand=False)
+        self.fakerootenv      = self.getvar('FAKEROOTENV', metadata)
+        self.fakerootdirs     = self.getvar('FAKEROOTDIRS', metadata)
+        self.fakerootnoenv    = self.getvar('FAKEROOTNOENV', metadata)
+        self.extradepsfunc    = self.getvar('calculate_extra_depends', metadata)
+
+    @classmethod
+    def init_cacheData(cls, cachedata):
+        # CacheData in Core RecipeInfo Class
+        cachedata.task_deps = {}
+        cachedata.pkg_fn = {}
+        cachedata.pkg_pn = defaultdict(list)
+        cachedata.pkg_pepvpr = {}
+        cachedata.pkg_dp = {}
+
+        cachedata.stamp = {}
+        cachedata.stampclean = {}
+        cachedata.stamp_extrainfo = {}
+        cachedata.file_checksums = {}
+        cachedata.fn_provides = {}
+        cachedata.pn_provides = defaultdict(list)
+        cachedata.all_depends = []
+
+        cachedata.deps = defaultdict(list)
+        cachedata.packages = defaultdict(list)
+        cachedata.providers = defaultdict(list)
+        cachedata.rproviders = defaultdict(list)
+        cachedata.packages_dynamic = defaultdict(list)
+
+        cachedata.rundeps = defaultdict(lambda: defaultdict(list))
+        cachedata.runrecs = defaultdict(lambda: defaultdict(list))
+        cachedata.possible_world = []
+        cachedata.universe_target = []
+        cachedata.hashfn = {}
+
+        cachedata.basetaskhash = {}
+        cachedata.inherits = {}
+        cachedata.fakerootenv = {}
+        cachedata.fakerootnoenv = {}
+        cachedata.fakerootdirs = {}
+        cachedata.extradepsfunc = {}
+
+    def add_cacheData(self, cachedata, fn):
+        cachedata.task_deps[fn] = self.task_deps
+        cachedata.pkg_fn[fn] = self.pn
+        cachedata.pkg_pn[self.pn].append(fn)
+        cachedata.pkg_pepvpr[fn] = (self.pe, self.pv, self.pr)
+        cachedata.pkg_dp[fn] = self.defaultpref
+        cachedata.stamp[fn] = self.stamp
+        cachedata.stampclean[fn] = self.stampclean
+        cachedata.stamp_extrainfo[fn] = self.stamp_extrainfo
+        cachedata.file_checksums[fn] = self.file_checksums
+
+        provides = [self.pn]
+        for provide in self.provides:
+            if provide not in provides:
+                provides.append(provide)
+        cachedata.fn_provides[fn] = provides
+
+        for provide in provides:
+            cachedata.providers[provide].append(fn)
+            if provide not in cachedata.pn_provides[self.pn]:
+                cachedata.pn_provides[self.pn].append(provide)
+
+        for dep in self.depends:
+            if dep not in cachedata.deps[fn]:
+                cachedata.deps[fn].append(dep)
+            if dep not in cachedata.all_depends:
+                cachedata.all_depends.append(dep)
+
+        rprovides = self.rprovides
+        for package in self.packages:
+            cachedata.packages[package].append(fn)
+            rprovides += self.rprovides_pkg[package]
+
+        for rprovide in rprovides:
+            if fn not in cachedata.rproviders[rprovide]:
+                cachedata.rproviders[rprovide].append(fn)
+
+        for package in self.packages_dynamic:
+            cachedata.packages_dynamic[package].append(fn)
+
+        # Build hash of runtime depends and recommends
+        for package in self.packages:
+            cachedata.rundeps[fn][package] = list(self.rdepends) + self.rdepends_pkg[package]
+            cachedata.runrecs[fn][package] = list(self.rrecommends) + self.rrecommends_pkg[package]
+
+        # Collect files we may need for possible world-dep
+        # calculations
+        if not self.not_world:
+            cachedata.possible_world.append(fn)
+        #else:
+        #    logger.debug(2, "EXCLUDE FROM WORLD: %s", fn)
+
+        # create a collection of all targets for sanity checking
+        # tasks, such as upstream versions, license, and tools for
+        # task and image creation.
+        cachedata.universe_target.append(self.pn)
+
+        cachedata.hashfn[fn] = self.hashfilename
+        for task, taskhash in self.basetaskhashes.items():
+            identifier = '%s:%s' % (fn, task)
+            cachedata.basetaskhash[identifier] = taskhash
+
+        cachedata.inherits[fn] = self.inherits
+        cachedata.fakerootenv[fn] = self.fakerootenv
+        cachedata.fakerootnoenv[fn] = self.fakerootnoenv
+        cachedata.fakerootdirs[fn] = self.fakerootdirs
+        cachedata.extradepsfunc[fn] = self.extradepsfunc
+
+def virtualfn2realfn(virtualfn):
+    """
+    Convert a virtual file name to a real one + the associated subclass keyword
+    """
+    mc = ""
+    if virtualfn.startswith('mc:'):
+        elems = virtualfn.split(':')
+        mc = elems[1]
+        virtualfn = ":".join(elems[2:])
+
+    fn = virtualfn
+    cls = ""
+    if virtualfn.startswith('virtual:'):
+        elems = virtualfn.split(':')
+        cls = ":".join(elems[1:-1])
+        fn = elems[-1]
+
+    return (fn, cls, mc)
+
+def realfn2virtual(realfn, cls, mc):
+    """
+    Convert a real filename + the associated subclass keyword to a virtual filename
+    """
+    if cls:
+        realfn = "virtual:" + cls + ":" + realfn
+    if mc:
+        realfn = "mc:" + mc + ":" + realfn
+    return realfn
+
+def variant2virtual(realfn, variant):
+    """
+    Convert a real filename + the associated subclass keyword to a virtual filename
+    """
+    if variant == "":
+        return realfn
+    if variant.startswith("mc:"):
+        elems = variant.split(":")
+        if elems[2]:
+            return "mc:" + elems[1] + ":virtual:" + ":".join(elems[2:]) + ":" + realfn
+        return "mc:" + elems[1] + ":" + realfn
+    return "virtual:" + variant + ":" + realfn
+
+def parse_recipe(bb_data, bbfile, appends, mc=''):
+    """
+    Parse a recipe
+    """
+
+    chdir_back = False
+
+    bb_data.setVar("__BBMULTICONFIG", mc)
+
+    # expand tmpdir to include this topdir
+    bb_data.setVar('TMPDIR', bb_data.getVar('TMPDIR') or "")
+    bbfile_loc = os.path.abspath(os.path.dirname(bbfile))
+    oldpath = os.path.abspath(os.getcwd())
+    bb.parse.cached_mtime_noerror(bbfile_loc)
+
+    # The ConfHandler first looks if there is a TOPDIR and if not
+    # then it would call getcwd().
+    # Previously, we chdir()ed to bbfile_loc, called the handler
+    # and finally chdir()ed back, a couple of thousand times. We now
+    # just fill in TOPDIR to point to bbfile_loc if there is no TOPDIR yet.
+    if not bb_data.getVar('TOPDIR', False):
+        chdir_back = True
+        bb_data.setVar('TOPDIR', bbfile_loc)
+    try:
+        if appends:
+            bb_data.setVar('__BBAPPEND', " ".join(appends))
+        bb_data = bb.parse.handle(bbfile, bb_data)
+        if chdir_back:
+            os.chdir(oldpath)
+        return bb_data
+    except:
+        if chdir_back:
+            os.chdir(oldpath)
+        raise
+
+
+
+class NoCache(object):
+
+    def __init__(self, databuilder):
+        self.databuilder = databuilder
+        self.data = databuilder.data
+
+    def loadDataFull(self, virtualfn, appends):
+        """
+        Return a complete set of data for fn.
+        To do this, we need to parse the file.
+        """
+        logger.debug(1, "Parsing %s (full)" % virtualfn)
+        (fn, virtual, mc) = virtualfn2realfn(virtualfn)
+        bb_data = self.load_bbfile(virtualfn, appends, virtonly=True)
+        return bb_data[virtual]
+
+    def load_bbfile(self, bbfile, appends, virtonly = False, mc=None):
+        """
+        Load and parse one .bb build file
+        Return the data and whether parsing resulted in the file being skipped
+        """
+
+        if virtonly:
+            (bbfile, virtual, mc) = virtualfn2realfn(bbfile)
+            bb_data = self.databuilder.mcdata[mc].createCopy()
+            bb_data.setVar("__ONLYFINALISE", virtual or "default")
+            datastores = parse_recipe(bb_data, bbfile, appends, mc)
+            return datastores
+
+        if mc is not None:
+            bb_data = self.databuilder.mcdata[mc].createCopy()
+            return parse_recipe(bb_data, bbfile, appends, mc)
+
+        bb_data = self.data.createCopy()
+        datastores = parse_recipe(bb_data, bbfile, appends)
+
+        for mc in self.databuilder.mcdata:
+            if not mc:
+                continue
+            bb_data = self.databuilder.mcdata[mc].createCopy()
+            newstores = parse_recipe(bb_data, bbfile, appends, mc)
+            for ns in newstores:
+                datastores["mc:%s:%s" % (mc, ns)] = newstores[ns]
+
+        return datastores
+
+class Cache(NoCache):
+    """
+    BitBake Cache implementation
+    """
+    def __init__(self, databuilder, mc, data_hash, caches_array):
+        super().__init__(databuilder)
+        data = databuilder.data
+
+        # Pass caches_array information into Cache Constructor
+        # It will be used later for deciding whether we
+        # need extra cache file dump/load support
+        self.mc = mc
+        self.logger = PrefixLoggerAdapter("Cache: %s: " % (mc if mc else "default"), logger)
+        self.caches_array = caches_array
+        self.cachedir = data.getVar("CACHE")
+        self.clean = set()
+        self.checked = set()
+        self.depends_cache = {}
+        self.data_fn = None
+        self.cacheclean = True
+        self.data_hash = data_hash
+        self.filelist_regex = re.compile(r'(?:(?<=:True)|(?<=:False))\s+')
+
+        if self.cachedir in [None, '']:
+            self.has_cache = False
+            self.logger.info("Not using a cache. "
+                             "Set CACHE = <directory> to enable.")
+            return
+
+        self.has_cache = True
+
+    def getCacheFile(self, cachefile):
+        return getCacheFile(self.cachedir, cachefile, self.mc, self.data_hash)
+
+    def prepare_cache(self, progress):
+        if not self.has_cache:
+            return 0
+
+        loaded = 0
+
+        self.cachefile = self.getCacheFile("bb_cache.dat")
+
+        self.logger.debug(1, "Cache dir: %s", self.cachedir)
+        bb.utils.mkdirhier(self.cachedir)
+
+        cache_ok = True
+        if self.caches_array:
+            for cache_class in self.caches_array:
+                cachefile = self.getCacheFile(cache_class.cachefile)
+                cache_exists = os.path.exists(cachefile)
+                self.logger.debug(2, "Checking if %s exists: %r", cachefile, cache_exists)
+                cache_ok = cache_ok and cache_exists
+                cache_class.init_cacheData(self)
+        if cache_ok:
+            loaded = self.load_cachefile(progress)
+        elif os.path.isfile(self.cachefile):
+            self.logger.info("Out of date cache found, rebuilding...")
+        else:
+            self.logger.debug(1, "Cache file %s not found, building..." % self.cachefile)
+
+        # We don't use the symlink, its just for debugging convinience
+        if self.mc:
+            symlink = os.path.join(self.cachedir, "bb_cache.dat.%s" % self.mc)
+        else:
+            symlink = os.path.join(self.cachedir, "bb_cache.dat")
+
+        if os.path.exists(symlink):
+            bb.utils.remove(symlink)
+        try:
+            os.symlink(os.path.basename(self.cachefile), symlink)
+        except OSError:
+            pass
+
+        return loaded
+
+    def cachesize(self):
+        if not self.has_cache:
+            return 0
+
+        cachesize = 0
+        for cache_class in self.caches_array:
+            cachefile = self.getCacheFile(cache_class.cachefile)
+            try:
+                with open(cachefile, "rb") as cachefile:
+                    cachesize += os.fstat(cachefile.fileno()).st_size
+            except FileNotFoundError:
+                pass
+
+        return cachesize
+
+    def load_cachefile(self, progress):
+        cachesize = self.cachesize()
+        previous_progress = 0
+        previous_percent = 0
+
+        for cache_class in self.caches_array:
+            cachefile = self.getCacheFile(cache_class.cachefile)
+            self.logger.debug(1, 'Loading cache file: %s' % cachefile)
+            with open(cachefile, "rb") as cachefile:
+                pickled = pickle.Unpickler(cachefile)
+                # Check cache version information
+                try:
+                    cache_ver = pickled.load()
+                    bitbake_ver = pickled.load()
+                except Exception:
+                    self.logger.info('Invalid cache, rebuilding...')
+                    return 0
+
+                if cache_ver != __cache_version__:
+                    self.logger.info('Cache version mismatch, rebuilding...')
+                    return 0
+                elif bitbake_ver != bb.__version__:
+                    self.logger.info('Bitbake version mismatch, rebuilding...')
+                    return 0
+
+                # Load the rest of the cache file
+                current_progress = 0
+                while cachefile:
+                    try:
+                        key = pickled.load()
+                        value = pickled.load()
+                    except Exception:
+                        break
+                    if not isinstance(key, str):
+                        bb.warn("%s from extras cache is not a string?" % key)
+                        break
+                    if not isinstance(value, RecipeInfoCommon):
+                        bb.warn("%s from extras cache is not a RecipeInfoCommon class?" % value)
+                        break
+
+                    if key in self.depends_cache:
+                        self.depends_cache[key].append(value)
+                    else:
+                        self.depends_cache[key] = [value]
+                    # only fire events on even percentage boundaries
+                    current_progress = cachefile.tell() + previous_progress
+                    progress(cachefile.tell() + previous_progress)
+
+                previous_progress += current_progress
+
+        return len(self.depends_cache)
+
+    def parse(self, filename, appends):
+        """Parse the specified filename, returning the recipe information"""
+        self.logger.debug(1, "Parsing %s", filename)
+        infos = []
+        datastores = self.load_bbfile(filename, appends, mc=self.mc)
+        depends = []
+        variants = []
+        # Process the "real" fn last so we can store variants list
+        for variant, data in sorted(datastores.items(),
+                                    key=lambda i: i[0],
+                                    reverse=True):
+            virtualfn = variant2virtual(filename, variant)
+            variants.append(variant)
+            depends = depends + (data.getVar("__depends", False) or [])
+            if depends and not variant:
+                data.setVar("__depends", depends)
+            if virtualfn == filename:
+                data.setVar("__VARIANTS", " ".join(variants))
+            info_array = []
+            for cache_class in self.caches_array:
+                info = cache_class(filename, data)
+                info_array.append(info)
+            infos.append((virtualfn, info_array))
+
+        return infos
+
+    def load(self, filename, appends):
+        """Obtain the recipe information for the specified filename,
+        using cached values if available, otherwise parsing.
+
+        Note that if it does parse to obtain the info, it will not
+        automatically add the information to the cache or to your
+        CacheData.  Use the add or add_info method to do so after
+        running this, or use loadData instead."""
+        cached = self.cacheValid(filename, appends)
+        if cached:
+            infos = []
+            # info_array item is a list of [CoreRecipeInfo, XXXRecipeInfo]
+            info_array = self.depends_cache[filename]
+            for variant in info_array[0].variants:
+                virtualfn = variant2virtual(filename, variant)
+                infos.append((virtualfn, self.depends_cache[virtualfn]))
+        else:
+            return self.parse(filename, appends, configdata, self.caches_array)
+
+        return cached, infos
+
+    def loadData(self, fn, appends, cacheData):
+        """Load the recipe info for the specified filename,
+        parsing and adding to the cache if necessary, and adding
+        the recipe information to the supplied CacheData instance."""
+        skipped, virtuals = 0, 0
+
+        cached, infos = self.load(fn, appends)
+        for virtualfn, info_array in infos:
+            if info_array[0].skipped:
+                self.logger.debug(1, "Skipping %s: %s", virtualfn, info_array[0].skipreason)
+                skipped += 1
+            else:
+                self.add_info(virtualfn, info_array, cacheData, not cached)
+                virtuals += 1
+
+        return cached, skipped, virtuals
+
+    def cacheValid(self, fn, appends):
+        """
+        Is the cache valid for fn?
+        Fast version, no timestamps checked.
+        """
+        if fn not in self.checked:
+            self.cacheValidUpdate(fn, appends)
+
+        # Is cache enabled?
+        if not self.has_cache:
+            return False
+        if fn in self.clean:
+            return True
+        return False
+
+    def cacheValidUpdate(self, fn, appends):
+        """
+        Is the cache valid for fn?
+        Make thorough (slower) checks including timestamps.
+        """
+        # Is cache enabled?
+        if not self.has_cache:
+            return False
+
+        self.checked.add(fn)
+
+        # File isn't in depends_cache
+        if not fn in self.depends_cache:
+            self.logger.debug(2, "%s is not cached", fn)
+            return False
+
+        mtime = bb.parse.cached_mtime_noerror(fn)
+
+        # Check file still exists
+        if mtime == 0:
+            self.logger.debug(2, "%s no longer exists", fn)
+            self.remove(fn)
+            return False
+
+        info_array = self.depends_cache[fn]
+        # Check the file's timestamp
+        if mtime != info_array[0].timestamp:
+            self.logger.debug(2, "%s changed", fn)
+            self.remove(fn)
+            return False
+
+        # Check dependencies are still valid
+        depends = info_array[0].file_depends
+        if depends:
+            for f, old_mtime in depends:
+                fmtime = bb.parse.cached_mtime_noerror(f)
+                # Check if file still exists
+                if old_mtime != 0 and fmtime == 0:
+                    self.logger.debug(2, "%s's dependency %s was removed",
+                                         fn, f)
+                    self.remove(fn)
+                    return False
+
+                if (fmtime != old_mtime):
+                    self.logger.debug(2, "%s's dependency %s changed",
+                                         fn, f)
+                    self.remove(fn)
+                    return False
+
+        if hasattr(info_array[0], 'file_checksums'):
+            for _, fl in info_array[0].file_checksums.items():
+                fl = fl.strip()
+                if not fl:
+                    continue
+                # Have to be careful about spaces and colons in filenames
+                flist = self.filelist_regex.split(fl)
+                for f in flist:
+                    if not f:
+                        continue
+                    f, exist = f.split(":")
+                    if (exist == "True" and not os.path.exists(f)) or (exist == "False" and os.path.exists(f)):
+                        self.logger.debug(2, "%s's file checksum list file %s changed",
+                                             fn, f)
+                        self.remove(fn)
+                        return False
+
+        if tuple(appends) != tuple(info_array[0].appends):
+            self.logger.debug(2, "appends for %s changed", fn)
+            self.logger.debug(2, "%s to %s" % (str(appends), str(info_array[0].appends)))
+            self.remove(fn)
+            return False
+
+        invalid = False
+        for cls in info_array[0].variants:
+            virtualfn = variant2virtual(fn, cls)
+            self.clean.add(virtualfn)
+            if virtualfn not in self.depends_cache:
+                self.logger.debug(2, "%s is not cached", virtualfn)
+                invalid = True
+            elif len(self.depends_cache[virtualfn]) != len(self.caches_array):
+                self.logger.debug(2, "Extra caches missing for %s?" % virtualfn)
+                invalid = True
+
+        # If any one of the variants is not present, mark as invalid for all
+        if invalid:
+            for cls in info_array[0].variants:
+                virtualfn = variant2virtual(fn, cls)
+                if virtualfn in self.clean:
+                    self.logger.debug(2, "Removing %s from cache", virtualfn)
+                    self.clean.remove(virtualfn)
+            if fn in self.clean:
+                self.logger.debug(2, "Marking %s as not clean", fn)
+                self.clean.remove(fn)
+            return False
+
+        self.clean.add(fn)
+        return True
+
+    def remove(self, fn):
+        """
+        Remove a fn from the cache
+        Called from the parser in error cases
+        """
+        if fn in self.depends_cache:
+            self.logger.debug(1, "Removing %s from cache", fn)
+            del self.depends_cache[fn]
+        if fn in self.clean:
+            self.logger.debug(1, "Marking %s as unclean", fn)
+            self.clean.remove(fn)
+
+    def sync(self):
+        """
+        Save the cache
+        Called from the parser when complete (or exiting)
+        """
+
+        if not self.has_cache:
+            return
+
+        if self.cacheclean:
+            self.logger.debug(2, "Cache is clean, not saving.")
+            return
+
+        for cache_class in self.caches_array:
+            cache_class_name = cache_class.__name__
+            cachefile = self.getCacheFile(cache_class.cachefile)
+            self.logger.debug(2, "Writing %s", cachefile)
+            with open(cachefile, "wb") as f:
+                p = pickle.Pickler(f, pickle.HIGHEST_PROTOCOL)
+                p.dump(__cache_version__)
+                p.dump(bb.__version__)
+
+                for key, info_array in self.depends_cache.items():
+                    for info in info_array:
+                        if isinstance(info, RecipeInfoCommon) and info.__class__.__name__ == cache_class_name:
+                            p.dump(key)
+                            p.dump(info)
+
+        del self.depends_cache
+
+    @staticmethod
+    def mtime(cachefile):
+        return bb.parse.cached_mtime_noerror(cachefile)
+
+    def add_info(self, filename, info_array, cacheData, parsed=None, watcher=None):
+        if self.mc is not None:
+            (fn, cls, mc) = virtualfn2realfn(filename)
+            if mc:
+                self.logger.error("Unexpected multiconfig %s", filename)
+                return
+
+            vfn = realfn2virtual(fn, cls, self.mc)
+        else:
+            vfn = filename
+
+        if isinstance(info_array[0], CoreRecipeInfo) and (not info_array[0].skipped):
+            cacheData.add_from_recipeinfo(vfn, info_array)
+
+            if watcher:
+                watcher(info_array[0].file_depends)
+
+        if not self.has_cache:
+            return
+
+        if (info_array[0].skipped or 'SRCREVINACTION' not in info_array[0].pv) and not info_array[0].nocache:
+            if parsed:
+                self.cacheclean = False
+            self.depends_cache[filename] = info_array
+
+    def add(self, file_name, data, cacheData, parsed=None):
+        """
+        Save data we need into the cache
+        """
+
+        realfn = virtualfn2realfn(file_name)[0]
+
+        info_array = []
+        for cache_class in self.caches_array:
+            info_array.append(cache_class(realfn, data))
+        self.add_info(file_name, info_array, cacheData, parsed)
+
+class MulticonfigCache(Mapping):
+    def __init__(self, databuilder, data_hash, caches_array):
+        def progress(p):
+            nonlocal current_progress
+            nonlocal previous_progress
+            nonlocal previous_percent
+            nonlocal cachesize
+
+            current_progress = previous_progress + p
+
+            if current_progress > cachesize:
+                # we might have calculated incorrect total size because a file
+                # might've been written out just after we checked its size
+                cachesize = current_progress
+            current_percent = 100 * current_progress / cachesize
+            if current_percent > previous_percent:
+                previous_percent = current_percent
+                bb.event.fire(bb.event.CacheLoadProgress(current_progress, cachesize),
+                                databuilder.data)
+
+
+        cachesize = 0
+        current_progress = 0
+        previous_progress = 0
+        previous_percent = 0
+        self.__caches = {}
+
+        for mc, mcdata in databuilder.mcdata.items():
+            self.__caches[mc] = Cache(databuilder, mc, data_hash, caches_array)
+
+            cachesize += self.__caches[mc].cachesize()
+
+        bb.event.fire(bb.event.CacheLoadStarted(cachesize), databuilder.data)
+        loaded = 0
+
+        for c in self.__caches.values():
+            loaded += c.prepare_cache(progress)
+            previous_progress = current_progress
+
+        # Note: depends cache number is corresponding to the parsing file numbers.
+        # The same file has several caches, still regarded as one item in the cache
+        bb.event.fire(bb.event.CacheLoadCompleted(cachesize, loaded), databuilder.data)
+
+    def __len__(self):
+        return len(self.__caches)
+
+    def __getitem__(self, key):
+        return self.__caches[key]
+
+    def __contains__(self, key):
+        return key in self.__caches
+
+    def __iter__(self):
+        for k in self.__caches:
+            yield k
+
+    def keys(self):
+        return self.__caches[key]
+
+
+def init(cooker):
+    """
+    The Objective: Cache the minimum amount of data possible yet get to the
+    stage of building packages (i.e. tryBuild) without reparsing any .bb files.
+
+    To do this, we intercept getVar calls and only cache the variables we see
+    being accessed. We rely on the cache getVar calls being made for all
+    variables bitbake might need to use to reach this stage. For each cached
+    file we need to track:
+
+    * Its mtime
+    * The mtimes of all its dependencies
+    * Whether it caused a parse.SkipRecipe exception
+
+    Files causing parsing errors are evicted from the cache.
+
+    """
+    return Cache(cooker.configuration.data, cooker.configuration.data_hash)
+
+
+class CacheData(object):
+    """
+    The data structures we compile from the cached data
+    """
+
+    def __init__(self, caches_array):
+        self.caches_array = caches_array
+        for cache_class in self.caches_array:
+            if not issubclass(cache_class, RecipeInfoCommon):
+                bb.error("Extra cache data class %s should subclass RecipeInfoCommon class" % cache_class)
+            cache_class.init_cacheData(self)
+
+        # Direct cache variables
+        self.task_queues = {}
+        self.preferred = {}
+        self.tasks = {}
+        # Indirect Cache variables (set elsewhere)
+        self.ignored_dependencies = []
+        self.world_target = set()
+        self.bbfile_priority = {}
+
+    def add_from_recipeinfo(self, fn, info_array):
+        for info in info_array:
+            info.add_cacheData(self, fn)
+
+class MultiProcessCache(object):
+    """
+    BitBake multi-process cache implementation
+
+    Used by the codeparser & file checksum caches
+    """
+
+    def __init__(self):
+        self.cachefile = None
+        self.cachedata = self.create_cachedata()
+        self.cachedata_extras = self.create_cachedata()
+
+    def init_cache(self, d, cache_file_name=None):
+        cachedir = (d.getVar("PERSISTENT_DIR") or
+                    d.getVar("CACHE"))
+        if cachedir in [None, '']:
+            return
+        bb.utils.mkdirhier(cachedir)
+        self.cachefile = os.path.join(cachedir,
+                                      cache_file_name or self.__class__.cache_file_name)
+        logger.debug(1, "Using cache in '%s'", self.cachefile)
+
+        glf = bb.utils.lockfile(self.cachefile + ".lock")
+
+        try:
+            with open(self.cachefile, "rb") as f:
+                p = pickle.Unpickler(f)
+                data, version = p.load()
+        except:
+            bb.utils.unlockfile(glf)
+            return
+
+        bb.utils.unlockfile(glf)
+
+        if version != self.__class__.CACHE_VERSION:
+            return
+
+        self.cachedata = data
+
+    def create_cachedata(self):
+        data = [{}]
+        return data
+
+    def save_extras(self):
+        if not self.cachefile:
+            return
+
+        glf = bb.utils.lockfile(self.cachefile + ".lock", shared=True)
+
+        i = os.getpid()
+        lf = None
+        while not lf:
+            lf = bb.utils.lockfile(self.cachefile + ".lock." + str(i), retry=False)
+            if not lf or os.path.exists(self.cachefile + "-" + str(i)):
+                if lf:
+                    bb.utils.unlockfile(lf)
+                    lf = None
+                i = i + 1
+                continue
+
+            with open(self.cachefile + "-" + str(i), "wb") as f:
+                p = pickle.Pickler(f, -1)
+                p.dump([self.cachedata_extras, self.__class__.CACHE_VERSION])
+
+        bb.utils.unlockfile(lf)
+        bb.utils.unlockfile(glf)
+
+    def merge_data(self, source, dest):
+        for j in range(0,len(dest)):
+            for h in source[j]:
+                if h not in dest[j]:
+                    dest[j][h] = source[j][h]
+
+    def save_merge(self):
+        if not self.cachefile:
+            return
+
+        glf = bb.utils.lockfile(self.cachefile + ".lock")
+
+        data = self.cachedata
+
+        for f in [y for y in os.listdir(os.path.dirname(self.cachefile)) if y.startswith(os.path.basename(self.cachefile) + '-')]:
+            f = os.path.join(os.path.dirname(self.cachefile), f)
+            try:
+                with open(f, "rb") as fd:
+                    p = pickle.Unpickler(fd)
+                    extradata, version = p.load()
+            except (IOError, EOFError):
+                os.unlink(f)
+                continue
+
+            if version != self.__class__.CACHE_VERSION:
+                os.unlink(f)
+                continue
+
+            self.merge_data(extradata, data)
+            os.unlink(f)
+
+        with open(self.cachefile, "wb") as f:
+            p = pickle.Pickler(f, -1)
+            p.dump([data, self.__class__.CACHE_VERSION])
+
+        bb.utils.unlockfile(glf)
+
+
+class SimpleCache(object):
+    """
+    BitBake multi-process cache implementation
+
+    Used by the codeparser & file checksum caches
+    """
+
+    def __init__(self, version):
+        self.cachefile = None
+        self.cachedata = None
+        self.cacheversion = version
+
+    def init_cache(self, d, cache_file_name=None, defaultdata=None):
+        cachedir = (d.getVar("PERSISTENT_DIR") or
+                    d.getVar("CACHE"))
+        if not cachedir:
+            return defaultdata
+
+        bb.utils.mkdirhier(cachedir)
+        self.cachefile = os.path.join(cachedir,
+                                      cache_file_name or self.__class__.cache_file_name)
+        logger.debug(1, "Using cache in '%s'", self.cachefile)
+
+        glf = bb.utils.lockfile(self.cachefile + ".lock")
+
+        try:
+            with open(self.cachefile, "rb") as f:
+                p = pickle.Unpickler(f)
+                data, version = p.load()
+        except:
+            bb.utils.unlockfile(glf)
+            return defaultdata
+
+        bb.utils.unlockfile(glf)
+
+        if version != self.cacheversion:
+            return defaultdata
+
+        return data
+
+    def save(self, data):
+        if not self.cachefile:
+            return
+
+        glf = bb.utils.lockfile(self.cachefile + ".lock")
+
+        with open(self.cachefile, "wb") as f:
+            p = pickle.Pickler(f, -1)
+            p.dump([data, self.cacheversion])
+
+        bb.utils.unlockfile(glf)

+ 63 - 0
openembedded-core/bitbake/lib/bb/cache_extra.py

@@ -0,0 +1,63 @@
+#
+# Extra RecipeInfo will be all defined in this file. Currently,
+# Only Hob (Image Creator) Requests some extra fields. So
+# HobRecipeInfo is defined. It's named HobRecipeInfo because it
+# is introduced by 'hob'. Users could also introduce other
+# RecipeInfo or simply use those already defined RecipeInfo.
+# In the following patch, this newly defined new extra RecipeInfo
+# will be dynamically loaded and used for loading/saving the extra
+# cache fields  
+
+# Copyright (C) 2011, Intel Corporation. All rights reserved.
+
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+from bb.cache import RecipeInfoCommon
+
+class HobRecipeInfo(RecipeInfoCommon):
+    __slots__ = ()
+
+    classname = "HobRecipeInfo"
+    # please override this member with the correct data cache file
+    # such as (bb_cache.dat, bb_extracache_hob.dat) 
+    cachefile = "bb_extracache_" + classname +".dat"        
+
+    # override this member with the list of extra cache fields
+    # that this class will provide
+    cachefields = ['summary', 'license', 'section',
+            'description', 'homepage', 'bugtracker',
+            'prevision', 'files_info']
+
+    def __init__(self, filename, metadata):
+
+        self.summary = self.getvar('SUMMARY', metadata)
+        self.license = self.getvar('LICENSE', metadata)
+        self.section = self.getvar('SECTION', metadata)
+        self.description = self.getvar('DESCRIPTION', metadata)
+        self.homepage = self.getvar('HOMEPAGE', metadata)
+        self.bugtracker = self.getvar('BUGTRACKER', metadata)
+        self.prevision = self.getvar('PR', metadata)
+        self.files_info = self.getvar('FILES_INFO', metadata)
+
+    @classmethod
+    def init_cacheData(cls, cachedata):
+        # CacheData in Hob RecipeInfo Class
+        cachedata.summary = {}
+        cachedata.license = {}
+        cachedata.section = {}
+        cachedata.description = {}
+        cachedata.homepage = {}
+        cachedata.bugtracker = {}
+        cachedata.prevision = {}
+        cachedata.files_info = {}
+
+    def add_cacheData(self, cachedata, fn):
+        cachedata.summary[fn] = self.summary
+        cachedata.license[fn] = self.license
+        cachedata.section[fn] = self.section
+        cachedata.description[fn] = self.description
+        cachedata.homepage[fn] = self.homepage
+        cachedata.bugtracker[fn] = self.bugtracker
+        cachedata.prevision[fn] = self.prevision
+        cachedata.files_info[fn] = self.files_info

+ 126 - 0
openembedded-core/bitbake/lib/bb/checksum.py

@@ -0,0 +1,126 @@
+# Local file checksum cache implementation
+#
+# Copyright (C) 2012 Intel Corporation
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+import glob
+import operator
+import os
+import stat
+import bb.utils
+import logging
+from bb.cache import MultiProcessCache
+
+logger = logging.getLogger("BitBake.Cache")
+
+# mtime cache (non-persistent)
+# based upon the assumption that files do not change during bitbake run
+class FileMtimeCache(object):
+    cache = {}
+
+    def cached_mtime(self, f):
+        if f not in self.cache:
+            self.cache[f] = os.stat(f)[stat.ST_MTIME]
+        return self.cache[f]
+
+    def cached_mtime_noerror(self, f):
+        if f not in self.cache:
+            try:
+                self.cache[f] = os.stat(f)[stat.ST_MTIME]
+            except OSError:
+                return 0
+        return self.cache[f]
+
+    def update_mtime(self, f):
+        self.cache[f] = os.stat(f)[stat.ST_MTIME]
+        return self.cache[f]
+
+    def clear(self):
+        self.cache.clear()
+
+# Checksum + mtime cache (persistent)
+class FileChecksumCache(MultiProcessCache):
+    cache_file_name = "local_file_checksum_cache.dat"
+    CACHE_VERSION = 1
+
+    def __init__(self):
+        self.mtime_cache = FileMtimeCache()
+        MultiProcessCache.__init__(self)
+
+    def get_checksum(self, f):
+        entry = self.cachedata[0].get(f)
+        cmtime = self.mtime_cache.cached_mtime(f)
+        if entry:
+            (mtime, hashval) = entry
+            if cmtime == mtime:
+                return hashval
+            else:
+                bb.debug(2, "file %s changed mtime, recompute checksum" % f)
+
+        hashval = bb.utils.md5_file(f)
+        self.cachedata_extras[0][f] = (cmtime, hashval)
+        return hashval
+
+    def merge_data(self, source, dest):
+        for h in source[0]:
+            if h in dest:
+                (smtime, _) = source[0][h]
+                (dmtime, _) = dest[0][h]
+                if smtime > dmtime:
+                    dest[0][h] = source[0][h]
+            else:
+                dest[0][h] = source[0][h]
+
+    def get_checksums(self, filelist, pn, localdirsexclude):
+        """Get checksums for a list of files"""
+
+        def checksum_file(f):
+            try:
+                checksum = self.get_checksum(f)
+            except OSError as e:
+                bb.warn("Unable to get checksum for %s SRC_URI entry %s: %s" % (pn, os.path.basename(f), e))
+                return None
+            return checksum
+
+        def checksum_dir(pth):
+            # Handle directories recursively
+            if pth == "/":
+                bb.fatal("Refusing to checksum /")
+            dirchecksums = []
+            for root, dirs, files in os.walk(pth, topdown=True):
+                [dirs.remove(d) for d in list(dirs) if d in localdirsexclude]
+                for name in files:
+                    fullpth = os.path.join(root, name)
+                    checksum = checksum_file(fullpth)
+                    if checksum:
+                        dirchecksums.append((fullpth, checksum))
+            return dirchecksums
+
+        checksums = []
+        for pth in filelist.split():
+            exist = pth.split(":")[1]
+            if exist == "False":
+                continue
+            pth = pth.split(":")[0]
+            if '*' in pth:
+                # Handle globs
+                for f in glob.glob(pth):
+                    if os.path.isdir(f):
+                        if not os.path.islink(f):
+                            checksums.extend(checksum_dir(f))
+                    else:
+                        checksum = checksum_file(f)
+                        if checksum:
+                            checksums.append((f, checksum))
+            elif os.path.isdir(pth):
+                if not os.path.islink(pth):
+                    checksums.extend(checksum_dir(pth))
+            else:
+                checksum = checksum_file(pth)
+                if checksum:
+                    checksums.append((pth, checksum))
+
+        checksums.sort(key=operator.itemgetter(1))
+        return checksums

+ 459 - 0
openembedded-core/bitbake/lib/bb/codeparser.py

@@ -0,0 +1,459 @@
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+"""
+BitBake code parser
+
+Parses actual code (i.e. python and shell) for functions and in-line
+expressions. Used mainly to determine dependencies on other functions
+and variables within the BitBake metadata. Also provides a cache for
+this information in order to speed up processing.
+
+(Not to be confused with the code that parses the metadata itself,
+see lib/bb/parse/ for that).
+
+NOTE: if you change how the parsers gather information you will almost
+certainly need to increment CodeParserCache.CACHE_VERSION below so that
+any existing codeparser cache gets invalidated. Additionally you'll need
+to increment __cache_version__ in cache.py in order to ensure that old
+recipe caches don't trigger "Taskhash mismatch" errors.
+
+"""
+
+import ast
+import sys
+import codegen
+import logging
+import bb.pysh as pysh
+import bb.utils, bb.data
+import hashlib
+from itertools import chain
+from bb.pysh import pyshyacc, pyshlex
+from bb.cache import MultiProcessCache
+
+logger = logging.getLogger('BitBake.CodeParser')
+
+def bbhash(s):
+    return hashlib.sha256(s.encode("utf-8")).hexdigest()
+
+def check_indent(codestr):
+    """If the code is indented, add a top level piece of code to 'remove' the indentation"""
+
+    i = 0
+    while codestr[i] in ["\n", "\t", " "]:
+        i = i + 1
+
+    if i == 0:
+        return codestr
+
+    if codestr[i-1] == "\t" or codestr[i-1] == " ":
+        if codestr[0] == "\n":
+            # Since we're adding a line, we need to remove one line of any empty padding
+            # to ensure line numbers are correct
+            codestr = codestr[1:]
+        return "if 1:\n" + codestr
+
+    return codestr
+
+# A custom getstate/setstate using tuples is actually worth 15% cachesize by
+# avoiding duplication of the attribute names!
+
+
+class SetCache(object):
+    def __init__(self):
+        self.setcache = {}
+
+    def internSet(self, items):
+        
+        new = []
+        for i in items:
+            new.append(sys.intern(i))
+        s = frozenset(new)
+        h = hash(s)
+        if h in self.setcache:
+            return self.setcache[h]
+        self.setcache[h] = s
+        return s
+
+codecache = SetCache()
+
+class pythonCacheLine(object):
+    def __init__(self, refs, execs, contains):
+        self.refs = codecache.internSet(refs)
+        self.execs = codecache.internSet(execs)
+        self.contains = {}
+        for c in contains:
+            self.contains[c] = codecache.internSet(contains[c])
+
+    def __getstate__(self):
+        return (self.refs, self.execs, self.contains)
+
+    def __setstate__(self, state):
+        (refs, execs, contains) = state
+        self.__init__(refs, execs, contains)
+    def __hash__(self):
+        l = (hash(self.refs), hash(self.execs))
+        for c in sorted(self.contains.keys()):
+            l = l + (c, hash(self.contains[c]))
+        return hash(l)
+    def __repr__(self):
+        return " ".join([str(self.refs), str(self.execs), str(self.contains)]) 
+
+
+class shellCacheLine(object):
+    def __init__(self, execs):
+        self.execs = codecache.internSet(execs)
+
+    def __getstate__(self):
+        return (self.execs)
+
+    def __setstate__(self, state):
+        (execs) = state
+        self.__init__(execs)
+    def __hash__(self):
+        return hash(self.execs)
+    def __repr__(self):
+        return str(self.execs)
+
+class CodeParserCache(MultiProcessCache):
+    cache_file_name = "bb_codeparser.dat"
+    # NOTE: you must increment this if you change how the parsers gather information,
+    # so that an existing cache gets invalidated. Additionally you'll need
+    # to increment __cache_version__ in cache.py in order to ensure that old
+    # recipe caches don't trigger "Taskhash mismatch" errors.
+    CACHE_VERSION = 11
+
+    def __init__(self):
+        MultiProcessCache.__init__(self)
+        self.pythoncache = self.cachedata[0]
+        self.shellcache = self.cachedata[1]
+        self.pythoncacheextras = self.cachedata_extras[0]
+        self.shellcacheextras = self.cachedata_extras[1]
+
+        # To avoid duplication in the codeparser cache, keep
+        # a lookup of hashes of objects we already have
+        self.pythoncachelines = {}
+        self.shellcachelines = {}
+
+    def newPythonCacheLine(self, refs, execs, contains):
+        cacheline = pythonCacheLine(refs, execs, contains)
+        h = hash(cacheline)
+        if h in self.pythoncachelines:
+            return self.pythoncachelines[h]
+        self.pythoncachelines[h] = cacheline
+        return cacheline
+
+    def newShellCacheLine(self, execs):
+        cacheline = shellCacheLine(execs)
+        h = hash(cacheline)
+        if h in self.shellcachelines:
+            return self.shellcachelines[h]
+        self.shellcachelines[h] = cacheline
+        return cacheline
+
+    def init_cache(self, d):
+        # Check if we already have the caches
+        if self.pythoncache:
+            return
+
+        MultiProcessCache.init_cache(self, d)
+
+        # cachedata gets re-assigned in the parent
+        self.pythoncache = self.cachedata[0]
+        self.shellcache = self.cachedata[1]
+
+    def create_cachedata(self):
+        data = [{}, {}]
+        return data
+
+codeparsercache = CodeParserCache()
+
+def parser_cache_init(d):
+    codeparsercache.init_cache(d)
+
+def parser_cache_save():
+    codeparsercache.save_extras()
+
+def parser_cache_savemerge():
+    codeparsercache.save_merge()
+
+Logger = logging.getLoggerClass()
+class BufferedLogger(Logger):
+    def __init__(self, name, level=0, target=None):
+        Logger.__init__(self, name)
+        self.setLevel(level)
+        self.buffer = []
+        self.target = target
+
+    def handle(self, record):
+        self.buffer.append(record)
+
+    def flush(self):
+        for record in self.buffer:
+            if self.target.isEnabledFor(record.levelno):
+                self.target.handle(record)
+        self.buffer = []
+
+class PythonParser():
+    getvars = (".getVar", ".appendVar", ".prependVar", "oe.utils.conditional")
+    getvarflags = (".getVarFlag", ".appendVarFlag", ".prependVarFlag")
+    containsfuncs = ("bb.utils.contains", "base_contains")
+    containsanyfuncs = ("bb.utils.contains_any",  "bb.utils.filter")
+    execfuncs = ("bb.build.exec_func", "bb.build.exec_task")
+
+    def warn(self, func, arg):
+        """Warn about calls of bitbake APIs which pass a non-literal
+        argument for the variable name, as we're not able to track such
+        a reference.
+        """
+
+        try:
+            funcstr = codegen.to_source(func)
+            argstr = codegen.to_source(arg)
+        except TypeError:
+            self.log.debug(2, 'Failed to convert function and argument to source form')
+        else:
+            self.log.debug(1, self.unhandled_message % (funcstr, argstr))
+
+    def visit_Call(self, node):
+        name = self.called_node_name(node.func)
+        if name and (name.endswith(self.getvars) or name.endswith(self.getvarflags) or name in self.containsfuncs or name in self.containsanyfuncs):
+            if isinstance(node.args[0], ast.Str):
+                varname = node.args[0].s
+                if name in self.containsfuncs and isinstance(node.args[1], ast.Str):
+                    if varname not in self.contains:
+                        self.contains[varname] = set()
+                    self.contains[varname].add(node.args[1].s)
+                elif name in self.containsanyfuncs and isinstance(node.args[1], ast.Str):
+                    if varname not in self.contains:
+                        self.contains[varname] = set()
+                    self.contains[varname].update(node.args[1].s.split())
+                elif name.endswith(self.getvarflags):
+                    if isinstance(node.args[1], ast.Str):
+                        self.references.add('%s[%s]' % (varname, node.args[1].s))
+                    else:
+                        self.warn(node.func, node.args[1])
+                else:
+                    self.references.add(varname)
+            else:
+                self.warn(node.func, node.args[0])
+        elif name and name.endswith(".expand"):
+            if isinstance(node.args[0], ast.Str):
+                value = node.args[0].s
+                d = bb.data.init()
+                parser = d.expandWithRefs(value, self.name)
+                self.references |= parser.references
+                self.execs |= parser.execs
+                for varname in parser.contains:
+                    if varname not in self.contains:
+                        self.contains[varname] = set()
+                    self.contains[varname] |= parser.contains[varname]
+        elif name in self.execfuncs:
+            if isinstance(node.args[0], ast.Str):
+                self.var_execs.add(node.args[0].s)
+            else:
+                self.warn(node.func, node.args[0])
+        elif name and isinstance(node.func, (ast.Name, ast.Attribute)):
+            self.execs.add(name)
+
+    def called_node_name(self, node):
+        """Given a called node, return its original string form"""
+        components = []
+        while node:
+            if isinstance(node, ast.Attribute):
+                components.append(node.attr)
+                node = node.value
+            elif isinstance(node, ast.Name):
+                components.append(node.id)
+                return '.'.join(reversed(components))
+            else:
+                break
+
+    def __init__(self, name, log):
+        self.name = name
+        self.var_execs = set()
+        self.contains = {}
+        self.execs = set()
+        self.references = set()
+        self.log = BufferedLogger('BitBake.Data.PythonParser', logging.DEBUG, log)
+
+        self.unhandled_message = "in call of %s, argument '%s' is not a string literal"
+        self.unhandled_message = "while parsing %s, %s" % (name, self.unhandled_message)
+
+    def parse_python(self, node, lineno=0, filename="<string>"):
+        if not node or not node.strip():
+            return
+
+        h = bbhash(str(node))
+
+        if h in codeparsercache.pythoncache:
+            self.references = set(codeparsercache.pythoncache[h].refs)
+            self.execs = set(codeparsercache.pythoncache[h].execs)
+            self.contains = {}
+            for i in codeparsercache.pythoncache[h].contains:
+                self.contains[i] = set(codeparsercache.pythoncache[h].contains[i])
+            return
+
+        if h in codeparsercache.pythoncacheextras:
+            self.references = set(codeparsercache.pythoncacheextras[h].refs)
+            self.execs = set(codeparsercache.pythoncacheextras[h].execs)
+            self.contains = {}
+            for i in codeparsercache.pythoncacheextras[h].contains:
+                self.contains[i] = set(codeparsercache.pythoncacheextras[h].contains[i])
+            return
+
+        # We can't add to the linenumbers for compile, we can pad to the correct number of blank lines though
+        node = "\n" * int(lineno) + node
+        code = compile(check_indent(str(node)), filename, "exec",
+                       ast.PyCF_ONLY_AST)
+
+        for n in ast.walk(code):
+            if n.__class__.__name__ == "Call":
+                self.visit_Call(n)
+
+        self.execs.update(self.var_execs)
+
+        codeparsercache.pythoncacheextras[h] = codeparsercache.newPythonCacheLine(self.references, self.execs, self.contains)
+
+class ShellParser():
+    def __init__(self, name, log):
+        self.funcdefs = set()
+        self.allexecs = set()
+        self.execs = set()
+        self.log = BufferedLogger('BitBake.Data.%s' % name, logging.DEBUG, log)
+        self.unhandled_template = "unable to handle non-literal command '%s'"
+        self.unhandled_template = "while parsing %s, %s" % (name, self.unhandled_template)
+
+    def parse_shell(self, value):
+        """Parse the supplied shell code in a string, returning the external
+        commands it executes.
+        """
+
+        h = bbhash(str(value))
+
+        if h in codeparsercache.shellcache:
+            self.execs = set(codeparsercache.shellcache[h].execs)
+            return self.execs
+
+        if h in codeparsercache.shellcacheextras:
+            self.execs = set(codeparsercache.shellcacheextras[h].execs)
+            return self.execs
+
+        self._parse_shell(value)
+        self.execs = set(cmd for cmd in self.allexecs if cmd not in self.funcdefs)
+
+        codeparsercache.shellcacheextras[h] = codeparsercache.newShellCacheLine(self.execs)
+
+        return self.execs
+
+    def _parse_shell(self, value):
+        try:
+            tokens, _ = pyshyacc.parse(value, eof=True, debug=False)
+        except Exception:
+            bb.error('Error during parse shell code, the last 5 lines are:\n%s' % '\n'.join(value.split('\n')[-5:]))
+            raise
+
+        self.process_tokens(tokens)
+
+    def process_tokens(self, tokens):
+        """Process a supplied portion of the syntax tree as returned by
+        pyshyacc.parse.
+        """
+
+        def function_definition(value):
+            self.funcdefs.add(value.name)
+            return [value.body], None
+
+        def case_clause(value):
+            # Element 0 of each item in the case is the list of patterns, and
+            # Element 1 of each item in the case is the list of commands to be
+            # executed when that pattern matches.
+            words = chain(*[item[0] for item in value.items])
+            cmds  = chain(*[item[1] for item in value.items])
+            return cmds, words
+
+        def if_clause(value):
+            main = chain(value.cond, value.if_cmds)
+            rest = value.else_cmds
+            if isinstance(rest, tuple) and rest[0] == "elif":
+                return chain(main, if_clause(rest[1]))
+            else:
+                return chain(main, rest)
+
+        def simple_command(value):
+            return None, chain(value.words, (assign[1] for assign in value.assigns))
+
+        token_handlers = {
+            "and_or": lambda x: ((x.left, x.right), None),
+            "async": lambda x: ([x], None),
+            "brace_group": lambda x: (x.cmds, None),
+            "for_clause": lambda x: (x.cmds, x.items),
+            "function_definition": function_definition,
+            "if_clause": lambda x: (if_clause(x), None),
+            "pipeline": lambda x: (x.commands, None),
+            "redirect_list": lambda x: ([x.cmd], None),
+            "subshell": lambda x: (x.cmds, None),
+            "while_clause": lambda x: (chain(x.condition, x.cmds), None),
+            "until_clause": lambda x: (chain(x.condition, x.cmds), None),
+            "simple_command": simple_command,
+            "case_clause": case_clause,
+        }
+
+        def process_token_list(tokens):
+            for token in tokens:
+                if isinstance(token, list):
+                    process_token_list(token)
+                    continue
+                name, value = token
+                try:
+                    more_tokens, words = token_handlers[name](value)
+                except KeyError:
+                    raise NotImplementedError("Unsupported token type " + name)
+
+                if more_tokens:
+                    self.process_tokens(more_tokens)
+
+                if words:
+                    self.process_words(words)
+
+        process_token_list(tokens)
+
+    def process_words(self, words):
+        """Process a set of 'words' in pyshyacc parlance, which includes
+        extraction of executed commands from $() blocks, as well as grabbing
+        the command name argument.
+        """
+
+        words = list(words)
+        for word in list(words):
+            wtree = pyshlex.make_wordtree(word[1])
+            for part in wtree:
+                if not isinstance(part, list):
+                    continue
+
+                if part[0] in ('`', '$('):
+                    command = pyshlex.wordtree_as_string(part[1:-1])
+                    self._parse_shell(command)
+
+                    if word[0] in ("cmd_name", "cmd_word"):
+                        if word in words:
+                            words.remove(word)
+
+        usetoken = False
+        for word in words:
+            if word[0] in ("cmd_name", "cmd_word") or \
+               (usetoken and word[0] == "TOKEN"):
+                if "=" in word[1]:
+                    usetoken = True
+                    continue
+
+                cmd = word[1]
+                if cmd.startswith("$"):
+                    self.log.debug(1, self.unhandled_template % cmd)
+                elif cmd == "eval":
+                    command = " ".join(word for _, word in words[1:])
+                    self._parse_shell(command)
+                else:
+                    self.allexecs.add(cmd)
+                break

+ 744 - 0
openembedded-core/bitbake/lib/bb/command.py

@@ -0,0 +1,744 @@
+"""
+BitBake 'Command' module
+
+Provide an interface to interact with the bitbake server through 'commands'
+"""
+
+# Copyright (C) 2006-2007  Richard Purdie
+#
+# SPDX-License-Identifier: GPL-2.0-only
+#
+
+"""
+The bitbake server takes 'commands' from its UI/commandline.
+Commands are either synchronous or asynchronous.
+Async commands return data to the client in the form of events.
+Sync commands must only return data through the function return value
+and must not trigger events, directly or indirectly.
+Commands are queued in a CommandQueue
+"""
+
+from collections import OrderedDict, defaultdict
+
+import bb.event
+import bb.cooker
+import bb.remotedata
+
+class DataStoreConnectionHandle(object):
+    def __init__(self, dsindex=0):
+        self.dsindex = dsindex
+
+class CommandCompleted(bb.event.Event):
+    pass
+
+class CommandExit(bb.event.Event):
+    def  __init__(self, exitcode):
+        bb.event.Event.__init__(self)
+        self.exitcode = int(exitcode)
+
+class CommandFailed(CommandExit):
+    def __init__(self, message):
+        self.error = message
+        CommandExit.__init__(self, 1)
+    def __str__(self):
+        return "Command execution failed: %s" % self.error
+
+class CommandError(Exception):
+    pass
+
+class Command:
+    """
+    A queue of asynchronous commands for bitbake
+    """
+    def __init__(self, cooker):
+        self.cooker = cooker
+        self.cmds_sync = CommandsSync()
+        self.cmds_async = CommandsAsync()
+        self.remotedatastores = None
+
+        # FIXME Add lock for this
+        self.currentAsyncCommand = None
+
+    def runCommand(self, commandline, ro_only = False):
+        command = commandline.pop(0)
+
+        # Ensure cooker is ready for commands
+        if command != "updateConfig" and command != "setFeatures":
+            self.cooker.init_configdata()
+            if not self.remotedatastores:
+                self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
+
+        if hasattr(CommandsSync, command):
+            # Can run synchronous commands straight away
+            command_method = getattr(self.cmds_sync, command)
+            if ro_only:
+                if not hasattr(command_method, 'readonly') or not getattr(command_method, 'readonly'):
+                    return None, "Not able to execute not readonly commands in readonly mode"
+            try:
+                self.cooker.process_inotify_updates()
+                if getattr(command_method, 'needconfig', True):
+                    self.cooker.updateCacheSync()
+                result = command_method(self, commandline)
+            except CommandError as exc:
+                return None, exc.args[0]
+            except (Exception, SystemExit) as exc:
+                import traceback
+                if isinstance(exc, bb.BBHandledException):
+                    # We need to start returning real exceptions here. Until we do, we can't
+                    # tell if an exception is an instance of bb.BBHandledException
+                    return None, "bb.BBHandledException()\n" + traceback.format_exc()
+                return None, traceback.format_exc()
+            else:
+                return result, None
+        if self.currentAsyncCommand is not None:
+            return None, "Busy (%s in progress)" % self.currentAsyncCommand[0]
+        if command not in CommandsAsync.__dict__:
+            return None, "No such command"
+        self.currentAsyncCommand = (command, commandline)
+        self.cooker.idleCallBackRegister(self.cooker.runCommands, self.cooker)
+        return True, None
+
+    def runAsyncCommand(self):
+        try:
+            self.cooker.process_inotify_updates()
+            if self.cooker.state in (bb.cooker.state.error, bb.cooker.state.shutdown, bb.cooker.state.forceshutdown):
+                # updateCache will trigger a shutdown of the parser
+                # and then raise BBHandledException triggering an exit
+                self.cooker.updateCache()
+                return False
+            if self.currentAsyncCommand is not None:
+                (command, options) = self.currentAsyncCommand
+                commandmethod = getattr(CommandsAsync, command)
+                needcache = getattr( commandmethod, "needcache" )
+                if needcache and self.cooker.state != bb.cooker.state.running:
+                    self.cooker.updateCache()
+                    return True
+                else:
+                    commandmethod(self.cmds_async, self, options)
+                    return False
+            else:
+                return False
+        except KeyboardInterrupt as exc:
+            self.finishAsyncCommand("Interrupted")
+            return False
+        except SystemExit as exc:
+            arg = exc.args[0]
+            if isinstance(arg, str):
+                self.finishAsyncCommand(arg)
+            else:
+                self.finishAsyncCommand("Exited with %s" % arg)
+            return False
+        except Exception as exc:
+            import traceback
+            if isinstance(exc, bb.BBHandledException):
+                self.finishAsyncCommand("")
+            else:
+                self.finishAsyncCommand(traceback.format_exc())
+            return False
+
+    def finishAsyncCommand(self, msg=None, code=None):
+        if msg or msg == "":
+            bb.event.fire(CommandFailed(msg), self.cooker.data)
+        elif code:
+            bb.event.fire(CommandExit(code), self.cooker.data)
+        else:
+            bb.event.fire(CommandCompleted(), self.cooker.data)
+        self.currentAsyncCommand = None
+        self.cooker.finishcommand()
+
+    def reset(self):
+        if self.remotedatastores:
+           self.remotedatastores = bb.remotedata.RemoteDatastores(self.cooker)
+
+class CommandsSync:
+    """
+    A class of synchronous commands
+    These should run quickly so as not to hurt interactive performance.
+    These must not influence any running synchronous command.
+    """
+
+    def stateShutdown(self, command, params):
+        """
+        Trigger cooker 'shutdown' mode
+        """
+        command.cooker.shutdown(False)
+
+    def stateForceShutdown(self, command, params):
+        """
+        Stop the cooker
+        """
+        command.cooker.shutdown(True)
+
+    def getAllKeysWithFlags(self, command, params):
+        """
+        Returns a dump of the global state. Call with
+        variable flags to be retrieved as params.
+        """
+        flaglist = params[0]
+        return command.cooker.getAllKeysWithFlags(flaglist)
+    getAllKeysWithFlags.readonly = True
+
+    def getVariable(self, command, params):
+        """
+        Read the value of a variable from data
+        """
+        varname = params[0]
+        expand = True
+        if len(params) > 1:
+            expand = (params[1] == "True")
+
+        return command.cooker.data.getVar(varname, expand)
+    getVariable.readonly = True
+
+    def setVariable(self, command, params):
+        """
+        Set the value of variable in data
+        """
+        varname = params[0]
+        value = str(params[1])
+        command.cooker.extraconfigdata[varname] = value
+        command.cooker.data.setVar(varname, value)
+
+    def getSetVariable(self, command, params):
+        """
+        Read the value of a variable from data and set it into the datastore
+        which effectively expands and locks the value.
+        """
+        varname = params[0]
+        result = self.getVariable(command, params)
+        command.cooker.data.setVar(varname, result)
+        return result
+
+    def setConfig(self, command, params):
+        """
+        Set the value of variable in configuration
+        """
+        varname = params[0]
+        value = str(params[1])
+        setattr(command.cooker.configuration, varname, value)
+
+    def enableDataTracking(self, command, params):
+        """
+        Enable history tracking for variables
+        """
+        command.cooker.enableDataTracking()
+
+    def disableDataTracking(self, command, params):
+        """
+        Disable history tracking for variables
+        """
+        command.cooker.disableDataTracking()
+
+    def setPrePostConfFiles(self, command, params):
+        prefiles = params[0].split()
+        postfiles = params[1].split()
+        command.cooker.configuration.prefile = prefiles
+        command.cooker.configuration.postfile = postfiles
+    setPrePostConfFiles.needconfig = False
+
+    def matchFile(self, command, params):
+        fMatch = params[0]
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.matchFile(fMatch, mc)
+    matchFile.needconfig = False
+
+    def getUIHandlerNum(self, command, params):
+        return bb.event.get_uihandler()
+    getUIHandlerNum.needconfig = False
+    getUIHandlerNum.readonly = True
+
+    def setEventMask(self, command, params):
+        handlerNum = params[0]
+        llevel = params[1]
+        debug_domains = params[2]
+        mask = params[3]
+        return bb.event.set_UIHmask(handlerNum, llevel, debug_domains, mask)
+    setEventMask.needconfig = False
+    setEventMask.readonly = True
+
+    def setFeatures(self, command, params):
+        """
+        Set the cooker features to include the passed list of features
+        """
+        features = params[0]
+        command.cooker.setFeatures(features)
+    setFeatures.needconfig = False
+    # although we change the internal state of the cooker, this is transparent since
+    # we always take and leave the cooker in state.initial
+    setFeatures.readonly = True
+
+    def updateConfig(self, command, params):
+        options = params[0]
+        environment = params[1]
+        cmdline = params[2]
+        command.cooker.updateConfigOpts(options, environment, cmdline)
+    updateConfig.needconfig = False
+
+    def parseConfiguration(self, command, params):
+        """Instruct bitbake to parse its configuration
+        NOTE: it is only necessary to call this if you aren't calling any normal action
+        (otherwise parsing is taken care of automatically)
+        """
+        command.cooker.parseConfiguration()
+    parseConfiguration.needconfig = False
+
+    def getLayerPriorities(self, command, params):
+        command.cooker.parseConfiguration()
+        ret = []
+        # regex objects cannot be marshalled by xmlrpc
+        for collection, pattern, regex, pri in command.cooker.bbfile_config_priorities:
+            ret.append((collection, pattern, regex.pattern, pri))
+        return ret
+    getLayerPriorities.readonly = True
+
+    def getRecipes(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return list(command.cooker.recipecaches[mc].pkg_pn.items())
+    getRecipes.readonly = True
+
+    def getRecipeDepends(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return list(command.cooker.recipecaches[mc].deps.items())
+    getRecipeDepends.readonly = True
+
+    def getRecipeVersions(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.recipecaches[mc].pkg_pepvpr
+    getRecipeVersions.readonly = True
+
+    def getRecipeProvides(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.recipecaches[mc].fn_provides
+    getRecipeProvides.readonly = True
+
+    def getRecipePackages(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.recipecaches[mc].packages
+    getRecipePackages.readonly = True
+
+    def getRecipePackagesDynamic(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.recipecaches[mc].packages_dynamic
+    getRecipePackagesDynamic.readonly = True
+
+    def getRProviders(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.recipecaches[mc].rproviders
+    getRProviders.readonly = True
+
+    def getRuntimeDepends(self, command, params):
+        ret = []
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        rundeps = command.cooker.recipecaches[mc].rundeps
+        for key, value in rundeps.items():
+            if isinstance(value, defaultdict):
+                value = dict(value)
+            ret.append((key, value))
+        return ret
+    getRuntimeDepends.readonly = True
+
+    def getRuntimeRecommends(self, command, params):
+        ret = []
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        runrecs = command.cooker.recipecaches[mc].runrecs
+        for key, value in runrecs.items():
+            if isinstance(value, defaultdict):
+                value = dict(value)
+            ret.append((key, value))
+        return ret
+    getRuntimeRecommends.readonly = True
+
+    def getRecipeInherits(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.recipecaches[mc].inherits
+    getRecipeInherits.readonly = True
+
+    def getBbFilePriority(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.recipecaches[mc].bbfile_priority
+    getBbFilePriority.readonly = True
+
+    def getDefaultPreference(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.recipecaches[mc].pkg_dp
+    getDefaultPreference.readonly = True
+
+    def getSkippedRecipes(self, command, params):
+        # Return list sorted by reverse priority order
+        import bb.cache
+        def sortkey(x):
+            vfn, _ = x
+            realfn, _, mc = bb.cache.virtualfn2realfn(vfn)
+            return (-command.cooker.collections[mc].calc_bbfile_priority(realfn)[0], vfn)
+
+        skipdict = OrderedDict(sorted(command.cooker.skiplist.items(), key=sortkey))
+        return list(skipdict.items())
+    getSkippedRecipes.readonly = True
+
+    def getOverlayedRecipes(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return list(command.cooker.collections[mc].overlayed.items())
+    getOverlayedRecipes.readonly = True
+
+    def getFileAppends(self, command, params):
+        fn = params[0]
+        try:
+            mc = params[1]
+        except IndexError:
+            mc = ''
+        return command.cooker.collections[mc].get_file_appends(fn)
+    getFileAppends.readonly = True
+
+    def getAllAppends(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.collections[mc].bbappends
+    getAllAppends.readonly = True
+
+    def findProviders(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return command.cooker.findProviders(mc)
+    findProviders.readonly = True
+
+    def findBestProvider(self, command, params):
+        (mc, pn) = bb.runqueue.split_mc(params[0])
+        return command.cooker.findBestProvider(pn, mc)
+    findBestProvider.readonly = True
+
+    def allProviders(self, command, params):
+        try:
+            mc = params[0]
+        except IndexError:
+            mc = ''
+        return list(bb.providers.allProviders(command.cooker.recipecaches[mc]).items())
+    allProviders.readonly = True
+
+    def getRuntimeProviders(self, command, params):
+        rprovide = params[0]
+        try:
+            mc = params[1]
+        except IndexError:
+            mc = ''
+        all_p = bb.providers.getRuntimeProviders(command.cooker.recipecaches[mc], rprovide)
+        if all_p:
+            best = bb.providers.filterProvidersRunTime(all_p, rprovide,
+                            command.cooker.data,
+                            command.cooker.recipecaches[mc])[0][0]
+        else:
+            best = None
+        return all_p, best
+    getRuntimeProviders.readonly = True
+
+    def dataStoreConnectorCmd(self, command, params):
+        dsindex = params[0]
+        method = params[1]
+        args = params[2]
+        kwargs = params[3]
+
+        d = command.remotedatastores[dsindex]
+        ret = getattr(d, method)(*args, **kwargs)
+
+        if isinstance(ret, bb.data_smart.DataSmart):
+            idx = command.remotedatastores.store(ret)
+            return DataStoreConnectionHandle(idx)
+
+        return ret
+
+    def dataStoreConnectorVarHistCmd(self, command, params):
+        dsindex = params[0]
+        method = params[1]
+        args = params[2]
+        kwargs = params[3]
+
+        d = command.remotedatastores[dsindex].varhistory
+        return getattr(d, method)(*args, **kwargs)
+
+    def dataStoreConnectorIncHistCmd(self, command, params):
+        dsindex = params[0]
+        method = params[1]
+        args = params[2]
+        kwargs = params[3]
+
+        d = command.remotedatastores[dsindex].inchistory
+        return getattr(d, method)(*args, **kwargs)
+
+    def dataStoreConnectorRelease(self, command, params):
+        dsindex = params[0]
+        if dsindex <= 0:
+            raise CommandError('dataStoreConnectorRelease: invalid index %d' % dsindex)
+        command.remotedatastores.release(dsindex)
+
+    def parseRecipeFile(self, command, params):
+        """
+        Parse the specified recipe file (with or without bbappends)
+        and return a datastore object representing the environment
+        for the recipe.
+        """
+        fn = params[0]
+        mc = bb.runqueue.mc_from_tid(fn)
+        appends = params[1]
+        appendlist = params[2]
+        if len(params) > 3:
+            config_data = command.remotedatastores[params[3]]
+        else:
+            config_data = None
+
+        if appends:
+            if appendlist is not None:
+                appendfiles = appendlist
+            else:
+                appendfiles = command.cooker.collections[mc].get_file_appends(fn)
+        else:
+            appendfiles = []
+        # We are calling bb.cache locally here rather than on the server,
+        # but that's OK because it doesn't actually need anything from
+        # the server barring the global datastore (which we have a remote
+        # version of)
+        if config_data:
+            # We have to use a different function here if we're passing in a datastore
+            # NOTE: we took a copy above, so we don't do it here again
+            envdata = bb.cache.parse_recipe(config_data, fn, appendfiles, mc)['']
+        else:
+            # Use the standard path
+            parser = bb.cache.NoCache(command.cooker.databuilder)
+            envdata = parser.loadDataFull(fn, appendfiles)
+        idx = command.remotedatastores.store(envdata)
+        return DataStoreConnectionHandle(idx)
+    parseRecipeFile.readonly = True
+
+class CommandsAsync:
+    """
+    A class of asynchronous commands
+    These functions communicate via generated events.
+    Any function that requires metadata parsing should be here.
+    """
+
+    def buildFile(self, command, params):
+        """
+        Build a single specified .bb file
+        """
+        bfile = params[0]
+        task = params[1]
+        if len(params) > 2:
+            internal = params[2]
+        else:
+            internal = False
+
+        if internal:
+            command.cooker.buildFileInternal(bfile, task, fireevents=False, quietlog=True)
+        else:
+            command.cooker.buildFile(bfile, task)
+    buildFile.needcache = False
+
+    def buildTargets(self, command, params):
+        """
+        Build a set of targets
+        """
+        pkgs_to_build = params[0]
+        task = params[1]
+
+        command.cooker.buildTargets(pkgs_to_build, task)
+    buildTargets.needcache = True
+
+    def generateDepTreeEvent(self, command, params):
+        """
+        Generate an event containing the dependency information
+        """
+        pkgs_to_build = params[0]
+        task = params[1]
+
+        command.cooker.generateDepTreeEvent(pkgs_to_build, task)
+        command.finishAsyncCommand()
+    generateDepTreeEvent.needcache = True
+
+    def generateDotGraph(self, command, params):
+        """
+        Dump dependency information to disk as .dot files
+        """
+        pkgs_to_build = params[0]
+        task = params[1]
+
+        command.cooker.generateDotGraphFiles(pkgs_to_build, task)
+        command.finishAsyncCommand()
+    generateDotGraph.needcache = True
+
+    def generateTargetsTree(self, command, params):
+        """
+        Generate a tree of buildable targets.
+        If klass is provided ensure all recipes that inherit the class are
+        included in the package list.
+        If pkg_list provided use that list (plus any extras brought in by
+        klass) rather than generating a tree for all packages.
+        """
+        klass = params[0]
+        pkg_list = params[1]
+
+        command.cooker.generateTargetsTree(klass, pkg_list)
+        command.finishAsyncCommand()
+    generateTargetsTree.needcache = True
+
+    def findConfigFiles(self, command, params):
+        """
+        Find config files which provide appropriate values
+        for the passed configuration variable. i.e. MACHINE
+        """
+        varname = params[0]
+
+        command.cooker.findConfigFiles(varname)
+        command.finishAsyncCommand()
+    findConfigFiles.needcache = False
+
+    def findFilesMatchingInDir(self, command, params):
+        """
+        Find implementation files matching the specified pattern
+        in the requested subdirectory of a BBPATH
+        """
+        pattern = params[0]
+        directory = params[1]
+
+        command.cooker.findFilesMatchingInDir(pattern, directory)
+        command.finishAsyncCommand()
+    findFilesMatchingInDir.needcache = False
+
+    def findConfigFilePath(self, command, params):
+        """
+        Find the path of the requested configuration file
+        """
+        configfile = params[0]
+
+        command.cooker.findConfigFilePath(configfile)
+        command.finishAsyncCommand()
+    findConfigFilePath.needcache = False
+
+    def showVersions(self, command, params):
+        """
+        Show the currently selected versions
+        """
+        command.cooker.showVersions()
+        command.finishAsyncCommand()
+    showVersions.needcache = True
+
+    def showEnvironmentTarget(self, command, params):
+        """
+        Print the environment of a target recipe
+        (needs the cache to work out which recipe to use)
+        """
+        pkg = params[0]
+
+        command.cooker.showEnvironment(None, pkg)
+        command.finishAsyncCommand()
+    showEnvironmentTarget.needcache = True
+
+    def showEnvironment(self, command, params):
+        """
+        Print the standard environment
+        or if specified the environment for a specified recipe
+        """
+        bfile = params[0]
+
+        command.cooker.showEnvironment(bfile)
+        command.finishAsyncCommand()
+    showEnvironment.needcache = False
+
+    def parseFiles(self, command, params):
+        """
+        Parse the .bb files
+        """
+        command.cooker.updateCache()
+        command.finishAsyncCommand()
+    parseFiles.needcache = True
+
+    def compareRevisions(self, command, params):
+        """
+        Parse the .bb files
+        """
+        if bb.fetch.fetcher_compare_revisions(command.cooker.data):
+            command.finishAsyncCommand(code=1)
+        else:
+            command.finishAsyncCommand()
+    compareRevisions.needcache = True
+
+    def triggerEvent(self, command, params):
+        """
+        Trigger a certain event
+        """
+        event = params[0]
+        bb.event.fire(eval(event), command.cooker.data)
+        command.currentAsyncCommand = None
+    triggerEvent.needcache = False
+
+    def resetCooker(self, command, params):
+        """
+        Reset the cooker to its initial state, thus forcing a reparse for
+        any async command that has the needcache property set to True
+        """
+        command.cooker.reset()
+        command.finishAsyncCommand()
+    resetCooker.needcache = False
+
+    def clientComplete(self, command, params):
+        """
+        Do the right thing when the controlling client exits
+        """
+        command.cooker.clientComplete()
+        command.finishAsyncCommand()
+    clientComplete.needcache = False
+
+    def findSigInfo(self, command, params):
+        """
+        Find signature info files via the signature generator
+        """
+        (mc, pn) = bb.runqueue.split_mc(params[0])
+        taskname = params[1]
+        sigs = params[2]
+        res = bb.siggen.find_siginfo(pn, taskname, sigs, command.cooker.databuilder.mcdata[mc])
+        bb.event.fire(bb.event.FindSigInfoResult(res), command.cooker.databuilder.mcdata[mc])
+        command.finishAsyncCommand()
+    findSigInfo.needcache = False

Some files were not shown because too many files changed in this diff