429 lines
12 KiB
Bash
Executable File
429 lines
12 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
## INIT
|
|
|
|
# Get script directory
|
|
script_dir="$(cd "$(dirname "$0")" && pwd)"
|
|
|
|
# Change working directory to script directory
|
|
cd $script_dir
|
|
|
|
# Set up log file
|
|
log_file="$script_dir/build.log"
|
|
|
|
rm -f $log_file
|
|
|
|
## FUNCTIONS
|
|
|
|
# Function to print usage instructions
|
|
help() {
|
|
echo "Usage: $0 [options]"
|
|
echo "Options:"
|
|
echo " -h, --help Print this help and exit"
|
|
echo " -i Input project name (required)"
|
|
echo " -g Generated project name (default: <input-project-name>.Generated)"
|
|
echo " -o Output folder name (default: libs)"
|
|
echo " -y Assume yes to all prompts"
|
|
echo " --ndk Android NDK path (default: ANDROID_NDK_HOME environment variable)"
|
|
echo " --no-android Disable Android build (default: false)"
|
|
echo " --no-ios Disable iOS build (default: false)"
|
|
echo " --input-spec Input project .NET spec (default: net8.0)"
|
|
echo " --output-spec Output project .NET spec (default: net8.0)"
|
|
echo " --flutter Generate flutter project"
|
|
}
|
|
|
|
# Function to log a message to the console and log file
|
|
log() {
|
|
echo "$1"
|
|
echo "$1" >>$log_file
|
|
}
|
|
|
|
# Function to run a command and log the output
|
|
run() {
|
|
eval $1 2>&1 | tee -a $log_file
|
|
}
|
|
|
|
# Function to check if a command exists
|
|
command_exists() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
# Function to replace INPUT_PROJECT_NAME and GENERATED_PROJECT_NAME
|
|
# by the actual project names in the passed file
|
|
replace_project_names() {
|
|
sed -i '' "s/INPUT_PROJECT_NAME/$input_project_name/g" $1
|
|
sed -i '' "s/GENERATED_PROJECT_NAME/$generated_project_name/g" $1
|
|
sed -i '' "s/INPUT_NET_SPEC/$input_project_net_spec/g" $1
|
|
sed -i '' "s/OUTPUT_NET_SPEC/$output_project_net_spec/g" $1
|
|
}
|
|
|
|
# Function to ask for confirmation before continuing
|
|
# $1: message
|
|
ask_confirmation() {
|
|
if [ "$assume_yes" = true ]; then
|
|
return
|
|
fi
|
|
read -p "$1 (y/n) " -n 1 -r
|
|
echo
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# Generate project
|
|
generate_project() {
|
|
cd $script_dir
|
|
|
|
# Copy template beyondnetgen.*.config.json
|
|
cp template.beyondnetgen.android.config.json beyondnetgen.android.config.json
|
|
replace_project_names beyondnetgen.android.config.json
|
|
|
|
cp template.beyondnetgen.ios.config.json beyondnetgen.ios.config.json
|
|
replace_project_names beyondnetgen.ios.config.json
|
|
|
|
# Generate project
|
|
log "Generating project"
|
|
run "beyondnetgen beyondnetgen.android.config.json"
|
|
}
|
|
|
|
# Generic function to build a project
|
|
build_project() {
|
|
local platform="$1"
|
|
local config_file="$2"
|
|
local template_csproj="$3"
|
|
local output_dir="$4"
|
|
local library_extension="$5"
|
|
local abis=("${!6}")
|
|
|
|
cd "$script_dir"
|
|
|
|
# Copy template config file
|
|
cp "$config_file" "beyondnetgen.$platform.config.json"
|
|
replace_project_names "beyondnetgen.$platform.config.json"
|
|
|
|
# Generate project
|
|
log "Generating $platform project"
|
|
run "beyondnetgen beyondnetgen.$platform.config.json"
|
|
|
|
# Copy template csproj
|
|
cp "$template_csproj" "$generated_project_dir/$generated_project_name.csproj"
|
|
replace_project_names "$generated_project_dir/$generated_project_name.csproj"
|
|
|
|
cd "$generated_project_dir"
|
|
|
|
# For each .dll in external folder add it as a reference in the generated project
|
|
search_dir="$script_dir/external"
|
|
for entry in "$search_dir"/*; do
|
|
dll_name=$(basename "$entry")
|
|
log "Adding reference to $dll_name"
|
|
# Add reference to the generated project by editing the csproj file
|
|
# Search for the line <!-- ADD REFERENCES HERE (DO NOT DELETE THIS)-->
|
|
# and add a reference to the dll below it
|
|
sed -i '' "/<!-- ADD REFERENCES HERE (DO NOT DELETE THIS)-->/a \\
|
|
<Reference Include=\"$entry\" />\\
|
|
" "$generated_project_dir/$generated_project_name.csproj"
|
|
done
|
|
|
|
if [ "$platform" == "android" ]; then
|
|
cp $script_dir/android_fake_clang.* "$generated_project_dir/"
|
|
fi
|
|
|
|
# Build for each architecture
|
|
for arch in "${abis[@]}"; do
|
|
log "Building $platform library for $arch"
|
|
|
|
run "dotnet publish -r $arch -v normal -c Release -p:DisableUnsupportedError=true -p:PublishAotUsingRuntimePack=true -p:RemoveSections=true -p:AllowUnsafeBlocks=true $generated_project_name.csproj"
|
|
|
|
# Copy the generated library to the output directory
|
|
mkdir -p "$output_dir/$arch"
|
|
cp $generated_project_dir/bin/Release/$output_project_net_spec/$arch/native/$generated_project_name.$library_extension $output_dir/$arch/$input_project_name.$library_extension
|
|
if [ "$platform" == "ios" ]; then
|
|
cd $output_dir/$arch
|
|
install_name_tool -id "$(pwd)/"$input_project_name.$library_extension"" $input_project_name.$library_extension
|
|
cd -
|
|
fi
|
|
done
|
|
|
|
# Copy the generated headers to the output directory
|
|
log "Copying header to output directory"
|
|
cp "$generated_project_dir/Generated.h" "$output_dir/$input_project_name.h"
|
|
}
|
|
|
|
# Definition of specific parameters for each platform
|
|
android_config_file="template.beyondnetgen.android.config.json"
|
|
ios_config_file="template.beyondnetgen.ios.config.json"
|
|
android_template_csproj="template.android.csproj"
|
|
ios_template_csproj="template.ios.csproj"
|
|
ios_library_extension="dylib"
|
|
android_library_extension="so"
|
|
|
|
# Definition of architectures for each platform
|
|
android_abis=("linux-bionic-arm64" "linux-bionic-x64")
|
|
ios_abis=( "osx-x64" "osx-arm64" "ios-arm64" "iossimulator-arm64" "iossimulator-x64")
|
|
|
|
# Calling the generic function to build the Android project
|
|
build_android() {
|
|
build_project "android" "$android_config_file" "$android_template_csproj" "$output_dir" "$android_library_extension" android_abis[@]
|
|
}
|
|
|
|
# Calling the generic function to build the iOS project
|
|
build_ios() {
|
|
build_project "ios" "$ios_config_file" "$ios_template_csproj" "$output_dir" "$ios_library_extension" ios_abis[@]
|
|
}
|
|
|
|
generate_flutter() {
|
|
cd $script_dir
|
|
|
|
# From input_project_dir generate a flutter project name
|
|
flutter_project_name="$input_project_name.Flutter"
|
|
# Dart project name is the same as flutter project name but in snake case (remove dots and capitalize each word)
|
|
dart_project_name=$(echo $flutter_project_name | sed -E 's/([A-Z])/_\1/g' | sed -E 's/^_//g' | sed -E 's/\.//g' | tr '[:upper:]' '[:lower:]')
|
|
|
|
# If flutter_project_name already exists, ask for confirmation before continuing
|
|
if [ -d "$flutter_project_name" ]; then
|
|
ask_confirmation "Flutter project $flutter_project_name already exists. Continue?"
|
|
rm -rf $flutter_project_name
|
|
fi
|
|
|
|
# Create flutter project
|
|
log "Creating flutter project in $flutter_project_name"
|
|
run "flutter create -e --platforms android,ios --project-name $dart_project_name $flutter_project_name"
|
|
|
|
# Copy generated files to flutter project
|
|
log "Copying generated files to flutter project"
|
|
mkdir -p $flutter_project_name/android/app/src/main/jniLibs
|
|
cp $generated_project_dir/Generated.h $flutter_project_name/Generated.h
|
|
cp -r libs/linux* $flutter_project_name/android/app/src/main/jniLibs/
|
|
cp ffigen.yaml $flutter_project_name/ffigen.yaml
|
|
|
|
cd $flutter_project_name
|
|
run "flutter pub add -d ffigen && flutter pub get && dart run ffigen --config ffigen.yaml"
|
|
}
|
|
|
|
## ARGUMENTS
|
|
|
|
# Set default values
|
|
WANT_TO_BUILD_ANDROID=true
|
|
WANT_TO_BUILD_IOS=true
|
|
ONLY_GENERATE=false
|
|
WANT_TO_GENERATE_FLUTTER=false
|
|
|
|
# Check for arguments
|
|
if [ $# -eq 0 ]; then
|
|
log "No arguments supplied"
|
|
help
|
|
exit 1
|
|
fi
|
|
|
|
# Parse arguments
|
|
while [ "$1" != "" ]; do
|
|
case $1 in
|
|
-h | --help)
|
|
help
|
|
exit 0
|
|
;;
|
|
-i)
|
|
shift
|
|
input_project_name=$1
|
|
;;
|
|
-g)
|
|
shift
|
|
generated_project_name=$1
|
|
;;
|
|
-o)
|
|
shift
|
|
output=$1
|
|
;;
|
|
-y)
|
|
assume_yes=true
|
|
;;
|
|
--ndk)
|
|
shift
|
|
export ANDROID_NDK_HOME=$1
|
|
;;
|
|
--input-spec)
|
|
shift
|
|
input_project_net_spec=$1
|
|
;;
|
|
--output-spec)
|
|
shift
|
|
output_project_net_spec=$1
|
|
;;
|
|
--no-android)
|
|
WANT_TO_BUILD_ANDROID=false
|
|
;;
|
|
--no-ios)
|
|
WANT_TO_BUILD_IOS=false
|
|
;;
|
|
--flutter)
|
|
WANT_TO_GENERATE_FLUTTER=true
|
|
;;
|
|
*)
|
|
log "Unknown argument: $1"
|
|
help
|
|
exit 1
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# Check for required arguments
|
|
if [ -z "$input_project_name" ]; then
|
|
log "Input project name is required"
|
|
help
|
|
exit 1
|
|
fi
|
|
|
|
# Set default values
|
|
if [ -z "$generated_project_name" ]; then
|
|
generated_project_name="$input_project_name.Generated"
|
|
fi
|
|
|
|
if [ -z "$input_project_net_spec" ]; then
|
|
input_project_net_spec="net8.0"
|
|
fi
|
|
|
|
if [ -z "$output_project_net_spec" ]; then
|
|
output_project_net_spec="net8.0"
|
|
fi
|
|
|
|
if [ -z "$output" ]; then
|
|
output="libs"
|
|
fi
|
|
|
|
input_project_dir="$script_dir/$input_project_name"
|
|
generated_project_dir="$script_dir/$generated_project_name"
|
|
output_dir="$script_dir/$output"
|
|
|
|
## PREREQUISITES CHECK
|
|
|
|
# Check for bash >= 4.0
|
|
if [ "${BASH_VERSINFO:-0}" -lt 4 ]; then
|
|
log "bash >= 4.0 is required. Aborting."
|
|
exit 1
|
|
fi
|
|
|
|
# Check for dotnet
|
|
command_exists dotnet || {
|
|
log "dotnet is required but it's not installed or not in PATH. Aborting."
|
|
exit 1
|
|
}
|
|
|
|
# Check if dotnet is in version 8.0 or higher
|
|
dotnet_version=$(dotnet --version)
|
|
|
|
if [[ $dotnet_version =~ ^8\. ]]; then
|
|
log "dotnet version $dotnet_version is supported"
|
|
else
|
|
log "dotnet version $dotnet_version is not supported. Aborting."
|
|
exit 1
|
|
fi
|
|
|
|
# Check for beyondnetgen
|
|
command_exists beyondnetgen || {
|
|
log "beyondnetgen is required but it's not installed or not in PATH. Aborting."
|
|
exit 1
|
|
}
|
|
|
|
# Check if host is macos, if so, check for xcode, and set BUILD_IOS to true
|
|
ostype=$(uname -s)
|
|
log "Host OS: $ostype"
|
|
if [ "$ostype" == "Darwin" ]; then
|
|
if [ "$WANT_TO_BUILD_IOS" = false ]; then
|
|
log "Disabling iOS build."
|
|
BUILD_IOS=false
|
|
else
|
|
command_exists xcodebuild || {
|
|
log "Xcode is not installed or not in PATH. Disabling iOS build."
|
|
BUILD_IOS=false
|
|
}
|
|
|
|
log "Xcode detected. Enabling iOS build."
|
|
BUILD_IOS=true
|
|
fi
|
|
else
|
|
BUILD_IOS=false
|
|
fi
|
|
|
|
# Check for ANDROID_NDK_HOME
|
|
if [ "$ANDROID_NDK_HOME" ] && [ "$WANT_TO_BUILD_ANDROID" = true ]; then
|
|
log "ANDROID_NDK_HOME is set to $ANDROID_NDK_HOME. Enabling Android build."
|
|
BUILD_ANDROID=true
|
|
else
|
|
BUILD_ANDROID=false
|
|
if [ -z "$ANDROID_NDK_HOME" ]; then
|
|
log "ANDROID_NDK_HOME is not set. Disabling Android build."
|
|
else
|
|
log "Disabling Android build."
|
|
fi
|
|
fi
|
|
|
|
# Check if BUILD_IOS or BUILD_ANDROID is true
|
|
if [ "$BUILD_IOS" = false ] && [ "$BUILD_ANDROID" = false ]; then
|
|
log "Neither iOS nor Android build is enabled."
|
|
log "Only generating project."
|
|
ONLY_GENERATE=true
|
|
fi
|
|
|
|
## CONFIG
|
|
|
|
cd $script_dir
|
|
|
|
# Copy template beyondnetgen.*.config.json
|
|
cp template.beyondnetgen.android.config.json beyondnetgen.android.config.json
|
|
replace_project_names beyondnetgen.android.config.json
|
|
|
|
cp template.beyondnetgen.ios.config.json beyondnetgen.ios.config.json
|
|
replace_project_names beyondnetgen.ios.config.json
|
|
|
|
# Check if output_dir exists, if not, create it
|
|
if [ ! -d "$output_dir" ]; then
|
|
log "Creating output directory $output_dir"
|
|
mkdir -p $output_dir
|
|
fi
|
|
|
|
## BUILD
|
|
|
|
# Clean previous build
|
|
log "Cleaning previous build..."
|
|
|
|
# Ask for confirmation
|
|
ask_confirmation "Will delete: $generated_project_dir, $output_dir, $input_project_dir/obj $input_project_dir/bin. Continue?"
|
|
|
|
rm -r $generated_project_dir
|
|
rm -r "$input_project_dir/obj"
|
|
rm -r "$input_project_dir/bin"
|
|
|
|
# Build input project
|
|
log "Building input project"
|
|
cd $input_project_dir
|
|
run "dotnet publish -v normal -c Release"
|
|
|
|
# Only generate project
|
|
if [ "$ONLY_GENERATE" = true ]; then
|
|
generate_project
|
|
fi
|
|
|
|
# Build Android libraries
|
|
if [ "$BUILD_ANDROID" = true ]; then
|
|
build_android
|
|
fi
|
|
|
|
# Build iOS libraries
|
|
if [ "$BUILD_IOS" = true ]; then
|
|
build_ios
|
|
fi
|
|
|
|
# Generate flutter project
|
|
if [ "$WANT_TO_GENERATE_FLUTTER" = true ]; then
|
|
generate_flutter
|
|
fi
|
|
|
|
# Check last command exit code
|
|
if [ $? -ne 0 ]; then
|
|
log "Build failed. See $log_file for details."
|
|
exit 1
|
|
else
|
|
log "Finished building. See $log_file for details."
|
|
fi
|