diff mbox series

[meta-darwin,1/1] Add DMG and PKG SDK installers

Message ID 20260202165146.3727-3-dev@qinc.tv
State New
Headers show
Series macOS DMG/PKG | expand

Commit Message

Eric L. Hernes Feb. 2, 2026, 4:51 p.m. UTC
This adds support for generating both .dmg and .pkg installers.

The .dmg will require running the `finalize-dmg` to relocate and sign
the executables.

The .pkg automates the process and integrates the relocation and
signage into the installer.

Signed-off-by: Eric L. Hernes <dev@qinc.tv>
---
 README                                      |  19 ++
 conf/files/darwin-toolchain-shar-extract.sh | 316 ++++++++++++++++++++
 conf/files/finalize-sdk.sh                  |  48 +++
 conf/files/mk-macos-dmg.sh                  |  49 +++
 conf/files/mk-macos-pkg.sh                  | 161 ++++++++++
 conf/files/post-install.in                  |   9 +
 conf/files/pre-install.in                   |  84 ++++++
 conf/layer.conf                             |   3 +
 conf/machine-sdk/darwin-common.inc          |  54 +++-
 9 files changed, 741 insertions(+), 2 deletions(-)
 create mode 100644 conf/files/darwin-toolchain-shar-extract.sh
 create mode 100644 conf/files/finalize-sdk.sh
 create mode 100755 conf/files/mk-macos-dmg.sh
 create mode 100755 conf/files/mk-macos-pkg.sh
 create mode 100644 conf/files/post-install.in
 create mode 100644 conf/files/pre-install.in

Comments

Etienne Cordonnier Feb. 27, 2026, 12:15 p.m. UTC | #1
Hi Eric,
sorry for the delay.
- I have tested some local build of some custom image, and it seems the pkg
and dmg packages are quite big, compared to the traditional sh files. I'm
not familiar with those packaging formats so I'm not sure whether it is
normal? For a 554MB sh file, I've got a 908MB pkg file and a 3.5GB dmg
file. I have also tested local installation on macOS and it principle it
works, even though of course there are warnings related to the lack of
signature.

Here is some feedback on the patch (partly AI generated, but reviewed
manually by me):

1. **Variable typo in darwin-toolchain-shar-extract.sh (line 198-199)**
   - Declares `fs_dev_type` but uses `fsdevtype` on next line
   - NFS filesystem check will silently fail, never triggering abort
condition
   - Fix: Change `fsdevtype` to `fs_dev_type` on line 199

2. **Undefined variable in mk-macos-pkg.sh (line 72)**
   - Script defines `pkg_vers` (line 22) but references `pkg_version` (line
72)
   - Generated PackageInfo will have empty version string
   - Fix: Change `${pkg_version}` to `${pkg_vers}` in PackageInfo XML

3. **Missing quotes in darwin-common.inc (line 66)**
   - Unquoted `${DARWIN_INSTALL_LOC}/${SDK_NAME}` passed to mk-macos-pkg.sh
   - Will break if DARWIN_INSTALLER_PATH contains spaces
   - Fix: Quote argument as `"${DARWIN_INSTALL_LOC}/${SDK_NAME}"`
   - Same issue on line 75 for mk-macos-dmg.sh call

4. **Incorrect sed command in mk-macos-pkg.sh (line 89)**
   - `sed -e 's,$,&,' ${files}/post-install.in >scripts/post-install`
   - Pattern 's,$,&,' does nothing (replaces end-of-line with itself)
   - Since post-install.in is intentionally empty (per cover letter Q5),
just use `cp` instead
   - Or remove the sed and the empty post-install.in file entirely if not
needed

5. **Typo in README (line 33)**
   - "follwing" should be "following"





On Mon, Feb 2, 2026 at 5:52 PM Eric L. Hernes via lists.yoctoproject.org
<dev=qinc.tv@lists.yoctoproject.org> wrote:

> This adds support for generating both .dmg and .pkg installers.
>
> The .dmg will require running the `finalize-dmg` to relocate and sign
> the executables.
>
> The .pkg automates the process and integrates the relocation and
> signage into the installer.
>
> Signed-off-by: Eric L. Hernes <dev@qinc.tv>
> ---
>  README                                      |  19 ++
>  conf/files/darwin-toolchain-shar-extract.sh | 316 ++++++++++++++++++++
>  conf/files/finalize-sdk.sh                  |  48 +++
>  conf/files/mk-macos-dmg.sh                  |  49 +++
>  conf/files/mk-macos-pkg.sh                  | 161 ++++++++++
>  conf/files/post-install.in                  |   9 +
>  conf/files/pre-install.in                   |  84 ++++++
>  conf/layer.conf                             |   3 +
>  conf/machine-sdk/darwin-common.inc          |  54 +++-
>  9 files changed, 741 insertions(+), 2 deletions(-)
>  create mode 100644 conf/files/darwin-toolchain-shar-extract.sh
>  create mode 100644 conf/files/finalize-sdk.sh
>  create mode 100755 conf/files/mk-macos-dmg.sh
>  create mode 100755 conf/files/mk-macos-pkg.sh
>  create mode 100644 conf/files/post-install.in
>  create mode 100644 conf/files/pre-install.in
>
> diff --git a/README b/README
> index 89845b5..97d176d 100644
> --- a/README
> +++ b/README
> @@ -30,3 +30,22 @@
> https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.yoctoproject.org_g_yocto-2Dpatches&d=DwIFAg&c=ncDTmphkJTvjIDPh0hpF_4vCHvabgGkICC2epckfdiw&r=AhkbNonVuMIGRfPx_Qj9TsRih1DULJTKUkSGa66m67E&m=ocDt_LbHjapIywNYWeZjpn13nP4qi8M-ViMysQ42MEAh4pLHUAUi7nHPV2HAzLgY&s=wo9y9WkvtD-73r84EwDgaSoRq1s2Q7o6YOy5P5FZRV8&e=
> before being able to post.
>  When sending single patches, please use something like:
>  'git send-email -M -1 --to yocto-patches@lists.yoctoproject.org
> --subject-prefix="meta-darwin][PATCH"'
>
> +The follwing variables can be set in the local.conf or elsewhere:
> +
> +To enable building the .pkg installer, set:
> +DARWIN_INSTALLER_PKG = "1"
> +
> +To enable building a .dmg installer, set:
> +DARWIN_INSTALLER_DMG = "1"
> +
> +To save some time during builds, you can disable the shell script
> installer with:
> +DARWIN_INSTALLER_SH = "0"
> +
> +To specify the path in the .dmg and path that the .pkg will install to,
> set
> +DARWIN_INSTALLER_PATH = "/Library/Developer/org.openembedded.sdk"
> +
> +The .dmg will require running the `finalize-dmg` to relocate and sign
> +the executables.
> +
> +The .pkg automates the process and integrates the relocation and
> +signage into the installer.
> diff --git a/conf/files/darwin-toolchain-shar-extract.sh
> b/conf/files/darwin-toolchain-shar-extract.sh
> new file mode 100644
> index 0000000..4417010
> --- /dev/null
> +++ b/conf/files/darwin-toolchain-shar-extract.sh
> @@ -0,0 +1,316 @@
> +#!/bin/sh
> +
> +export LC_ALL=en_US.UTF-8
> +
> +# The pipefail option is now part of POSIX (POSIX.1-2024) and available
> in more
> +# and more shells. Enable it if available to make the SDK installer more
> robust.
> +(set -o pipefail 2> /dev/null) && set -o pipefail
> +
> +#Make sure at least one python is installed
> +INIT_PYTHON=$(which python3 2>/dev/null )
> +[ -z "$INIT_PYTHON" ] && INIT_PYTHON=$(which python2 2>/dev/null)
> +[ -z "$INIT_PYTHON" ] && echo "Error: The SDK needs a python installed"
> && exit 1
> +
> +# Remove invalid PATH elements first (maybe from a previously setup
> toolchain now deleted
> +PATH=`$INIT_PYTHON -c 'import os; print(":".join(e for e in
> os.environ["PATH"].split(":") if os.path.exists(e)))'`
> +
> +tweakpath () {
> +    case ":${PATH}:" in
> +        *:"$1":*)
> +            ;;
> +        *)
> +            PATH=$PATH:$1
> +    esac
> +}
> +
> +# Some systems don't have /usr/sbin or /sbin in the cleaned environment
> PATH but we make need it
> +# for the system's host tooling checks
> +tweakpath /usr/sbin
> +tweakpath /sbin
> +
> +# linux calls it aarch64; Apple calls it arm64
> +if [ @SDK_ARCH@ == aarch64 ]; then
> +    OSX_SDK_ARCH=arm64
> +else
> +    OSX_SDK_ARCH=@SDK_ARCH@
> +fi
> +
> +INST_ARCH=$(uname -m | gsed -e "s/i[3-6]86/ix86/" -e
> "s/x86[-_]64/x86_64/")
> +SDK_ARCH=$(echo ${OSX_SDK_ARCH} | gsed -e "s/i[3-6]86/ix86/" -e
> "s/x86[-_]64/x86_64/")
> +
> +INST_GCC_VER=$(gcc --version 2>/dev/null | gsed -ne 's/.*
> \([0-9]\+\.[0-9]\+\)\.[0-9]\+.*/\1/p')
> +SDK_GCC_VER='@SDK_GCC_VER@'
> +
> +verlte () {
> +       [  "$1" = "`printf "$1\n$2" | sort -V | head -n1`" ]
> +}
> +
> +verlt() {
> +       [ "$1" = "$2" ] && return 1 || verlte $1 $2
> +}
> +
> +verlt `uname -r` @OLDEST_KERNEL@
> +if [ $? = 0 ]; then
> +       echo "Error: The SDK needs a kernel > @OLDEST_KERNEL@"
> +       exit 1
> +fi
> +
> +if [ "$INST_ARCH" != "$SDK_ARCH" ]; then
> +       # Allow for installation of ix86 SDK on x86_64 host
> +       if [ "$INST_ARCH" != x86_64 -o "$SDK_ARCH" != ix86 ]; then
> +               echo "Error: Incompatible SDK installer! Your host is
> $INST_ARCH and this SDK was built for $SDK_ARCH hosts."
> +               exit 1
> +       fi
> +fi
> +
> +if ! xz -V > /dev/null 2>&1; then
> +       echo "Error: xz is required for installation of this SDK, please
> install it first"
> +       exit 1
> +fi
> +
> +SDK_BUILD_PATH="@SDKPATH@"
> +DEFAULT_INSTALL_DIR="@SDKPATHINSTALL@"
> +SUDO_EXEC=""
> +EXTRA_TAR_OPTIONS=""
> +target_sdk_dir=""
> +answer=""
> +relocate=1
> +savescripts=0
> +verbose=0
> +publish=0
> +listcontents=0
> +while getopts ":yd:npDRSl" OPT; do
> +       case $OPT in
> +       y)
> +               answer="Y"
> +               ;;
> +       d)
> +               target_sdk_dir=$OPTARG
> +               ;;
> +       n)
> +               prepare_buildsystem="no"
> +               ;;
> +       p)
> +               prepare_buildsystem="no"
> +               publish=1
> +               ;;
> +       D)
> +               verbose=1
> +               ;;
> +       R)
> +               relocate=0
> +               savescripts=1
> +               ;;
> +       S)
> +               savescripts=1
> +               ;;
> +       l)
> +               listcontents=1
> +               ;;
> +       *)
> +               echo "Usage: $(basename "$0") [-y] [-d <dir>]"
> +               echo "  -y         Automatic yes to all prompts"
> +               echo "  -d <dir>   Install the SDK to <dir>"
> +               echo "======== Extensible SDK only options ============"
> +               echo "  -n         Do not prepare the build system"
> +               echo "  -p         Publish mode (implies -n)"
> +               echo "======== Advanced DEBUGGING ONLY OPTIONS ========"
> +               echo "  -S         Save relocation scripts"
> +               echo "  -R         Do not relocate executables"
> +               echo "  -D         use set -x to see what is going on"
> +               echo "  -l         list files that will be extracted"
> +               exit 1
> +               ;;
> +       esac
> +done
> +
> +payload_offset=$(($(grep -na -m1 "^MARKER:$" "$0"|cut -d':' -f1) + 1))
> +if [ "$listcontents" = "1" ] ; then
> +    if [ @SDK_ARCHIVE_TYPE@ = "zip" ]; then
> +        tail -n +$payload_offset "$0" > sdk.zip
> +        if unzip -l sdk.zip;then
> +            rm sdk.zip
> +        else
> +            rm sdk.zip && exit 1
> +        fi
> +    else
> +        tail -n +$payload_offset "$0"| gtar tvJ || exit 1
> +    fi
> +    exit
> +fi
> +
> +titlestr="@SDK_TITLE@ installer version @SDK_VERSION@"
> +printf "%s\n" "$titlestr"
> +printf "%${#titlestr}s\n" | tr " " "="
> +
> +if [ $verbose = 1 ] ; then
> +       set -x
> +fi
> +
> +@SDK_PRE_INSTALL_COMMAND@
> +
> +# SDK_EXTENSIBLE is exposed from the SDK_PRE_INSTALL_COMMAND above
> +if [ "$SDK_EXTENSIBLE" = "1" ]; then
> +       DEFAULT_INSTALL_DIR="@SDKEXTPATH@"
> +       if [ "$INST_GCC_VER" = '4.8' -a "$SDK_GCC_VER" = '4.9' ] || [
> "$INST_GCC_VER" = '4.8' -a "$SDK_GCC_VER" = '' ] || \
> +               [ "$INST_GCC_VER" = '4.9' -a "$SDK_GCC_VER" = '' ]; then
> +               echo "Error: Incompatible SDK installer! Your host gcc
> version is $INST_GCC_VER and this SDK was built by gcc higher version."
> +               exit 1
> +       fi
> +fi
> +
> +if [ "$target_sdk_dir" = "" ]; then
> +       if [ "$answer" = "Y" ]; then
> +               target_sdk_dir="$DEFAULT_INSTALL_DIR"
> +       else
> +               read -p "Enter target directory for SDK (default:
> $DEFAULT_INSTALL_DIR): " target_sdk_dir
> +               [ "$target_sdk_dir" = "" ] &&
> target_sdk_dir=$DEFAULT_INSTALL_DIR
> +       fi
> +fi
> +
> +eval target_sdk_dir=$(echo "$target_sdk_dir"|gsed 's/ /\\ /g')
> +if [ -d "$target_sdk_dir" ]; then
> +       target_sdk_dir=$(cd "$target_sdk_dir"; pwd)
> +else
> +       target_sdk_dir=$(greadlink -m "$target_sdk_dir")
> +fi
> +
> +# limit the length for target_sdk_dir, ensure the relocation behaviour in
> relocate_sdk.py has right result.
> +# This is due to ELF interpreter being set to 'a'*1024 in
> +# meta/recipes-core/meta/uninative-tarball.bb
> +if [ ${#target_sdk_dir} -gt 1024 ]; then
> +       echo "Error: The target directory path is too long!!!"
> +       exit 1
> +fi
> +
> +if [ "$SDK_EXTENSIBLE" = "1" ]; then
> +       # We're going to be running the build system, additional
> restrictions apply
> +       if echo "$target_sdk_dir" | grep -q '[+\ @$]'; then
> +               echo "The target directory path ($target_sdk_dir) contains
> illegal" \
> +                    "characters such as spaces, @, \$ or +. Abort!"
> +               exit 1
> +       fi
> +       # The build system doesn't work well with /tmp on NFS
> +       fs_dev_path="$target_sdk_dir"
> +       while [ ! -d "$fs_dev_path" ] ; do
> +               fs_dev_path=`dirname $fs_dev_path`
> +        done
> +       fs_dev_type=`stat -f -c '%t' "$fs_dev_path"`
> +       if [ "$fsdevtype" = "6969" ] ; then
> +               echo "The target directory path $target_sdk_dir is on NFS,
> this is not possible. Abort!"
> +               exit 1
> +       fi
> +else
> +       if [ -n "$(echo $target_sdk_dir|grep ' ')" ]; then
> +               echo "The target directory path ($target_sdk_dir) contains
> spaces. Abort!"
> +               exit 1
> +       fi
> +fi
> +
> +if [ -e "$target_sdk_dir/environment-setup-@REAL_MULTIMACH_TARGET_SYS@"
> ]; then
> +       echo "The directory \"$target_sdk_dir\" already contains a SDK for
> this architecture."
> +       printf "If you continue, existing files will be overwritten!
> Proceed [y/N]? "
> +
> +       default_answer="n"
> +else
> +       printf "You are about to install the SDK to \"$target_sdk_dir\".
> Proceed [Y/n]? "
> +
> +       default_answer="y"
> +fi
> +
> +if [ "$answer" = "" ]; then
> +       read answer
> +       [ "$answer" = "" ] && answer="$default_answer"
> +else
> +       echo $answer
> +fi
> +
> +if [ "$answer" != "Y" -a "$answer" != "y" ]; then
> +       echo "Installation aborted!"
> +       exit 1
> +fi
> +
> +# Try to create the directory (this will not succeed if user doesn't have
> rights)
> +mkdir -p $target_sdk_dir >/dev/null 2>&1
> +
> +# if don't have the right to access dir, gain by sudo
> +if [ ! -x $target_sdk_dir -o ! -w $target_sdk_dir -o ! -r $target_sdk_dir
> ]; then
> +       if [ "$SDK_EXTENSIBLE" = "1" ]; then
> +               echo "Unable to access \"$target_sdk_dir\", will not
> attempt to use" \
> +                    "sudo as as extensible SDK cannot be used as root."
> +               exit 1
> +       fi
> +
> +       SUDO_EXEC=$(which "sudo")
> +       if [ -z $SUDO_EXEC ]; then
> +               echo "No command 'sudo' found, please install sudo first.
> Abort!"
> +               exit 1
> +       fi
> +
> +       # test sudo could gain root right
> +       $SUDO_EXEC pwd >/dev/null 2>&1
> +       [ $? -ne 0 ] && echo "Sorry, you are not allowed to execute as
> root." && exit 1
> +
> +       # now that we have sudo rights, create the directory
> +       $SUDO_EXEC mkdir -p $target_sdk_dir >/dev/null 2>&1
> +fi
> +
> +printf "Extracting SDK..."
> +if [ @SDK_ARCHIVE_TYPE@ = "zip" ]; then
> +    tail -n +$payload_offset "$0" > sdk.zip
> +    if $SUDO_EXEC unzip $EXTRA_TAR_OPTIONS sdk.zip -d $target_sdk_dir;then
> +        rm sdk.zip
> +    else
> +        rm sdk.zip && exit 1
> +    fi
> +else
> +    tail -n +$payload_offset "$0"| $SUDO_EXEC gtar mxJ -C $target_sdk_dir
> --checkpoint=.2500 $EXTRA_TAR_OPTIONS || exit 1
> +fi
> +echo "done"
> +
> +printf "Setting it up..."
> +# fix environment paths
> +real_env_setup_script=""
> +for env_setup_script in `ls $target_sdk_dir/environment-setup-*`; do
> +       if grep -q 'OECORE_NATIVE_SYSROOT=' $env_setup_script; then
> +               # Handle custom env setup scripts that are only named
> +               # environment-setup-* so that they have relocation
> +               # applied - what we want beyond here is the main one
> +               # rather than the one that simply sorts last
> +               real_env_setup_script="$env_setup_script"
> +       fi
> +       $SUDO_EXEC gsed -e "s:@SDKPATH@:$target_sdk_dir:g" -i
> $env_setup_script
> +done
> +if [ -n "$real_env_setup_script" ] ; then
> +       env_setup_script="$real_env_setup_script"
> +fi
> +
> +@SDK_POST_INSTALL_COMMAND@
> +
> +# delete the relocating script, so that user is forced to re-run the
> installer
> +# if he/she wants another location for the sdk
> +if [ $savescripts = 0 ] ; then
> +       $SUDO_EXEC rm -f ${env_setup_script%/*}/relocate_sdk.py
> ${env_setup_script%/*}/relocate_sdk.sh
> +fi
> +
> +# Execute post-relocation script
> +post_relocate="$target_sdk_dir/post-relocate-setup.sh"
> +if [ -e "$post_relocate" ]; then
> +       $SUDO_EXEC gsed -e "s:@SDKPATH@:$target_sdk_dir:g" -i
> $post_relocate
> +       $SUDO_EXEC /bin/sh $post_relocate "$target_sdk_dir" "@SDKPATH@"
> +       if [ $? -ne 0 ]; then
> +               echo "Executing $post_relocate failed"
> +               exit 1
> +       fi
> +       $SUDO_EXEC rm -f $post_relocate
> +fi
> +
> +echo "SDK has been successfully set up and is ready to be used."
> +echo "Each time you wish to use the SDK in a new shell session, you need
> to source the environment setup script e.g."
> +for env_setup_script in `ls $target_sdk_dir/environment-setup-*`; do
> +       echo " \$ . $env_setup_script"
> +done
> +
> +exit 0
> +
> +MARKER:
> diff --git a/conf/files/finalize-sdk.sh b/conf/files/finalize-sdk.sh
> new file mode 100644
> index 0000000..bd4f313
> --- /dev/null
> +++ b/conf/files/finalize-sdk.sh
> @@ -0,0 +1,48 @@
> +#!/bin/sh
> +##################################################
> +## file: finalize-sdk.sh
> +##
> +##
> +## /bin/sh script to finalize oesdk files
> +##
> +## 1. change pathing from hardcoded path to install path
> +## 2. codesign binaries and dylibs
> +##
> +## This can be run on the final installed files; or during install in a
> staging area if we know
> +## what the final destination path will be.
> +##
> +
> +x_path=$(realpath $(dirname "${0}"))
> +first_csid=$(security -qq find-identity -v -p codesigning |cut -c47-
> |head -1 | tr -d '"')
> +
> +staging=${1:-"${x_path}"}
> +new_path=${2:-"${x_path}"}
> +codesign_id=${3:-"${first_csid}"}
> +
> +native_sysroot="@native_sysroot@"
> +
> +do_relocate=yes
> +do_codesign=yes
> +
> +if [ "${do_relocate}" = yes ]; then
> +    old_path="/usr/local/oe-sdk-hardcoded-buildpath"
> +
> +    find "${staging}" -type f -exec file {} +| grep -i
> ":.*\(ASCII\|script\|source\).*text" |cut -d: -f1  |
> +        while read fn; do
> +            sed -i "" "s,${old_path},${new_path},g" "${fn}" || echo
> "${fn}"
> +        done
> +fi
> +
> +if [ "${do_codesign}" = yes ]; then
> +    if [ -z "${codesign_id}" ]; then
> +        echo "requested codesigning, but did not find a codesigning
> identity"
> +    else
> +        find "${staging}/sysroots/${native_sysroot}" -type f -exec file
> {} + |
> +            grep Mach-O |
> +            cut -d: -f1 |
> +            sed -e "s,^,'," -e "s,$,'," |
> +            xargs codesign --continue --force --timestamp --sign
> "${codesign_id}"
> +    fi
> +fi
> +
> +exit 0
> diff --git a/conf/files/mk-macos-dmg.sh b/conf/files/mk-macos-dmg.sh
> new file mode 100755
> index 0000000..ebf95d0
> --- /dev/null
> +++ b/conf/files/mk-macos-dmg.sh
> @@ -0,0 +1,49 @@
> +#!/bin/bash
> +##################################################
> +## file: meta-darwin/conf/files/mk-macos-dmg.sh
> +##
> +## Original Author: Eric L. Hernes <eric@qinc.tv>
> +##
> +## /bin/sh script to do create macos .dmg image for openembedded sdk
> +##
> +
> +# $1 = SDK Title
> +# $2 = SDK Name
> +# $3 = SDK Architecture
> +# $4 = SDK Version
> +# $5 = path to SDK path files
> +# $6 = SDK dmg output filename
> +# $7 = path to finalize script
> +# $8 = destination path within the DMG
> +
> +pkg_title=${1:-"OpenEmbedded SDK"}
> +pkg_name=${2:-"oesdk-darwin21"}
> +pkg_arch=${3:-"aarch64"}
> +pkg_vers=${4:-"x.x.x.y"}
> +sdk_path=${5:-".../tmp/work/armv8a-oe-linux/meta-toolchain/1.0/sdk/image"}
> +dmg_path=${6:-".../tmp/deploy/sdk/macos-test-sdk.dmg"}
> +finalize_dmg=${7:-"finalize-dmg"}
> +dst_path=${8-"/Library/Developer/org.openembedded.sdk/${pkg_name}"}
> +
> +dmg_finalize="${dst_path}/"$(basename "${finalize_dmg}")
> +
> +set $(du -sm ${sdk_path})
> +
> +# add 10% for overhead
> +size_mb=$((${1} * 11 / 10))
> +
> +dd if=/dev/zero of="${dmg_path}" bs=1M count=${size_mb}
> +mkfs.hfsplus -s -v "${pkg_name}" "${dmg_path}"
> +
> +hfsplus "${dmg_path}" mkdir-p "${dst_path}"
> +
> +hfsplus "${dmg_path}" addall "${sdk_path}" "${dst_path}"
> +
> +hfsplus "${dmg_path}" add "${finalize_dmg}" "${dmg_finalize}"
> +hfsplus "${dmg_path}" chmod 755 "${dmg_finalize}"
> +
> +hfsplus "${dmg_path}" rm "${dst_path}/relocate_sdk.py"
> +
> +hfsplus "${dmg_path}" rm "${dst_path}/post-relocate-setup.sh"
> +
> +
> diff --git a/conf/files/mk-macos-pkg.sh b/conf/files/mk-macos-pkg.sh
> new file mode 100755
> index 0000000..283a0e3
> --- /dev/null
> +++ b/conf/files/mk-macos-pkg.sh
> @@ -0,0 +1,161 @@
> +#!/bin/bash
> +##################################################
> +## file: meta-darwin/conf/files/mk-macos-pkg.sh
> +##
> +## Original Author: Eric L. Hernes <eric@qinc.tv>
> +##
> +## /bin/sh script to do create macos .pkg installer for openembedded sdk
> +##
> +
> +# $1 = SDK Title
> +# $2 = SDK Name
> +# $3 = SDK Architecture
> +# $4 = SDK Version
> +# $5 = path to SDK path files
> +# $6 = SDK dmg output filename
> +# $7 = path to finalize script
> +# $8 = destination path relative to the user's selected volume
> +
> +pkg_title=${1:-"OpenEmbedded SDK"}
> +pkg_name=${2:-"oesdk-darwin21"}
> +pkg_arch=${3:-"aarch64"}
> +pkg_vers=${4:-"x.x.x.y"}
> +sdk_path=${5:-".../tmp/work/armv8a-oe-linux/meta-toolchain/1.0/sdk/image"}
> +pkg_path=${6:-".../tmp/deploy/sdk/macos-test-sdk.pkg"}
> +finalize_pkg=${7:-"finalize-pkg"}
> +dst_path=${8-"/Library/Developer/org.openembedded.sdk/${pkg_name}/x"}
> +
> +echo "pkg_title: ${pkg_title}"
> +echo "pkg_name: ${pkg_name}"
> +echo "pkg_arch: ${pkg_arch}"
> +echo "pkg_vers: ${pkg_vers}"
> +echo "sdk_path: ${sdk_path}"
> +echo "pkg_path: ${pkg_path}"
> +echo "dst_path: ${dst_path}"
> +
> +count=$(find ${sdk_path} -type f | wc -l)
> +set $(du -sk ${sdk_path})
> +kbytes=$1
> +
> +echo "SDK will contain ${count} files and consume ${kbytes}K bytes"
> +
> +org_id=org.openembedded.sdk
> +
> +pkg_id="${org_id}.${pkg_name}.pkg"
> +
> +flat=dist/Package.pkg
> +
> +build=build
> +mkbom=mkbom
> +xar=xar
> +
> +files=$(realpath $(dirname $0))
> +
> +rm -rf ${build}
> +rm -f "${pkg_path}"
> +
> +mkdir ${build}
> +cd ${build}
> +
> +mkdir -p ${flat}
> +mkdir scripts
> +
> +( cd ${sdk_path} && find . | cpio -o --format odc --owner 0:80 | gzip -c
> ) > ${flat}/Payload
> +
> +#
> +# Swift installs stuff to /Library/org.swift.swiftpm;
> +#
> +# So let's do something similar
> +# Install files to /Library/Developer/org.openembedded.sdk
> +#
> +cat > ${flat}/PackageInfo <<EOF
> +<pkg-info format-version="2" identifier="${pkg_id}"
> version="${pkg_version}" relocatable="false" overwrite-permissions="false"
> followSymLinks="false" install-location="${dst_path}" auth="root">
> +  <payload installKBytes="${kbytes}" numberOfFiles="${count}"/>
> +    <bundle-version/>
> +    <upgrade-bundle/>
> +    <update-bundle/>
> +    <atomic-update-bundle/>
> +    <strict-identifier/>
> +    <relocate/>
> +    <scripts>
> +      <preinstall file="./pre-install"/>
> +      <postinstall file="./post-install"/>
> +  </scripts>
> +</pkg-info>
> +EOF
> +
> +sed -e "s#@dst_path@#${dst_path}#g" \
> +    ${files}/pre-install.in >scripts/pre-install
> +
> +sed -e 's,$,&,' ${files}/post-install.in >scripts/post-install
> +cp ${finalize_pkg} scripts/finalize-pkg
> +
> +chmod +x scripts/finalize-pkg
> +chmod +x scripts/pre-install
> +chmod +x scripts/post-install
> +
> +( cd scripts && find . | cpio -o --format odc --owner 0:80 | gzip -c ) >
> ${flat}/Scripts
> +${mkbom} -u 0 -g 80 ${sdk_path} ${flat}/Bom
> +
> +#
> +# linux calls it aarch64; apple calls it arm64
> +#
> +
> +declare -A arch_map
> +arch_map["aarch64"]="arm64"
> +arch_map["x86_64"]="x86_64"
> +
> +p_id=$(tr -dc 'a-z0-9' < /dev/urandom | head -c 16)
> +pki_id="org.openembedded.oesdk.installer.${p_id}"
> +
> +
> +cat >dist/Distribution <<EOF
> +<?xml version="1.0" encoding="utf-8"?>
> +<installer-gui-script minSpecVersion="2">
> +    <title>${pkg_title}</title>
> +    <options customize="allow"
> hostArchitectures="${arch_map[${pkg_arch}]}"/>
> +    <domains enable_localSystem="true" enable_anywhere="true"
> enable_currentUserHome="true"/>
> +    <installation-check script="canInstall()"/>
> +    <script><![CDATA[
> +       function canInstall() {
> +               var version;
> +               var major;
> +
> +               // ProductVersion is usually "major.minor.patch"
> +               if (!system || !system.version ||
> !system.version.ProductVersion) {
> +                       return false;
> +               }
> +
> +               version = system.version.ProductVersion.split(".");
> +               major = parseInt(version[0], 10);
> +
> +               if (isNaN(major)) {
> +                       return false;
> +               }
> +
> +               // Darwin21 ==  macOS 12+
> +               if (major < 12) {
> +                       return false;
> +               }
> +
> +               return true;
> +       }
> +
> +]]></script>
> +    <pkg-ref id="${p_id}" version="1"
> onConclusion="none">#Package.pkg</pkg-ref>
> +    <pkg-ref id="${p_id}" packageIdentifier="${pki_id}" installKBytes="0"
> updateKBytes="0">
> +        <must-close/>
> +        <bundle-version/>
> +    </pkg-ref>
> +    <choices-outline>
> +        <line choice="${p_id}"/>
> +    </choices-outline>
> +    <choice id="${p_id}" title="Package" start_selected="true">
> +        <pkg-ref id="${p_id}"/>
> +    </choice>
> +    <product id="${pkg_id}" version="${pkg_vers}"/>
> +</installer-gui-script>
> +EOF
> +
> +( cd dist && ${xar} --compression none -cf "${pkg_path}" * )
> +
> diff --git a/conf/files/post-install.in b/conf/files/post-install.in
> new file mode 100644
> index 0000000..9321f79
> --- /dev/null
> +++ b/conf/files/post-install.in
> @@ -0,0 +1,9 @@
> +#!/bin/bash
> +#########################################
> +#  file: meta-darwin/conf/files/post-install.in
> +#
> +#  @file    post-install
> +#  @version V1.0
> +#
> +# post install script for meta-darwin SDK
> +#
> diff --git a/conf/files/pre-install.in b/conf/files/pre-install.in
> new file mode 100644
> index 0000000..0c488c4
> --- /dev/null
> +++ b/conf/files/pre-install.in
> @@ -0,0 +1,84 @@
> +#!/usr/bin/osascript -l JavaScript
> +/***************************************************
> + * file: meta-darwin/conf/files/pre-install.in
> + *
> + * @file    pre-install.jxa
> + * @version V1.0
> + *
> + * pre-install script for meta-darwin macOS SDK
> + *
> + * this script gets user options and sets up various things
> + * so that the files are installed properly in their final
> + * destination
> + *
> + */
> +
> +ObjC.import("stdlib");
> +
> +var seApp = Application("System Events");
> +var oProcess = seApp.processes.whose({frontmost: true})[0];
> +var appName = oProcess.displayedName();
> +
> +app = Application.currentApplication();
> +
> +app.includeStandardAdditions = true;
> +
> +retval = []
> +
> +function run(args) {
> +
> +  codesign_id=""
> +  if (true) {
> +    idstr = app.doShellScript("security -qq find-identity -v -p
> codesigning |cut -c47- |tr '\n' ';'")
> +    idList = idstr.split(';').filter(element => element);
> +    switch (idList.length) {
> +      case 0: // can't sign
> +        let dialogText = "Could not find any code signing identities,
> binaries will not be signed"
> +        app.displayDialog(dialogText)
> +      break;
> +
> +      case 1: // no decisions
> +        codesign_id = idList[0]
> +      break;
> +
> +      default:
> +        codesign_id = app.chooseFromList(idList, {
> +          withTitle: "Signing ID",
> +          withPrompt: "Please select an ID to sign binaries",
> +          defaultItems: [idList[0]],
> +          okButtonName: "OK",
> +          cancelButtonName: "Cancel",
> +          multipleSelectionsAllowed: false,
> +          emptySelectionAllowed: false
> +        })
> +      if (codesign_id == false) {
> +        let dialogText = "Cancelled code signing"
> +        app.displayDialog(dialogText)
> +        return false
> +      }
> +    }
> +  }
> +
> +  // finalize script
> +  // finalize {staging} {new_path} {code_sign}
> +  pwd = ObjC.unwrap($.NSFileManager.defaultManager.currentDirectoryPath)
> +  finalize = pwd + "/finalize-pkg";
> +  staging = $.getenv("INSTALLER_PAYLOAD_DIR") + "@dst_path@"
> +  new_path = args[1]
> +  command = `${finalize} "${staging}" "${new_path}" ${codesign_id}`
> +
> +  var dialogText = "Will run a script to relocate and codesign\n\n"
> +  dialogText += "\n\n"
> +  dialogText += "This may take a few minutes depending on the size of the
> SDK"
> +
> +  app.displayDialog(dialogText)
> +
> +  finalize_data = app.doShellScript(command + " >/dev/null 2>&1")
> +
> +  app.displayDialog(finalize_data)
> +
> +  retval.push("ok")
> +  return retval.join("\n")
> +}
> +
> +/* end of pre-install.in */
> diff --git a/conf/layer.conf b/conf/layer.conf
> index 2f14754..6730f3b 100644
> --- a/conf/layer.conf
> +++ b/conf/layer.conf
> @@ -9,3 +9,6 @@ BBFILES += "${LAYERDIR}/recipes*/*/*.bb
> ${LAYERDIR}/recipes*/*/*.bbappend"
>  BBFILE_COLLECTIONS += "meta-darwin"
>  BBFILE_PATTERN_meta-darwin := "^${LAYERDIR}/"
>  BBFILE_PRIORITY_meta-darwin = "8"
> +
> +DARWINBASE = '${@os.path.normpath("${LAYERDIR}")}'
> +BB_BASEHASH_IGNORE_VARS:append = " DARWINBASE"
> diff --git a/conf/machine-sdk/darwin-common.inc
> b/conf/machine-sdk/darwin-common.inc
> index cec76a5..2f1aec9 100644
> --- a/conf/machine-sdk/darwin-common.inc
> +++ b/conf/machine-sdk/darwin-common.inc
> @@ -14,8 +14,13 @@ SDKUSE_NLS = "no"
>  SDKIMAGE_LINGUAS = ""
>  SDK_DEPENDS:remove = "nativesdk-glibc-locale nativesdk-qemuwrapper-cross"
>
> +SDK_DEPENDS:append = "${@bb.utils.contains('DARWIN_INSTALLER_PKG', '1', '
> bomutils-native xar-native', '', d)}"
> +SDK_DEPENDS:append = "${@bb.utils.contains('DARWIN_INSTALLER_DMG', '1', '
> hfsprogs-native libdmg-hfsplus-native', '', d)}"
> +
>  SDKPKGSUFFIX = "nativesdk-darwin"
>
> +DARWIN_INSTALL_LOC = "${@d.getVar('DARWIN_INSTALLER_PATH') or
> '/Library/Developer/org.openembedded.sdk'}"
> +
>  OSX_TOOLCHAIN_OPTIONS = " \
>      -mmacosx-version-min=12.3 \
>      -L${STAGING_DIR_TARGET}${SDKPATHNATIVE}/usr/lib \
> @@ -24,9 +29,12 @@ OSX_TOOLCHAIN_OPTIONS = " \
>  "
>
>  TOOLCHAIN_OPTIONS:append:darwin21 = " \
> -    ${OSX_TOOLCHAIN_OPTIONS}"
> +    ${OSX_TOOLCHAIN_OPTIONS} \
> +"
> +
>  TOOLCHAIN_OPTIONS:append:class-cross-canadian = " \
> -    ${OSX_TOOLCHAIN_OPTIONS}"
> +    ${OSX_TOOLCHAIN_OPTIONS} \
> +"
>
>  # Remove -rpath-link
>  BUILDSDK_LDFLAGS = " \
> @@ -35,3 +43,45 @@ BUILDSDK_LDFLAGS = " \
>  "
>
>  MACHINEOVERRIDES .= ":darwinsdk"
> +
> +TOOLCHAIN_SHAR_EXT_TMPL ?=
> "${DARWINBASE}/conf/files/darwin-toolchain-shar-extract.sh"
> +
> +SDK_POSTPROCESS_COMMAND:append =
> "${@bb.utils.contains('DARWIN_INSTALLER_PKG', '1', ' create_macos_pkg', '',
> d)}"
> +SDK_POSTPROCESS_COMMAND:append =
> "${@bb.utils.contains('DARWIN_INSTALLER_DMG', '1', ' create_macos_dmg', '',
> d)}"
> +
> +#
> +# remove the .xz and .sh creation if we want to save a bit of time
> +SDK_POSTPROCESS_COMMAND:remove =
> "${@bb.utils.contains('DARWIN_INSTALLER_SH', '0', ' archive_sdk', '', d)}"
> +SDK_POSTPROCESS_COMMAND:remove =
> "${@bb.utils.contains('DARWIN_INSTALLER_SH', '0', ' create_shar', '', d)}"
> +
> +fakeroot create_macos_pkg() {
> +    sdk_pkg="${SDKDEPLOYDIR}/${TOOLCHAIN_OUTPUTNAME}.pkg"
> +    native_sysroot=$(basename ${SDKPATHNATIVE})
> +
> +    sed -e "s#@target_prefix@#${TARGET_PREFIX}#g" \
> +        -e "s#@native_sysroot@#${native_sysroot}#g" \
> +         ${DARWINBASE}/conf/files/finalize-sdk.sh \
> +         > "${B}/finalize-pkg"
> +
> +    (cd ${B}; \
> +        ${DARWINBASE}/conf/files/mk-macos-pkg.sh "${SDK_TITLE}"
> "${SDK_NAME}" "${SDK_ARCH}" "${DISTRO_VERSION}.${SDK_VERSION}"
> "${SDK_OUTPUT}/${SDKPATH}" "${sdk_pkg}" "${B}/finalize-pkg"
> ${DARWIN_INSTALL_LOC}/${SDK_NAME} \
> +    )
> +
> +   ls -lh "${sdk_pkg}"
> +}
> +
> +fakeroot create_macos_dmg() {
> +    sdk_dmg="${SDKDEPLOYDIR}/${TOOLCHAIN_OUTPUTNAME}.dmg"
> +    native_sysroot=$(basename ${SDKPATHNATIVE})
> +    sed -e "s#@target_prefix@#${TARGET_PREFIX}#g" \
> +        -e "s#@native_sysroot@#${native_sysroot}#g" \
> +         ${DARWINBASE}/conf/files/finalize-sdk.sh \
> +         > "${B}/finalize-dmg"
> +
> +    echo 'rm ${0}' >> "${B}/finalize-dmg"
> +
> +    ( cd ${B}; \
> +        ${DARWINBASE}/conf/files/mk-macos-dmg.sh "${SDK_TITLE}"
> "${SDK_NAME}" "${SDK_ARCH}" "${DISTRO_VERSION}.${SDK_VERSION}"
> "${SDK_OUTPUT}/${SDKPATH}" "${sdk_dmg}" "${B}/finalize-dmg"
> "${DARWIN_INSTALL_LOC}/${SDK_NAME}" \
> +    )
> +   ls -lh "${sdk_dmg}"
> +}
> --
> 2.50.1 (Apple Git-155)
>
>
>
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#3170):
> https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.yoctoproject.org_g_yocto-2Dpatches_message_3170&d=DwIFAg&c=ncDTmphkJTvjIDPh0hpF_4vCHvabgGkICC2epckfdiw&r=AhkbNonVuMIGRfPx_Qj9TsRih1DULJTKUkSGa66m67E&m=ocDt_LbHjapIywNYWeZjpn13nP4qi8M-ViMysQ42MEAh4pLHUAUi7nHPV2HAzLgY&s=RI7TbVVDb1JI4t7V-VwIOzosoaA0QogUxTcPBqFWles&e=
> Mute This Topic:
> https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.yoctoproject.org_mt_117599656_7048771&d=DwIFAg&c=ncDTmphkJTvjIDPh0hpF_4vCHvabgGkICC2epckfdiw&r=AhkbNonVuMIGRfPx_Qj9TsRih1DULJTKUkSGa66m67E&m=ocDt_LbHjapIywNYWeZjpn13nP4qi8M-ViMysQ42MEAh4pLHUAUi7nHPV2HAzLgY&s=HmiWukrayw1P0qfPuQgy18xIGA9t7RYJ8nplxk4fUc8&e=
> Group Owner: yocto-patches+owner@lists.yoctoproject.org
> Unsubscribe:
> https://urldefense.proofpoint.com/v2/url?u=https-3A__lists.yoctoproject.org_g_yocto-2Dpatches_leave_13184993_7048771_1814342232_xyzzy&d=DwIFAg&c=ncDTmphkJTvjIDPh0hpF_4vCHvabgGkICC2epckfdiw&r=AhkbNonVuMIGRfPx_Qj9TsRih1DULJTKUkSGa66m67E&m=ocDt_LbHjapIywNYWeZjpn13nP4qi8M-ViMysQ42MEAh4pLHUAUi7nHPV2HAzLgY&s=_VBIT28ALkqgS9F91h-sUFpZJjfOKwlRhJMIfmw9GqM&e=
> [ecordonnier@snap.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
>
>
Eric L. Hernes Feb. 27, 2026, 5:24 p.m. UTC | #2
Hi Etienne,

Thanks for the review. I'll get this cleaned up and re-submitted.

Regarding the file sizes - yes, that's expected.  The .pkg uses xz compression, which doesn't get as small as bzip2.  The .dmg (which is more correctly a .img), is uncompressed.  I think it needs to be uncompressed in order to relocate and code sign the binaries.  When I tried using a compressed (and real) .dmg file; it was read-only.  It's probably ok to have it uncompressed when in use on the target system - it's no different than the .sh installer after installation.  I'll add a step to bzip2 compress it so that it can be smaller for distribution.

I'm open to any other comments about pathing, naming, etc.  I just blindly made up some of it as a hybrid between what Yocto would do and what macOS would do.  It could be the worst of both worlds ;)

-Eric
Eric L. Hernes March 3, 2026, 2:25 p.m. UTC | #3
Hi Etienne,

I'm looking at these changes now.

It's interesting that I just copied the toolchain-shar-extract.sh straight from poky and only changed the sed references to use gsed.  The original poky version has the same typo(s) with fsdevtype.  Honestly, though, the fs_dev_type of "6969" looks highly linux specific and may be out of place on macOS entirely.  Nonetheless, I've patched the script.

The others are cleaned up.

I also realized that the .dmg is actually an .img file.  The relevant part is that a .dmg is read only.  We need the image to be writable so we can run the finalize script and sign the binaries.  I've updated things so that it's properly called an .img file.  I've also added a final command to bzip2 compress it for distribution.  It will still need to be uncompressed on the macOS host, but that happens with all SDKs.  It could be re-compressed back to a genuine .dmg after processing on the host, but the advantages are not so clear.

I have also updated the .pkg file to use xz compression, which makes it smaller as well.  On meta-toolchain, here's what I'm seeing now:

-rwxr-xr-x 2 ubuntu ubuntu 766M Mar  2 17:59 oecore-meta-toolchain-aarch64-armv8a-rk3576-pg2-toolchain-1.sh
-rw-r--r-- 2 ubuntu ubuntu 861M Mar  2 18:03 oecore-meta-toolchain-aarch64-armv8a-rk3576-pg2-toolchain-1.pkg
-rw-r--r-- 2 ubuntu ubuntu 1.3G Mar  2 18:05 oecore-meta-toolchain-aarch64-armv8a-rk3576-pg2-toolchain-1.img.bz2

-Eric
diff mbox series

Patch

diff --git a/README b/README
index 89845b5..97d176d 100644
--- a/README
+++ b/README
@@ -30,3 +30,22 @@  https://lists.yoctoproject.org/g/yocto-patches before being able to post.
 When sending single patches, please use something like:
 'git send-email -M -1 --to yocto-patches@lists.yoctoproject.org --subject-prefix="meta-darwin][PATCH"'
 
+The follwing variables can be set in the local.conf or elsewhere:
+
+To enable building the .pkg installer, set:
+DARWIN_INSTALLER_PKG = "1"
+
+To enable building a .dmg installer, set:
+DARWIN_INSTALLER_DMG = "1"
+
+To save some time during builds, you can disable the shell script installer with:
+DARWIN_INSTALLER_SH = "0"
+
+To specify the path in the .dmg and path that the .pkg will install to, set
+DARWIN_INSTALLER_PATH = "/Library/Developer/org.openembedded.sdk"
+
+The .dmg will require running the `finalize-dmg` to relocate and sign
+the executables.
+
+The .pkg automates the process and integrates the relocation and
+signage into the installer.
diff --git a/conf/files/darwin-toolchain-shar-extract.sh b/conf/files/darwin-toolchain-shar-extract.sh
new file mode 100644
index 0000000..4417010
--- /dev/null
+++ b/conf/files/darwin-toolchain-shar-extract.sh
@@ -0,0 +1,316 @@ 
+#!/bin/sh
+
+export LC_ALL=en_US.UTF-8
+
+# The pipefail option is now part of POSIX (POSIX.1-2024) and available in more
+# and more shells. Enable it if available to make the SDK installer more robust.
+(set -o pipefail 2> /dev/null) && set -o pipefail
+
+#Make sure at least one python is installed
+INIT_PYTHON=$(which python3 2>/dev/null )
+[ -z "$INIT_PYTHON" ] && INIT_PYTHON=$(which python2 2>/dev/null)
+[ -z "$INIT_PYTHON" ] && echo "Error: The SDK needs a python installed" && exit 1
+
+# Remove invalid PATH elements first (maybe from a previously setup toolchain now deleted
+PATH=`$INIT_PYTHON -c 'import os; print(":".join(e for e in os.environ["PATH"].split(":") if os.path.exists(e)))'`
+
+tweakpath () {
+    case ":${PATH}:" in
+        *:"$1":*)
+            ;;
+        *)
+            PATH=$PATH:$1
+    esac
+}
+
+# Some systems don't have /usr/sbin or /sbin in the cleaned environment PATH but we make need it 
+# for the system's host tooling checks
+tweakpath /usr/sbin
+tweakpath /sbin
+
+# linux calls it aarch64; Apple calls it arm64
+if [ @SDK_ARCH@ == aarch64 ]; then
+    OSX_SDK_ARCH=arm64
+else
+    OSX_SDK_ARCH=@SDK_ARCH@
+fi
+
+INST_ARCH=$(uname -m | gsed -e "s/i[3-6]86/ix86/" -e "s/x86[-_]64/x86_64/")
+SDK_ARCH=$(echo ${OSX_SDK_ARCH} | gsed -e "s/i[3-6]86/ix86/" -e "s/x86[-_]64/x86_64/")
+
+INST_GCC_VER=$(gcc --version 2>/dev/null | gsed -ne 's/.* \([0-9]\+\.[0-9]\+\)\.[0-9]\+.*/\1/p')
+SDK_GCC_VER='@SDK_GCC_VER@'
+
+verlte () {
+	[  "$1" = "`printf "$1\n$2" | sort -V | head -n1`" ]
+}
+
+verlt() {
+	[ "$1" = "$2" ] && return 1 || verlte $1 $2
+}
+
+verlt `uname -r` @OLDEST_KERNEL@
+if [ $? = 0 ]; then
+	echo "Error: The SDK needs a kernel > @OLDEST_KERNEL@"
+	exit 1
+fi
+
+if [ "$INST_ARCH" != "$SDK_ARCH" ]; then
+	# Allow for installation of ix86 SDK on x86_64 host
+	if [ "$INST_ARCH" != x86_64 -o "$SDK_ARCH" != ix86 ]; then
+		echo "Error: Incompatible SDK installer! Your host is $INST_ARCH and this SDK was built for $SDK_ARCH hosts."
+		exit 1
+	fi
+fi
+
+if ! xz -V > /dev/null 2>&1; then
+	echo "Error: xz is required for installation of this SDK, please install it first"
+	exit 1
+fi
+
+SDK_BUILD_PATH="@SDKPATH@"
+DEFAULT_INSTALL_DIR="@SDKPATHINSTALL@"
+SUDO_EXEC=""
+EXTRA_TAR_OPTIONS=""
+target_sdk_dir=""
+answer=""
+relocate=1
+savescripts=0
+verbose=0
+publish=0
+listcontents=0
+while getopts ":yd:npDRSl" OPT; do
+	case $OPT in
+	y)
+		answer="Y"
+		;;
+	d)
+		target_sdk_dir=$OPTARG
+		;;
+	n)
+		prepare_buildsystem="no"
+		;;
+	p)
+		prepare_buildsystem="no"
+		publish=1
+		;;
+	D)
+		verbose=1
+		;;
+	R)
+		relocate=0
+		savescripts=1
+		;;
+	S)
+		savescripts=1
+		;;
+	l)
+		listcontents=1
+		;;
+	*)
+		echo "Usage: $(basename "$0") [-y] [-d <dir>]"
+		echo "  -y         Automatic yes to all prompts"
+		echo "  -d <dir>   Install the SDK to <dir>"
+		echo "======== Extensible SDK only options ============"
+		echo "  -n         Do not prepare the build system"
+		echo "  -p         Publish mode (implies -n)"
+		echo "======== Advanced DEBUGGING ONLY OPTIONS ========"
+		echo "  -S         Save relocation scripts"
+		echo "  -R         Do not relocate executables"
+		echo "  -D         use set -x to see what is going on"
+		echo "  -l         list files that will be extracted"
+		exit 1
+		;;
+	esac
+done
+
+payload_offset=$(($(grep -na -m1 "^MARKER:$" "$0"|cut -d':' -f1) + 1))
+if [ "$listcontents" = "1" ] ; then
+    if [ @SDK_ARCHIVE_TYPE@ = "zip" ]; then
+        tail -n +$payload_offset "$0" > sdk.zip
+        if unzip -l sdk.zip;then
+            rm sdk.zip
+        else
+            rm sdk.zip && exit 1
+        fi
+    else
+        tail -n +$payload_offset "$0"| gtar tvJ || exit 1
+    fi
+    exit
+fi
+
+titlestr="@SDK_TITLE@ installer version @SDK_VERSION@"
+printf "%s\n" "$titlestr"
+printf "%${#titlestr}s\n" | tr " " "="
+
+if [ $verbose = 1 ] ; then
+	set -x
+fi
+
+@SDK_PRE_INSTALL_COMMAND@
+
+# SDK_EXTENSIBLE is exposed from the SDK_PRE_INSTALL_COMMAND above
+if [ "$SDK_EXTENSIBLE" = "1" ]; then
+	DEFAULT_INSTALL_DIR="@SDKEXTPATH@"
+	if [ "$INST_GCC_VER" = '4.8' -a "$SDK_GCC_VER" = '4.9' ] || [ "$INST_GCC_VER" = '4.8' -a "$SDK_GCC_VER" = '' ] || \
+		[ "$INST_GCC_VER" = '4.9' -a "$SDK_GCC_VER" = '' ]; then
+		echo "Error: Incompatible SDK installer! Your host gcc version is $INST_GCC_VER and this SDK was built by gcc higher version."
+		exit 1
+	fi
+fi
+
+if [ "$target_sdk_dir" = "" ]; then
+	if [ "$answer" = "Y" ]; then
+		target_sdk_dir="$DEFAULT_INSTALL_DIR"
+	else
+		read -p "Enter target directory for SDK (default: $DEFAULT_INSTALL_DIR): " target_sdk_dir
+		[ "$target_sdk_dir" = "" ] && target_sdk_dir=$DEFAULT_INSTALL_DIR
+	fi
+fi
+
+eval target_sdk_dir=$(echo "$target_sdk_dir"|gsed 's/ /\\ /g')
+if [ -d "$target_sdk_dir" ]; then
+	target_sdk_dir=$(cd "$target_sdk_dir"; pwd)
+else
+	target_sdk_dir=$(greadlink -m "$target_sdk_dir")
+fi
+
+# limit the length for target_sdk_dir, ensure the relocation behaviour in relocate_sdk.py has right result.
+# This is due to ELF interpreter being set to 'a'*1024 in
+# meta/recipes-core/meta/uninative-tarball.bb
+if [ ${#target_sdk_dir} -gt 1024 ]; then
+	echo "Error: The target directory path is too long!!!"
+	exit 1
+fi
+
+if [ "$SDK_EXTENSIBLE" = "1" ]; then
+	# We're going to be running the build system, additional restrictions apply
+	if echo "$target_sdk_dir" | grep -q '[+\ @$]'; then
+		echo "The target directory path ($target_sdk_dir) contains illegal" \
+		     "characters such as spaces, @, \$ or +. Abort!"
+		exit 1
+	fi
+	# The build system doesn't work well with /tmp on NFS
+	fs_dev_path="$target_sdk_dir"
+	while [ ! -d "$fs_dev_path" ] ; do
+		fs_dev_path=`dirname $fs_dev_path`
+        done
+	fs_dev_type=`stat -f -c '%t' "$fs_dev_path"`
+	if [ "$fsdevtype" = "6969" ] ; then
+		echo "The target directory path $target_sdk_dir is on NFS, this is not possible. Abort!"
+		exit 1
+	fi
+else
+	if [ -n "$(echo $target_sdk_dir|grep ' ')" ]; then
+		echo "The target directory path ($target_sdk_dir) contains spaces. Abort!"
+		exit 1
+	fi
+fi
+
+if [ -e "$target_sdk_dir/environment-setup-@REAL_MULTIMACH_TARGET_SYS@" ]; then
+	echo "The directory \"$target_sdk_dir\" already contains a SDK for this architecture."
+	printf "If you continue, existing files will be overwritten! Proceed [y/N]? "
+
+	default_answer="n"
+else
+	printf "You are about to install the SDK to \"$target_sdk_dir\". Proceed [Y/n]? "
+
+	default_answer="y"
+fi
+
+if [ "$answer" = "" ]; then
+	read answer
+	[ "$answer" = "" ] && answer="$default_answer"
+else
+	echo $answer
+fi
+
+if [ "$answer" != "Y" -a "$answer" != "y" ]; then
+	echo "Installation aborted!"
+	exit 1
+fi
+
+# Try to create the directory (this will not succeed if user doesn't have rights)
+mkdir -p $target_sdk_dir >/dev/null 2>&1
+
+# if don't have the right to access dir, gain by sudo 
+if [ ! -x $target_sdk_dir -o ! -w $target_sdk_dir -o ! -r $target_sdk_dir ]; then 
+	if [ "$SDK_EXTENSIBLE" = "1" ]; then
+		echo "Unable to access \"$target_sdk_dir\", will not attempt to use" \
+		     "sudo as as extensible SDK cannot be used as root."
+		exit 1
+	fi
+
+	SUDO_EXEC=$(which "sudo")
+	if [ -z $SUDO_EXEC ]; then
+		echo "No command 'sudo' found, please install sudo first. Abort!"
+		exit 1
+	fi
+
+	# test sudo could gain root right
+	$SUDO_EXEC pwd >/dev/null 2>&1
+	[ $? -ne 0 ] && echo "Sorry, you are not allowed to execute as root." && exit 1
+
+	# now that we have sudo rights, create the directory
+	$SUDO_EXEC mkdir -p $target_sdk_dir >/dev/null 2>&1
+fi
+
+printf "Extracting SDK..."
+if [ @SDK_ARCHIVE_TYPE@ = "zip" ]; then
+    tail -n +$payload_offset "$0" > sdk.zip
+    if $SUDO_EXEC unzip $EXTRA_TAR_OPTIONS sdk.zip -d $target_sdk_dir;then
+        rm sdk.zip
+    else
+        rm sdk.zip && exit 1
+    fi
+else
+    tail -n +$payload_offset "$0"| $SUDO_EXEC gtar mxJ -C $target_sdk_dir --checkpoint=.2500 $EXTRA_TAR_OPTIONS || exit 1
+fi
+echo "done"
+
+printf "Setting it up..."
+# fix environment paths
+real_env_setup_script=""
+for env_setup_script in `ls $target_sdk_dir/environment-setup-*`; do
+	if grep -q 'OECORE_NATIVE_SYSROOT=' $env_setup_script; then
+		# Handle custom env setup scripts that are only named
+		# environment-setup-* so that they have relocation
+		# applied - what we want beyond here is the main one
+		# rather than the one that simply sorts last
+		real_env_setup_script="$env_setup_script"
+	fi
+	$SUDO_EXEC gsed -e "s:@SDKPATH@:$target_sdk_dir:g" -i $env_setup_script
+done
+if [ -n "$real_env_setup_script" ] ; then
+	env_setup_script="$real_env_setup_script"
+fi
+
+@SDK_POST_INSTALL_COMMAND@
+
+# delete the relocating script, so that user is forced to re-run the installer
+# if he/she wants another location for the sdk
+if [ $savescripts = 0 ] ; then
+	$SUDO_EXEC rm -f ${env_setup_script%/*}/relocate_sdk.py ${env_setup_script%/*}/relocate_sdk.sh
+fi
+
+# Execute post-relocation script
+post_relocate="$target_sdk_dir/post-relocate-setup.sh"
+if [ -e "$post_relocate" ]; then
+	$SUDO_EXEC gsed -e "s:@SDKPATH@:$target_sdk_dir:g" -i $post_relocate
+	$SUDO_EXEC /bin/sh $post_relocate "$target_sdk_dir" "@SDKPATH@"
+	if [ $? -ne 0 ]; then
+		echo "Executing $post_relocate failed"
+		exit 1
+	fi
+	$SUDO_EXEC rm -f $post_relocate
+fi
+
+echo "SDK has been successfully set up and is ready to be used."
+echo "Each time you wish to use the SDK in a new shell session, you need to source the environment setup script e.g."
+for env_setup_script in `ls $target_sdk_dir/environment-setup-*`; do
+	echo " \$ . $env_setup_script"
+done
+
+exit 0
+
+MARKER:
diff --git a/conf/files/finalize-sdk.sh b/conf/files/finalize-sdk.sh
new file mode 100644
index 0000000..bd4f313
--- /dev/null
+++ b/conf/files/finalize-sdk.sh
@@ -0,0 +1,48 @@ 
+#!/bin/sh
+##################################################
+## file: finalize-sdk.sh
+##
+##
+## /bin/sh script to finalize oesdk files
+##
+## 1. change pathing from hardcoded path to install path
+## 2. codesign binaries and dylibs
+##
+## This can be run on the final installed files; or during install in a staging area if we know
+## what the final destination path will be.
+##
+
+x_path=$(realpath $(dirname "${0}"))
+first_csid=$(security -qq find-identity -v -p codesigning |cut -c47- |head -1 | tr -d '"')
+
+staging=${1:-"${x_path}"}
+new_path=${2:-"${x_path}"}
+codesign_id=${3:-"${first_csid}"}
+
+native_sysroot="@native_sysroot@"
+
+do_relocate=yes
+do_codesign=yes
+
+if [ "${do_relocate}" = yes ]; then
+    old_path="/usr/local/oe-sdk-hardcoded-buildpath"
+
+    find "${staging}" -type f -exec file {} +| grep -i ":.*\(ASCII\|script\|source\).*text" |cut -d: -f1  |
+        while read fn; do
+            sed -i "" "s,${old_path},${new_path},g" "${fn}" || echo "${fn}"
+        done
+fi
+
+if [ "${do_codesign}" = yes ]; then
+    if [ -z "${codesign_id}" ]; then
+        echo "requested codesigning, but did not find a codesigning identity"
+    else
+        find "${staging}/sysroots/${native_sysroot}" -type f -exec file {} + |
+            grep Mach-O | 
+            cut -d: -f1 |
+            sed -e "s,^,'," -e "s,$,'," |
+            xargs codesign --continue --force --timestamp --sign "${codesign_id}"
+    fi
+fi
+
+exit 0
diff --git a/conf/files/mk-macos-dmg.sh b/conf/files/mk-macos-dmg.sh
new file mode 100755
index 0000000..ebf95d0
--- /dev/null
+++ b/conf/files/mk-macos-dmg.sh
@@ -0,0 +1,49 @@ 
+#!/bin/bash
+##################################################
+## file: meta-darwin/conf/files/mk-macos-dmg.sh
+##
+## Original Author: Eric L. Hernes <eric@qinc.tv>
+##
+## /bin/sh script to do create macos .dmg image for openembedded sdk
+##
+
+# $1 = SDK Title
+# $2 = SDK Name
+# $3 = SDK Architecture
+# $4 = SDK Version
+# $5 = path to SDK path files
+# $6 = SDK dmg output filename
+# $7 = path to finalize script
+# $8 = destination path within the DMG
+
+pkg_title=${1:-"OpenEmbedded SDK"}
+pkg_name=${2:-"oesdk-darwin21"}
+pkg_arch=${3:-"aarch64"}
+pkg_vers=${4:-"x.x.x.y"}
+sdk_path=${5:-".../tmp/work/armv8a-oe-linux/meta-toolchain/1.0/sdk/image"}
+dmg_path=${6:-".../tmp/deploy/sdk/macos-test-sdk.dmg"}
+finalize_dmg=${7:-"finalize-dmg"}
+dst_path=${8-"/Library/Developer/org.openembedded.sdk/${pkg_name}"}
+
+dmg_finalize="${dst_path}/"$(basename "${finalize_dmg}")
+
+set $(du -sm ${sdk_path})
+
+# add 10% for overhead
+size_mb=$((${1} * 11 / 10))
+
+dd if=/dev/zero of="${dmg_path}" bs=1M count=${size_mb}
+mkfs.hfsplus -s -v "${pkg_name}" "${dmg_path}"
+
+hfsplus "${dmg_path}" mkdir-p "${dst_path}"
+
+hfsplus "${dmg_path}" addall "${sdk_path}" "${dst_path}"
+
+hfsplus "${dmg_path}" add "${finalize_dmg}" "${dmg_finalize}"
+hfsplus "${dmg_path}" chmod 755 "${dmg_finalize}"
+
+hfsplus "${dmg_path}" rm "${dst_path}/relocate_sdk.py"
+
+hfsplus "${dmg_path}" rm "${dst_path}/post-relocate-setup.sh"
+
+
diff --git a/conf/files/mk-macos-pkg.sh b/conf/files/mk-macos-pkg.sh
new file mode 100755
index 0000000..283a0e3
--- /dev/null
+++ b/conf/files/mk-macos-pkg.sh
@@ -0,0 +1,161 @@ 
+#!/bin/bash
+##################################################
+## file: meta-darwin/conf/files/mk-macos-pkg.sh
+##
+## Original Author: Eric L. Hernes <eric@qinc.tv>
+##
+## /bin/sh script to do create macos .pkg installer for openembedded sdk
+##
+
+# $1 = SDK Title
+# $2 = SDK Name
+# $3 = SDK Architecture
+# $4 = SDK Version
+# $5 = path to SDK path files
+# $6 = SDK dmg output filename
+# $7 = path to finalize script
+# $8 = destination path relative to the user's selected volume
+
+pkg_title=${1:-"OpenEmbedded SDK"}
+pkg_name=${2:-"oesdk-darwin21"}
+pkg_arch=${3:-"aarch64"}
+pkg_vers=${4:-"x.x.x.y"}
+sdk_path=${5:-".../tmp/work/armv8a-oe-linux/meta-toolchain/1.0/sdk/image"}
+pkg_path=${6:-".../tmp/deploy/sdk/macos-test-sdk.pkg"}
+finalize_pkg=${7:-"finalize-pkg"}
+dst_path=${8-"/Library/Developer/org.openembedded.sdk/${pkg_name}/x"}
+
+echo "pkg_title: ${pkg_title}"
+echo "pkg_name: ${pkg_name}"
+echo "pkg_arch: ${pkg_arch}"
+echo "pkg_vers: ${pkg_vers}"
+echo "sdk_path: ${sdk_path}"
+echo "pkg_path: ${pkg_path}"
+echo "dst_path: ${dst_path}"
+
+count=$(find ${sdk_path} -type f | wc -l)
+set $(du -sk ${sdk_path})
+kbytes=$1
+
+echo "SDK will contain ${count} files and consume ${kbytes}K bytes"
+
+org_id=org.openembedded.sdk
+
+pkg_id="${org_id}.${pkg_name}.pkg"
+
+flat=dist/Package.pkg
+
+build=build
+mkbom=mkbom
+xar=xar
+
+files=$(realpath $(dirname $0))
+
+rm -rf ${build}
+rm -f "${pkg_path}"
+
+mkdir ${build}
+cd ${build}
+
+mkdir -p ${flat}
+mkdir scripts
+
+( cd ${sdk_path} && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > ${flat}/Payload
+
+#
+# Swift installs stuff to /Library/org.swift.swiftpm;
+#
+# So let's do something similar
+# Install files to /Library/Developer/org.openembedded.sdk
+#
+cat > ${flat}/PackageInfo <<EOF
+<pkg-info format-version="2" identifier="${pkg_id}" version="${pkg_version}" relocatable="false" overwrite-permissions="false" followSymLinks="false" install-location="${dst_path}" auth="root">
+  <payload installKBytes="${kbytes}" numberOfFiles="${count}"/>
+    <bundle-version/>
+    <upgrade-bundle/>
+    <update-bundle/>
+    <atomic-update-bundle/>
+    <strict-identifier/>
+    <relocate/>
+    <scripts>
+      <preinstall file="./pre-install"/>
+      <postinstall file="./post-install"/>
+  </scripts>
+</pkg-info>
+EOF
+
+sed -e "s#@dst_path@#${dst_path}#g" \
+    ${files}/pre-install.in >scripts/pre-install
+
+sed -e 's,$,&,' ${files}/post-install.in >scripts/post-install
+cp ${finalize_pkg} scripts/finalize-pkg
+
+chmod +x scripts/finalize-pkg
+chmod +x scripts/pre-install
+chmod +x scripts/post-install
+
+( cd scripts && find . | cpio -o --format odc --owner 0:80 | gzip -c ) > ${flat}/Scripts
+${mkbom} -u 0 -g 80 ${sdk_path} ${flat}/Bom
+
+#
+# linux calls it aarch64; apple calls it arm64
+#
+
+declare -A arch_map
+arch_map["aarch64"]="arm64"
+arch_map["x86_64"]="x86_64"
+
+p_id=$(tr -dc 'a-z0-9' < /dev/urandom | head -c 16)
+pki_id="org.openembedded.oesdk.installer.${p_id}"
+
+
+cat >dist/Distribution <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<installer-gui-script minSpecVersion="2">
+    <title>${pkg_title}</title>
+    <options customize="allow" hostArchitectures="${arch_map[${pkg_arch}]}"/>
+    <domains enable_localSystem="true" enable_anywhere="true" enable_currentUserHome="true"/>
+    <installation-check script="canInstall()"/>
+    <script><![CDATA[
+	function canInstall() {
+		var version;
+		var major;
+
+		// ProductVersion is usually "major.minor.patch"
+		if (!system || !system.version || !system.version.ProductVersion) {
+			return false;
+		}
+
+		version = system.version.ProductVersion.split(".");
+		major = parseInt(version[0], 10);
+
+		if (isNaN(major)) {
+			return false;
+		}
+
+		// Darwin21 ==  macOS 12+
+		if (major < 12) {
+			return false;
+		}
+
+		return true;
+	}
+
+]]></script>
+    <pkg-ref id="${p_id}" version="1" onConclusion="none">#Package.pkg</pkg-ref>
+    <pkg-ref id="${p_id}" packageIdentifier="${pki_id}" installKBytes="0" updateKBytes="0">
+        <must-close/>
+        <bundle-version/>
+    </pkg-ref>
+    <choices-outline>
+        <line choice="${p_id}"/>
+    </choices-outline>
+    <choice id="${p_id}" title="Package" start_selected="true">
+        <pkg-ref id="${p_id}"/>
+    </choice>
+    <product id="${pkg_id}" version="${pkg_vers}"/>
+</installer-gui-script>
+EOF
+
+( cd dist && ${xar} --compression none -cf "${pkg_path}" * )
+
diff --git a/conf/files/post-install.in b/conf/files/post-install.in
new file mode 100644
index 0000000..9321f79
--- /dev/null
+++ b/conf/files/post-install.in
@@ -0,0 +1,9 @@ 
+#!/bin/bash
+#########################################
+#  file: meta-darwin/conf/files/post-install.in
+#
+#  @file    post-install
+#  @version V1.0
+#
+# post install script for meta-darwin SDK
+#
diff --git a/conf/files/pre-install.in b/conf/files/pre-install.in
new file mode 100644
index 0000000..0c488c4
--- /dev/null
+++ b/conf/files/pre-install.in
@@ -0,0 +1,84 @@ 
+#!/usr/bin/osascript -l JavaScript
+/***************************************************
+ * file: meta-darwin/conf/files/pre-install.in
+ *
+ * @file    pre-install.jxa
+ * @version V1.0
+ *
+ * pre-install script for meta-darwin macOS SDK
+ *
+ * this script gets user options and sets up various things
+ * so that the files are installed properly in their final
+ * destination
+ *
+ */
+
+ObjC.import("stdlib");
+
+var seApp = Application("System Events");
+var oProcess = seApp.processes.whose({frontmost: true})[0];
+var appName = oProcess.displayedName();
+
+app = Application.currentApplication();
+
+app.includeStandardAdditions = true;
+
+retval = []
+
+function run(args) {
+
+  codesign_id=""
+  if (true) {
+    idstr = app.doShellScript("security -qq find-identity -v -p codesigning |cut -c47- |tr '\n' ';'")
+    idList = idstr.split(';').filter(element => element);
+    switch (idList.length) {
+      case 0: // can't sign
+        let dialogText = "Could not find any code signing identities, binaries will not be signed"
+        app.displayDialog(dialogText)
+      break;
+
+      case 1: // no decisions
+        codesign_id = idList[0]
+      break;
+
+      default:
+        codesign_id = app.chooseFromList(idList, {
+          withTitle: "Signing ID",
+          withPrompt: "Please select an ID to sign binaries",
+          defaultItems: [idList[0]],
+          okButtonName: "OK",
+          cancelButtonName: "Cancel",
+          multipleSelectionsAllowed: false,
+          emptySelectionAllowed: false
+        })
+      if (codesign_id == false) {
+        let dialogText = "Cancelled code signing"
+        app.displayDialog(dialogText)
+        return false
+      }
+    }
+  }
+
+  // finalize script
+  // finalize {staging} {new_path} {code_sign}
+  pwd = ObjC.unwrap($.NSFileManager.defaultManager.currentDirectoryPath)
+  finalize = pwd + "/finalize-pkg";
+  staging = $.getenv("INSTALLER_PAYLOAD_DIR") + "@dst_path@"
+  new_path = args[1]
+  command = `${finalize} "${staging}" "${new_path}" ${codesign_id}`
+
+  var dialogText = "Will run a script to relocate and codesign\n\n"
+  dialogText += "\n\n"
+  dialogText += "This may take a few minutes depending on the size of the SDK"
+
+  app.displayDialog(dialogText)
+
+  finalize_data = app.doShellScript(command + " >/dev/null 2>&1")
+
+  app.displayDialog(finalize_data)
+
+  retval.push("ok")
+  return retval.join("\n")
+}
+
+/* end of pre-install.in */
diff --git a/conf/layer.conf b/conf/layer.conf
index 2f14754..6730f3b 100644
--- a/conf/layer.conf
+++ b/conf/layer.conf
@@ -9,3 +9,6 @@  BBFILES += "${LAYERDIR}/recipes*/*/*.bb ${LAYERDIR}/recipes*/*/*.bbappend"
 BBFILE_COLLECTIONS += "meta-darwin"
 BBFILE_PATTERN_meta-darwin := "^${LAYERDIR}/"
 BBFILE_PRIORITY_meta-darwin = "8"
+
+DARWINBASE = '${@os.path.normpath("${LAYERDIR}")}'
+BB_BASEHASH_IGNORE_VARS:append = " DARWINBASE"
diff --git a/conf/machine-sdk/darwin-common.inc b/conf/machine-sdk/darwin-common.inc
index cec76a5..2f1aec9 100644
--- a/conf/machine-sdk/darwin-common.inc
+++ b/conf/machine-sdk/darwin-common.inc
@@ -14,8 +14,13 @@  SDKUSE_NLS = "no"
 SDKIMAGE_LINGUAS = ""
 SDK_DEPENDS:remove = "nativesdk-glibc-locale nativesdk-qemuwrapper-cross"
 
+SDK_DEPENDS:append = "${@bb.utils.contains('DARWIN_INSTALLER_PKG', '1', ' bomutils-native xar-native', '', d)}"
+SDK_DEPENDS:append = "${@bb.utils.contains('DARWIN_INSTALLER_DMG', '1', ' hfsprogs-native libdmg-hfsplus-native', '', d)}"
+
 SDKPKGSUFFIX = "nativesdk-darwin"
 
+DARWIN_INSTALL_LOC = "${@d.getVar('DARWIN_INSTALLER_PATH') or '/Library/Developer/org.openembedded.sdk'}"
+
 OSX_TOOLCHAIN_OPTIONS = " \
     -mmacosx-version-min=12.3 \
     -L${STAGING_DIR_TARGET}${SDKPATHNATIVE}/usr/lib \
@@ -24,9 +29,12 @@  OSX_TOOLCHAIN_OPTIONS = " \
 "
 
 TOOLCHAIN_OPTIONS:append:darwin21 = " \
-    ${OSX_TOOLCHAIN_OPTIONS}"
+    ${OSX_TOOLCHAIN_OPTIONS} \
+"
+
 TOOLCHAIN_OPTIONS:append:class-cross-canadian = " \
-    ${OSX_TOOLCHAIN_OPTIONS}"
+    ${OSX_TOOLCHAIN_OPTIONS} \
+"
 
 # Remove -rpath-link
 BUILDSDK_LDFLAGS = " \
@@ -35,3 +43,45 @@  BUILDSDK_LDFLAGS = " \
 "
 
 MACHINEOVERRIDES .= ":darwinsdk"
+
+TOOLCHAIN_SHAR_EXT_TMPL ?= "${DARWINBASE}/conf/files/darwin-toolchain-shar-extract.sh"
+
+SDK_POSTPROCESS_COMMAND:append = "${@bb.utils.contains('DARWIN_INSTALLER_PKG', '1', ' create_macos_pkg', '', d)}"
+SDK_POSTPROCESS_COMMAND:append = "${@bb.utils.contains('DARWIN_INSTALLER_DMG', '1', ' create_macos_dmg', '', d)}"
+
+#
+# remove the .xz and .sh creation if we want to save a bit of time
+SDK_POSTPROCESS_COMMAND:remove = "${@bb.utils.contains('DARWIN_INSTALLER_SH', '0', ' archive_sdk', '', d)}"
+SDK_POSTPROCESS_COMMAND:remove = "${@bb.utils.contains('DARWIN_INSTALLER_SH', '0', ' create_shar', '', d)}"
+
+fakeroot create_macos_pkg() {
+    sdk_pkg="${SDKDEPLOYDIR}/${TOOLCHAIN_OUTPUTNAME}.pkg"
+    native_sysroot=$(basename ${SDKPATHNATIVE})
+
+    sed -e "s#@target_prefix@#${TARGET_PREFIX}#g" \
+        -e "s#@native_sysroot@#${native_sysroot}#g" \
+         ${DARWINBASE}/conf/files/finalize-sdk.sh \
+         > "${B}/finalize-pkg"
+
+    (cd ${B}; \
+        ${DARWINBASE}/conf/files/mk-macos-pkg.sh "${SDK_TITLE}" "${SDK_NAME}" "${SDK_ARCH}" "${DISTRO_VERSION}.${SDK_VERSION}" "${SDK_OUTPUT}/${SDKPATH}" "${sdk_pkg}" "${B}/finalize-pkg" ${DARWIN_INSTALL_LOC}/${SDK_NAME} \
+    )
+
+   ls -lh "${sdk_pkg}"
+}
+
+fakeroot create_macos_dmg() {
+    sdk_dmg="${SDKDEPLOYDIR}/${TOOLCHAIN_OUTPUTNAME}.dmg"
+    native_sysroot=$(basename ${SDKPATHNATIVE})
+    sed -e "s#@target_prefix@#${TARGET_PREFIX}#g" \
+        -e "s#@native_sysroot@#${native_sysroot}#g" \
+         ${DARWINBASE}/conf/files/finalize-sdk.sh \
+         > "${B}/finalize-dmg"
+
+    echo 'rm ${0}' >> "${B}/finalize-dmg"
+
+    ( cd ${B}; \
+        ${DARWINBASE}/conf/files/mk-macos-dmg.sh "${SDK_TITLE}" "${SDK_NAME}" "${SDK_ARCH}" "${DISTRO_VERSION}.${SDK_VERSION}" "${SDK_OUTPUT}/${SDKPATH}" "${sdk_dmg}" "${B}/finalize-dmg" "${DARWIN_INSTALL_LOC}/${SDK_NAME}" \
+    )
+   ls -lh "${sdk_dmg}"
+}