Skip to content

Instantly share code, notes, and snippets.

@KosmicTask
Created December 9, 2019 17:11
Show Gist options
  • Save KosmicTask/d97904304f242308feaad94aa93c0513 to your computer and use it in GitHub Desktop.
Save KosmicTask/d97904304f242308feaad94aa93c0513 to your computer and use it in GitHub Desktop.
Make an embeddable copy of Mono on macOS
#!/bin/sh
# make-mono-framework.sh
#
# Generate ./Mono.framework from /Library/Frameworks/Mono.framework.
# The generated framework will be suitable for copying into an app bundle.
#
# Typical usage would be:
# sudo ./make-mono-framework.sh x.x.x
#
#
# Looking at how Xamarin package this up for Xamarin.mac apps it is clear that we could perhaps
# simplify the folder structure here.
#
USAGE="usage is make-mono-framework mono-version"
# arg 1 is Mono version
if [ -z "$1" ]
then
echo "Missing Mono version string; $USAGE "
exit 1
fi
VERSION="$1"
#commands
MK_DIR='mkdir -vp'
# change to directory of this script
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $SCRIPT_DIR
# targets, we copy from LIB_ to OUT_
FRAMEWORK=Mono.framework
LIB_FRAMEWORK=/Library/Frameworks/Mono.framework
OUT_FRAMEWORK=${SCRIPT_DIR}/${FRAMEWORK}
# remove existing framework
echo "Removing existing ${FRAMEWORK}"
rm -rf $FRAMEWORK
# make bundle from build products
echo "Making framework bundle"
$MK_DIR $FRAMEWORK
cd $FRAMEWORK
# folder names
F_VERSIONS='Versions'
F_VERSION=$VERSION
F_BIN='bin'
F_COMMANDS='commands'
F_ETC='etc'
F_MONO='mono'
F_NET_FRAMEWORK_VERSION='4.5'
F_LIB='lib'
F_GAC='gac'
# relative folder paths
P_VERSIONS=$F_VERSIONS
P_VERSION=${P_VERSIONS}/$F_VERSION
P_BIN=${P_VERSION}/$F_BIN
P_COMMANDS=${P_VERSION}/$F_COMMANDS
P_ETC=${P_VERSION}/$F_ETC
P_LIB=${P_VERSION}/$F_LIB
# make out paths
$MK_DIR ${OUT_FRAMEWORK}/$P_VERSIONS
$MK_DIR ${OUT_FRAMEWORK}/$P_VERSION
$MK_DIR ${OUT_FRAMEWORK}/$P_BIN
$MK_DIR ${OUT_FRAMEWORK}/$P_COMMANDS
$MK_DIR ${OUT_FRAMEWORK}/$P_ETC
$MK_DIR ${OUT_FRAMEWORK}/$P_LIB
# native libraries
LIB_MONO=libmonosgen-2.0.1.dylib
#
# copy_targets and srguments
#
SRC_PATH=''
OUT_PATH=''
TARGETS=() # passing array as function arg seems tricky
function copy_targets() {
if [ ! -d $OUT_PATH ]; then
$MK_DIR $OUT_PATH;
fi
for TARGET in "${TARGETS[@]}"; do
cp -R ${SRC_PATH}/${TARGET} $OUT_PATH
done
}
#
# do_lipo
#
function do_lipo() {
local TARGET=$1
LIPO_TARGET=${TARGET}.lipotarget
cp $TARGET $LIPO_TARGET
rm -f $TARGET
lipo -extract 'x86_64' -output $TARGET $LIPO_TARGET
rm -f $LIPO_TARGET
}
#
# copy bin targets
#
SRC_PATH=${LIB_FRAMEWORK}/${P_BIN}
OUT_PATH=${OUT_FRAMEWORK}/${P_BIN}
TARGETS=(
mcs
mono-sgen64
)
copy_targets
#
# copy etc/mono targets
#
SRC_PATH=${LIB_FRAMEWORK}/${P_ETC}/${F_MONO}
OUT_PATH=${OUT_FRAMEWORK}/${P_ETC}/${F_MONO}
TARGETS=(
config
mconfig
$F_NET_FRAMEWORK_VERSION
)
copy_targets
#
# copy lib targets
#
SRC_PATH=${LIB_FRAMEWORK}/${P_LIB}
OUT_PATH=${OUT_FRAMEWORK}/${P_LIB}
TARGETS=(
libMonoPosixHelper.dylib
$LIB_MONO
)
copy_targets
do_lipo ${OUT_PATH}/${LIB_MONO}
#
# copy lib/mono/${4.5} targets
#
SRC_PATH=${LIB_FRAMEWORK}/${P_LIB}/${F_MONO}/${F_NET_FRAMEWORK_VERSION}
OUT_PATH=${OUT_FRAMEWORK}/${P_LIB}/${F_MONO}/${F_NET_FRAMEWORK_VERSION}
TARGETS=(
mscorlib.dll
mcs.exe
)
copy_targets
#
# copy lib/mono/gac targets
# note that the gac contains folders named using the assembly name.
# each assembly folder then contsins subfolders identifying instances of the named assembly by its strong name.
# required assemblies available as monolinker -c link -a UK.BrightPay.Engine.OSX.exe -out minimal
# we should really run the monolinker here and dynamically extract the required GAC assemblies
SRC_PATH=${LIB_FRAMEWORK}/${P_LIB}/${F_MONO}/${F_GAC}
OUT_PATH=${OUT_FRAMEWORK}/${P_LIB}/${F_MONO}/${F_GAC}
TARGETS=(
I18N
I18N.CJK
I18N.MidEast
I18N.Other
I18N.Rare
I18N.West
Microsoft.CSharp
Mono.CSharp
Mono.Data.Tds
Mono.Posix
Mono.Security
System.ComponentModel.DataAnnotations
System.Configuration
System.Core
System.Data
System.Data.Entity
System.Drawing
System.EnterpriseServices
System.Management
System.Numerics
System.Runtime.Serialization
System.Security
System.Transactions
System.Web
System.Xml.Linq
System.Xml
System
)
copy_targets
#
# iterate over the GAC strong named folders and create symlinks in lib/mono/${4.5} pointing to actual dlls.
# these symlinks make it much easier to locate the mono system libraries and replicates the form of the mono framework bundle.
#
OUT_PATH=${OUT_FRAMEWORK}/${P_LIB}/${F_MONO}/${F_NET_FRAMEWORK_VERSION}
for TARGET in "${TARGETS[@]}"; do
SRC_FOLDER="$SRC_PATH"/"$TARGET"
# we loop here but there should only be one strong named subfolder
for d in "$SRC_FOLDER"/*/ ; do
STRONG_NAME="$(basename $d)"
ln -sv ../gac/"$TARGET"/"$STRONG_NAME"/"$TARGET".dll "$OUT_PATH"/"$TARGET".dll
done
done
#
# rename version folder to A.
# this makes life simpler as when the xcode does the signing it always looks for the A version
#
mv ./$P_VERSIONS/$F_VERSION ./$P_VERSIONS/A
#
# we must have a Current symlink otherwise codesign rejects bundle
#
ln -sv ./A ${OUT_FRAMEWORK}/$P_VERSIONS/Current
#
# create resources folder and copy in framework bundle plist.
# without this codesign will fail for the bundle citing an invalid format
# as an info.plist is a mandatory signature component.
#
OUT_PATH=${OUT_FRAMEWORK}/$P_VERSIONS/A/Resources
$MK_DIR ${OUT_PATH}
cp "$SCRIPT_DIR"/mono-framework-info.plist "$OUT_PATH"/info.plist
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment