osxfuse/build.sh

951 lines
29 KiB
Bash
Executable File

#!/bin/bash
# Copyright (c) 2011-2016 Benjamin Fleischer
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
function build_target_get_build_directory
{
local target_name="${1}"
printf "%s/%s" "${BUILD_BUILD_DIRECTORY}" "${target_name}"
}
function build_target_sanity_check
{
if ! xcode_sdk_is_supported "${BUILD_TARGET_OPTION_SDK}"
then
common_die "macOS ${BUILD_TARGET_OPTION_SDK} SDK not supported"
fi
if ! xcode_sdk_is_installed "${BUILD_TARGET_OPTION_SDK}"
then
common_die "macOS ${BUILD_TARGET_OPTION_SDK} SDK not found"
fi
if ! array_contains "XCODE_INSTALLED" "${BUILD_TARGET_OPTION_XCODE}"
then
common_die "Xcode ${BUILD_TARGET_OPTION_XCODE} not found"
fi
if ! xcode_contains_sdk "${BUILD_TARGET_OPTION_XCODE}" "${BUILD_TARGET_OPTION_SDK}"
then
common_die "Xcode ${BUILD_TARGET_OPTION_XCODE} does not include macOS ${BUILD_TARGET_OPTION_SDK} SDK"
fi
function build_target_sanity_check_build_achitecture
{
if ! array_contains "DEFAULT_SDK_${BUILD_TARGET_OPTION_SDK/./_}_ARCHITECURES" "${1}"
then
common_die "macOS ${BUILD_TARGET_OPTION_SDK} SDK does not support architecture ${1}"
fi
}
array_foreach BUILD_TARGET_OPTION_ARCHITECTURES build_target_sanity_check_build_achitecture
unset build_target_sanity_check_build_achitecture
if ! version_is_version "${BUILD_TARGET_OPTION_DEPLOYMENT_TARGET}"
then
common_die "Deployment target is illegal"
fi
version_compare "${BUILD_TARGET_OPTION_DEPLOYMENT_TARGET}" 10.0
if (( ${?} == 1 ))
then
common_die "Deployment target must be at least macOS 10.0"
fi
version_compare "${BUILD_TARGET_OPTION_DEPLOYMENT_TARGET}" "${BUILD_TARGET_OPTION_SDK}"
if (( ${?} == 2 ))
then
common_die "macOS ${BUILD_TARGET_OPTION_SDK} SDK does not support macOS ${BUILD_TARGET_OPTION_DEPLOYMENT_TARGET} as deployment target"
fi
if [[ -n "${BUILD_TARGET_OPTION_DEBUG_DIRECTORY}" && ! -d "${BUILD_TARGET_OPTION_DEBUG_DIRECTORY}" ]]
then
common_die "Debug directory '${BUILD_TARGET_OPTION_DEBUG_DIRECTORY}' does not exist"
fi
}
function build_target_getopt
{
function build_target_getopt_internal
{
local -a options=()
common_getopt options "p:,preset:,s:,custom-specs:,h:,handler:,o:,out:" "${@}"
common_die_on_error "${options[@]}"
set -- "${options[@]}"
local preset=""
local custom_specs=""
local handler=""
local out=""
while [[ ${#} -gt 0 ]]
do
case "${1}" in
--)
shift
break
;;
-p|--preset)
preset="${2}"
shift 2
;;
-s|--custom-specs)
custom_specs="${2}"
shift 2
;;
-h|--handler)
handler="${2}"
shift 2
;;
-o|--out)
out="${2}"
shift 2
;;
esac
done
if [[ -n "${out}" ]]
then
common_assert "common_is_variable `string_escape "${out}"`"
fi
local preset_specs=""
case "${preset}" in
build)
preset_specs="s:,sdk:,x:,xcode:,a:,architecure:,d:,deployment-target:,c:,configuration:,b:,build-setting:,m:,macro:,code-sign-identity:,provisioning-profile:,product-sign-identity:"
;;
clean)
preset_specs="root,no-root"
;;
install)
preset_specs="root,no-root,o:,owner:,g:,group:,debug:"
;;
make-build)
preset_specs="s:,sdk:,x:,xcode:,a:,architecure:,d:,deployment-target:,m:,macro:,code-sign-identity:,product-sign-identity:,prefix:"
;;
make-install)
preset_specs="prefix:,root,no-root,debug:"
;;
meta)
preset_specs=""
;;
esac
local specs=""
if [[ -n "${preset_specs}" && -n "${custom_specs}" ]]
then
specs="${preset_specs},${custom_specs}"
else
specs="${preset_specs}${custom_specs}"
fi
common_getopt options "${specs}" "${@:1}"
common_die_on_error "${options[@]}"
set -- "${options[@]}"
local sdk=""
local xcode=""
local -a architectures=()
local deployment_target=""
local build_configuration=""
local -a build_settings=()
local -a macros=()
while [[ ${#} -gt 0 ]]
do
case "${1}" in
--)
shift
break
;;
-s|--sdk)
sdk="${2}"
shift 2
;;
-x|--xcode)
xcode="${2}"
shift 2
;;
-a|--architecture)
if ! array_contains architectures "${2}"
then
array_append architectures "${2}"
fi
shift 2
;;
-d|--deployment-target)
deployment_target="${2}"
shift 2
;;
-c|--configuration)
build_configuration="${2}"
shift 2
;;
-b|--build-setting)
if ! array_contains build_settings "${2}"
then
array_append build_settings "${2}"
fi
shift 2
;;
-m|--macro)
array_append macros "${2}"
shift 2
;;
--code-sign-identity)
BUILD_TARGET_OPTION_CODE_SIGN_IDENTITY="${2}"
shift 2
;;
--provisioning-profile)
BUILD_TARGET_OPTION_PROVISIONING_PROFILE_SPECIFIER="${2}"
shift 2
;;
--product-sign-identity)
BUILD_TARGET_OPTION_PRODUCT_SIGN_IDENTITY="${2}"
shift 2
;;
--prefix)
BUILD_TARGET_OPTION_PREFIX="${2}"
shift 2
;;
--root)
BUILD_TARGET_OPTION_ROOT=1
shift
;;
--no-root)
BUILD_TARGET_OPTION_ROOT=0
shift
;;
-o|--owner)
BUILD_TARGET_OPTION_OWNER="${2}"
shift 2
;;
-g|--group)
BUILD_TARGET_OPTION_GROUP="${2}"
shift 2
;;
--debug)
BUILD_TARGET_OPTION_DEBUG_DIRECTORY="${2}"
shift 2
;;
*)
if common_is_function "${handler}"
then
local -i offset=0
"${handler}" "${@}"
offset=${?}
common_assert "(( ${offset} > 0 ))" "Option '${1}' unsupported by handler"
shift ${offset}
else
common_die -t "Option handler required"
fi
;;
esac
done
if [[ -z "${out}" && ${#} -gt 0 ]]
then
common_warn "Action '${BUILD_TARGET_ACTION}' of target '${BUILD_TARGET_NAME}' does not expect any arguments"
fi
if [[ -n "${sdk}" ]]
then
BUILD_TARGET_OPTION_SDK="${sdk}"
BUILD_TARGET_OPTION_DEPLOYMENT_TARGET="${sdk}"
fi
if [[ -n "${xcode}" ]]
then
BUILD_TARGET_OPTION_XCODE="${xcode}"
elif xcode_sdk_is_installed "${BUILD_TARGET_OPTION_SDK}"
then
array_get XCODE_SDK_${BUILD_TARGET_OPTION_SDK//./_}_XCODE 0 BUILD_TARGET_OPTION_XCODE
fi
if [[ ${#architectures[@]} -gt 0 ]]
then
common_variable_clone architectures BUILD_TARGET_OPTION_ARCHITECTURES
elif xcode_sdk_is_supported "${BUILD_TARGET_OPTION_SDK}"
then
common_variable_clone DEFAULT_SDK_${BUILD_TARGET_OPTION_SDK//./_}_ARCHITECURES BUILD_TARGET_OPTION_ARCHITECTURES
fi
if [[ -n "${deployment_target}" ]]
then
BUILD_TARGET_OPTION_DEPLOYMENT_TARGET="${deployment_target}"
fi
if [[ -n "${build_configuration}" ]]
then
BUILD_TARGET_OPTION_BUILD_CONFIGURATION="${build_configuration}"
fi
if [[ ${#build_settings[@]} -gt 0 ]]
then
common_variable_clone build_settings BUILD_TARGET_OPTION_BUILD_SETTINGS
fi
if [[ ${#macros[@]} -gt 0 ]]
then
common_variable_clone macros BUILD_TARGET_OPTION_MACROS
fi
if [[ -n "${out}" ]]
then
local -a arguments=("${@}")
printf "%s=" "${out}"
common_variable_clone arguments
printf "\n"
fi
local target_name_uppercase="`string_uppercase <<< "${BUILD_TARGET_NAME}"`"
for variable in ${!BUILD_TARGET_OPTION_@} `common_variable_expand "${target_name_uppercase}_"`
do
if ! common_variable_is_readonly "${variable}"
then
common_variable_print "${variable}"
fi
done
return 0
}
eval "`build_target_getopt_internal "${@}"`"
unset build_target_getopt_internal
common_log_variable ${!BUILD_TARGET_OPTION_@}
build_target_sanity_check
DEVELOPER_DIR="`xcode_get_path "${BUILD_TARGET_OPTION_XCODE}"`"
export DEVELOPER_DIR
}
function build_target_xcodebuild
{
local compiler=""
common_variable_clone "DEFAULT_SDK_${BUILD_TARGET_OPTION_SDK//./_}_COMPILER" compiler
local -a command=(/usr/bin/xcodebuild
-configuration "${BUILD_TARGET_OPTION_BUILD_CONFIGURATION}"
CONFIGURATION_BUILD_DIR="`build_target_get_build_directory "${BUILD_TARGET_NAME}"`"
SDKROOT="macosx${BUILD_TARGET_OPTION_SDK}"
ARCHS="`array_join BUILD_TARGET_OPTION_ARCHITECTURES " "`"
GCC_VERSION="${compiler}"
MACOSX_DEPLOYMENT_TARGET="${BUILD_TARGET_OPTION_DEPLOYMENT_TARGET}"
CODE_SIGN_IDENTITY="${BUILD_TARGET_OPTION_CODE_SIGN_IDENTITY}"
PROVISIONING_PROFILE_SPECIFIER="${BUILD_TARGET_OPTION_PROVISIONING_PROFILE_SPECIFIER}"
"${BUILD_TARGET_OPTION_BUILD_SETTINGS[@]}")
if [[ ${#BUILD_TARGET_OPTION_MACROS} -gt 0 ]]
then
command+=(GCC_PREPROCESSOR_DEFINITIONS="\$(inherited)`printf " %q" "${BUILD_TARGET_OPTION_MACROS[@]}"`")
fi
command+=("${@}")
"${command[@]}" 1>&3 2>&4
}
function build_target_configure
{
local sdk_path="`xcodebuild -version -sdk macosx${BUILD_TARGET_OPTION_SDK} Path 2>&4`"
if [[ "${sdk_path}" =~ [[:space:]] ]]
then
common_die "macOS ${BUILD_TARGET_OPTION_SDK} SDK path '${sdk_path}' contains whitespace"
fi
local compiler=""
common_variable_clone "DEFAULT_SDK_${BUILD_TARGET_OPTION_SDK//./_}_COMPILER" compiler
local compiler_binary=""
case "${compiler}" in
4.0|4.2)
compiler_binary="gcc-${compiler}"
;;
com.apple.compilers.llvmgcc42)
compiler_binary="llvm-gcc-4.2"
;;
com.apple.compilers.llvm.clang.1_0)
compiler_binary="clang"
;;
*)
common_die "Compiler '${compiler}' is not supported"
;;
esac
for macro in "${BUILD_TARGET_OPTION_MACROS[@]}"
do
common_assert "[[ `string_escape "${macro}"` =~ ^[^[:space:]]*$ ]]" "Macro '${macro//\'/\\\'}' contains whitespace"
done
MAKE="`/usr/bin/xcrun --find make`" \
CPP="`/usr/bin/xcrun --find cpp`" \
CC="`/usr/bin/xcrun --find "${compiler_binary}"`" \
LD="`/usr/bin/xcrun --find ld`" \
CPPFLAGS="-Wp,-isysroot,${sdk_path} ${CPPFLAGS}" \
CFLAGS="${BUILD_TARGET_OPTION_ARCHITECTURES[@]/#/-arch } -isysroot ${sdk_path} -mmacosx-version-min=${BUILD_TARGET_OPTION_DEPLOYMENT_TARGET}${BUILD_TARGET_OPTION_MACROS[@]/#/ -D} ${CFLAGS}" \
LDFLAGS="-Wl,-syslibroot,${sdk_path} -Wl,-macosx_version_min,${BUILD_TARGET_OPTION_DEPLOYMENT_TARGET} ${LDFLAGS}" \
./configure --prefix="${BUILD_TARGET_OPTION_PREFIX}" "${@}" 1>&3 2>&4
}
function build_target_make
{
local -a options=()
common_getopt options "root,no-root" "${@}"
common_die_on_error "${options[@]}"
set -- "${options[@]}"
local -i root="${BUILD_TARGET_OPTION_ROOT}"
while [[ ${#} -gt 0 ]]
do
case "${1}" in
--)
shift
break
;;
--root)
root=1
shift
;;
--no-root)
root=0
shift
;;
esac
done
local -a command=(/usr/bin/xcrun make "${@}")
if (( root == 0 ))
then
"${command[@]}" 1>&3 2>&4
else
common_sudo "Enter password to run make" "${command[@]}" 1>&3 2>&4
fi
}
function build_target_codesign
{
if [[ -n "${BUILD_TARGET_OPTION_CODE_SIGN_IDENTITY}" ]]
then
/usr/bin/codesign -s "${BUILD_TARGET_OPTION_CODE_SIGN_IDENTITY}" -f "${@}" 1>&3 2>&4
else
return 0
fi
}
function build_target_pkgbuild
{
local command=(/usr/bin/pkgbuild)
if [[ -n "${BUILD_TARGET_OPTION_PRODUCT_SIGN_IDENTITY}" ]]
then
command+=(--sign "${BUILD_TARGET_OPTION_PRODUCT_SIGN_IDENTITY}")
fi
command+=("${@}")
"${command[@]}" 1>&3 2>&4
}
function build_target_pkgbuild_component_plist_foreach
{
common_assert "common_is_function `string_escape "${3}"`"
common_assert "[[ ! `string_escape "${3}"` =~ ^bt_pkgbuild_component_plist_foreach_ ]]"
if [[ "`plist_array_size "${1}" "${2}"`" -gt 0 ]]
then
eval "
function build_target_pkgbuild_component_plist_foreach_internal
{
while [[ \${#} -gt 0 ]]
do
${3} `string_escape "${1}"` ${2}:\${1}
if /usr/libexec/PlistBuddy -c \"Print '${2}:\${1}:ChildBundles'\" `string_escape "${1}"` > /dev/null 2>&1
then
build_target_pkgbuild_component_plist_foreach `string_escape "${1}"` \"${2}:\${1}:ChildBundles\" ${3}
fi
shift
done
}
" && build_target_pkgbuild_component_plist_foreach_internal $(/usr/bin/jot - 0 $(( $(plist_array_size "${1}" "${2}") - 1 )))
fi
}
function build_target_productbuild
{
local command=(/usr/bin/productbuild)
if [[ -n "${BUILD_TARGET_OPTION_PRODUCT_SIGN_IDENTITY}" ]]
then
command+=(--sign "${BUILD_TARGET_OPTION_PRODUCT_SIGN_IDENTITY}")
fi
command+=("${@}")
"${command[@]}" 1>&3 2>&4
}
function build_target_install
{
local -a options=()
common_getopt options "r,root,o:,owner:,g:,group:" "${@}"
common_die_on_error "${options[@]}"
set -- "${options[@]}"
local -i root="${BUILD_TARGET_OPTION_ROOT}"
local owner="${BUILD_TARGET_OPTION_OWNER}"
local group="${BUILD_TARGET_OPTION_GROUP}"
while [[ ${#} -gt 0 ]]
do
case "${1}" in
--)
shift
break
;;
-r|--root)
root=1
shift
;;
-o|--owner)
owner="${2}"
shift 2
;;
-g|--group)
group="${2}"
shift 2
;;
esac
done
local source="${1}"
local target_directory="${2}"
common_assert "[[ -e `string_escape "${source}"` ]]"
common_assert "[[ -d `string_escape "${target_directory}"` ]]"
local target="${target_directory}"
if [[ ! "${source}" =~ /$ ]]
then
target="${target}/`basename "${source}"`"
common_assert "[[ ! -e `string_escape "${target}"` ]]" "Target is already installed"
fi
local -a command=(/bin/cp -pPR "${source}" "${target}")
if (( root == 0 ))
then
"${command[@]}" 1>&3 2>&4
else
common_sudo "Enter password to install target" "${command[@]}" 1>&3 2>&4
fi
common_die_on_error "Failed to install target"
if [[ -n "${owner}" || -n "${group}" ]]
then
common_sudo "Enter password to change owner and/or group of installed target" chown -R "${owner}:${group}" "${target}" 1>&3 2>&4
common_die_on_error "Failed to change owner and/or group of installed target"
fi
}
function build_target_invoke
{
local target_name="${1}"
local action="${2}"
local target_path="${BUILD_D_DIRECTORY}/targets/${target_name}.sh"
common_assert "common_function_is_legal_name `string_escape "${target_name}"`"
common_assert "[[ -f `string_escape "${target_path}"` ]]" "Target '${target_name}' does not exist"
(
eval "
function ${target_name}_build
{
common_die -t \"Action '\${BUILD_TARGET_ACTION}' of target '\${BUILD_TARGET_NAME}' needs to be overridden\"
}
function ${target_name}_clean
{
build_target_getopt -p clean -- \"\${@}\"
common_log -v 3 \"Removing target build directory '\${BUILD_TARGET_BUILD_DIRECTORY}'\"
if [[ -e \"\${BUILD_TARGET_BUILD_DIRECTORY}\" ]]
then
local command=(rm -rf \"\${BUILD_TARGET_BUILD_DIRECTORY}\")
if (( BUILD_TARGET_OPTION_ROOT == 0 ))
then
\"\${command[@]}\" 1>&3 2>&4
else
common_sudo \"Enter password to remove target build directory\" \"\${command[@]}\" 1>&3 2>&4
fi
fi
}
function ${target_name}_help
{
build_help
printf \"Target: %s\n\n\" \"\${BUILD_TARGET_NAME}\"
printf \"Actions:\r\"
for action in \"\${BUILD_TARGET_ACTIONS[@]}\"
do
printf \"\033[10C%s\n\" \"\${action}\"
done
}
"
declare -r BUILD_TARGET_NAME="${target_name}"
declare -r BUILD_TARGET_PATH="${target_path}"
declare -r BUILD_TARGET_ACTION="${action}"
declare -ra BUILD_TARGET_ACTION_ARGUMENTS=("${@:3}")
declare -a BUILD_TARGET_ACTIONS=()
declare BUILD_TARGET_SOURCE_DIRECTORY="${BUILD_SOURCE_DIRECTORY}"
declare BUILD_TARGET_BUILD_DIRECTORY="`build_target_get_build_directory "${BUILD_TARGET_NAME}"`"
# Options
declare BUILD_TARGET_OPTION_SDK="${DEFAULT_SDK}"
declare BUILD_TARGET_OPTION_XCODE=""
declare -a BUILD_TARGET_OPTION_ARCHITECTURES=()
declare BUILD_TARGET_OPTION_DEPLOYMENT_TARGET="${DEFAULT_SDK}"
declare BUILD_TARGET_OPTION_BUILD_CONFIGURATION="${DEFAULT_BUILD_CONFIGURATION}"
declare -a BUILD_TARGET_OPTION_BUILD_SETTINGS=()
declare -a BUILD_TARGET_OPTION_MACROS=()
declare BUILD_TARGET_OPTION_CODE_SIGN_IDENTITY=""
declare BUILD_TARGET_OPTION_PROVISIONING_PROFILE_SPECIFIER=""
declare BUILD_TARGET_OPTION_PRODUCT_SIGN_IDENTITY=""
declare BUILD_TARGET_OPTION_PREFIX="${DEFAULT_PREFIX}"
declare -i BUILD_TARGET_OPTION_ROOT=0
declare BUILD_TARGET_OPTION_OWNER=""
declare BUILD_TARGET_OPTION_GROUP=""
declare BUILD_TARGET_OPTION_DEBUG_DIRECTORY=""
array_get XCODE_SDK_${BUILD_TARGET_OPTION_SDK/./_}_XCODE 0 BUILD_TARGET_OPTION_XCODE
common_variable_clone DEFAULT_SDK_${BUILD_TARGET_OPTION_SDK/./_}_ARCHITECURES BUILD_TARGET_OPTION_ARCHITECTURES
# Source target
stack_push COMMON_LOG_PREFIX "T:${BUILD_TARGET_NAME}"
common_log -v 3 "Source target ${BUILD_TARGET_NAME}"
source "${target_path}" 1>&3 2>&4
common_die_on_error "Failed to source target"
common_assert "array_is_array BUILD_TARGET_ACTIONS"
common_assert "array_contains BUILD_TARGET_ACTIONS `string_escape "${BUILD_TARGET_ACTION}"`" \
"Unsupported target action: '${BUILD_TARGET_ACTION}'"
declare DEVELOPER_DIR="`xcode_get_path "${BUILD_TARGET_OPTION_XCODE}"`"
export DEVELOPER_DIR
# Invoke target action
pushd "${BUILD_TARGET_SOURCE_DIRECTORY}" > /dev/null 2>&1
common_warn_on_error "Target source directory '${BUILD_TARGET_SOURCE_DIRECTORY}' does not exist"
common_log -v 3 "Invoke action ${BUILD_TARGET_ACTION}"
"${target_name}_${BUILD_TARGET_ACTION}" "${BUILD_TARGET_ACTION_ARGUMENTS[@]}"
declare -i rc=${?}
common_log -v 3 "Completed action ${BUILD_TARGET_ACTION}"
popd > /dev/null 2>&1
stack_pop COMMON_LOG_PREFIX
exit ${rc}
)
}
function build_clean
{
common_log -v 2 "Removing build directory '${BUILD_BUILD_DIRECTORY}'"
if [[ -e "${BUILD_BUILD_DIRECTORY}" ]]
then
rm -rf "${BUILD_BUILD_DIRECTORY}"
fi
}
function build_help
{
local script="`basename "${BASH_SOURCE[0]}"`"
/bin/cat <<EOF
Copyright (c) 2011-2015 Benjamin Fleischer
All rights reserved.
Usage: ${script} [options ...] (-h|--help) [(-t|--target) {target name}]
${script} [options ...] (-c|--clean) [(-t|--target) {target name}]
${script} [options ...] (-t|--target) {target name} [(-a|--action) {action}] -- [action options ...]
Options: [-v {verbose level}|--verbose={verbose level}]
Installed Xcode versions: `array_join XCODE_INSTALLED ", "`
Installed macOS SDKs: `array_join XCODE_SDK_INSTALLED ", "`
EOF
}
function build_main
{
local build_d_directory="`dirname "${BASH_SOURCE[0]}"`/build.d"
# Source libraries
local library_path=""
for library_path in "${build_d_directory}/lib"/*.sh
do
if [[ -f "${library_path}" ]]
then
source "${library_path}" || return 1
fi
done
common_log_initialize
common_signal_trap_initialize
declare -r BUILD_D_DIRECTORY="`common_path_absolute "${build_d_directory}"`"
# Source defaults
local defaults_path="${BUILD_D_DIRECTORY}/defaults.sh"
common_log -v 3 "Source defaults"
stack_push COMMON_LOG_PREFIX "Defaults"
source "${defaults_path}" 1>&3 2>&4
common_die_on_error "Failed to source defaults '${defaults_path}'"
common_variable_require DEFAULT_SOURCE_DIRECTORY \
DEFAULT_BUILD_DIRECTORY \
DEFAULT_LOG_VERBOSE \
DEFAULT_SDK_SUPPORTED \
DEFAULT_SDK \
DEFAULT_BUILD_CONFIGURATION \
DEFAULT_PREFIX
stack_pop COMMON_LOG_PREFIX
# Initialize settings
BUILD_SOURCE_DIRECTORY="${DEFAULT_SOURCE_DIRECTORY}"
BUILD_BUILD_DIRECTORY="${DEFAULT_BUILD_DIRECTORY}"
common_log_set_verbose "${DEFAULT_LOG_VERBOSE}"
# Parse options
local -a options=()
common_getopt options "h,help,c,clean,v:,verbose:,s:,source-directory:,b:,build-directory:,t:,target:,a:,action:" "${@}"
common_die_on_error "${options[@]}"
set -- "${options[@]}"
local -i help=0
local -i clean=0
local verbose=2
local target_name=""
local action="build"
while [[ ${#} -gt 0 ]]
do
case "${1}" in
--)
shift
break
;;
-h|--help)
help=1
shift
;;
-c|--clean)
clean=1
shift
;;
-v|--verbose)
verbose="${2}"
shift 2
;;
-s|--source-directory)
BUILD_SOURCE_DIRECTORY="`common_path_absolute "${2}"`"
shift 2
;;
-b|--build-directory)
BUILD_BUILD_DIRECTORY="`common_path_absolute "${2}"`"
shift 2
;;
-t|--target)
target_name="${2}"
shift 2
;;
-a|--action)
action="${2}"
shift 2
;;
esac
done
if ! math_is_integer "${verbose}" || [[ ${verbose} -lt 1 ]]
then
common_die "Verbosity must be a positive integer"
fi
common_log_set_verbose "${verbose}"
common_log_variable ${!DEFAULT_@} \
BUILD_SOURCE_DIRECTORY \
BUILD_BUILD_DIRECTORY
# Find Xcode installations
xcode_find
if [[ ${#XCODE_INSTALLED[@]} -eq 0 ]]
then
common_die "No version of Xcode found"
fi
if [[ ${#XCODE_SDK_INSTALLED} -eq 0 ]]
then
common_die "No supported macOS SDK installed"
fi
# Check settings
if [[ ! -e "${BUILD_SOURCE_DIRECTORY}" ]]
then
common_warn "Source directory '${BUILD_SOURCE_DIRECTORY}' does not exist"
fi
if [[ -z "${DEFAULT_SDK}" ]] || ! xcode_sdk_is_installed "${DEFAULT_SDK}"
then
if common_variable_is_readonly DEFAULT_SDK
then
common_die "Default macOS SDK not available"
else
local macos_version="`macos_get_version`"
function build_main_default_sdk
{
if [[ -z "${DEFAULT_SDK}" ]]
then
DEFAULT_SDK="${1}"
else
version_compare "${1}" "${macos_version}"
if (( ${?} == 2 ))
then
return 1
else
DEFAULT_SDK="${1}"
fi
fi
}
DEFAULT_SDK=""
array_foreach XCODE_SDK_INSTALLED build_main_default_sdk
unset build_main_default_sdk
common_assert "[[ -n `string_escape "${DEFAULT_SDK}"` ]]"
common_warn "Falling back to macOS ${DEFAULT_SDK} SDK as default SDK"
fi
fi
local variable=""
for variable in BUILD_SOURCE_DIRECTORY BUILD_BUILD_DIRECTORY ${!DEFAULT_@}
do
readonly ${variable}
done
# Source extensions
local extension_path=""
for extension_path in "${BUILD_D_DIRECTORY}/extensions"/*.sh
do
if [[ -f "${library_path}" ]]
then
local extension_basename="`basename "${extension_path}"`"
local extension_name="${extension_basename%.*}"
common_log -v 3 "Source extension ${extension_name}"
stack_push COMMON_LOG_PREFIX "E:${extension_name}"
source "${extension_path}" 1>&3 2>&4
common_die_on_error "Failed to source extension '${extension_path}'"
stack_pop COMMON_LOG_PREFIX
fi
done
# Invoke target action
pushd "${BUILD_SOURCE_DIRECTORY}" > /dev/null 2>&1
common_warn_on_error "Source directory '${BUILD_SOURCE_DIRECTORY}' does not exist"
if (( help != 0 ))
then
if [[ -n "${target_name}" ]]
then
action="help"
else
build_help
fi
elif (( clean != 0 ))
then
if [[ -n "${target_name}" ]]
then
action="clean"
else
build_clean
fi
elif [[ -z "${target_name}" ]]
then
common_die "No target specified"
fi
if [[ -n "${target_name}" ]]
then
build_target_invoke "${target_name}" "${action}" "${@}"
common_die_on_error "Action '${action}' of target '${target_name}' failed"
fi
popd > /dev/null 2>&1
return 0
}
build_main "${@}"