From daf97d40a80272269058eb1411c8b31c6efddd86 Mon Sep 17 00:00:00 2001 From: David Capello Date: Mon, 28 Oct 2024 18:49:43 -0300 Subject: [PATCH] Add build scripts --- .gitignore | 1 + build.cmd | 14 ++ build.ps1 | 15 ++ build.sh | 438 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 468 insertions(+) create mode 100644 build.cmd create mode 100644 build.ps1 create mode 100755 build.sh diff --git a/.gitignore b/.gitignore index 07057bdcc3..85a86a640a 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ .vs tests/_test* build +.build CMakeSettings.json diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000000..72c42e67dd --- /dev/null +++ b/build.cmd @@ -0,0 +1,14 @@ +@echo off + +rem If cl.exe is not available, we try to run the vcvars64.bat +where cl.exe >nul 2>nul +if %errorlevel%==1 ( + @call "%ProgramFiles%\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" +) + +rem Add an extra path element which will be invalidated by Git Bash. +rem In this way we avoid invalidating the PATH location where cl.exe is. +set PATH=.;%PATH% + +powershell -ExecutionPolicy Bypass -File .\build.ps1 %* +pause diff --git a/build.ps1 b/build.ps1 new file mode 100644 index 0000000000..9c47f3f1fe --- /dev/null +++ b/build.ps1 @@ -0,0 +1,15 @@ +if (Test-Path "$env:ProgramFiles\Git\bin") { + $env:Path = "$env:ProgramFiles\Git\bin;$env:ProgramFiles\Git\mingw64\bin" + $env:Path +} +elseif (Test-Path "$env:ProgramFiles(x86)\Git\bin") { + $env:Path = "$env:ProgramFiles(x86)\Git\bin;$env:ProgramFiles(x86)\Git\mingw64\bin;" + $env:Path +} + +try { + sh.exe build.sh $args +} +catch { + echo "bash.exe doesn't found" + echo "`r`nInstall Git Bash from:" + echo "`r`n https://gitforwindows.org/`r`n" +} diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000..90d72ba14f --- /dev/null +++ b/build.sh @@ -0,0 +1,438 @@ +#! /bin/bash +# +# This is a script to help users and developers to build Aseprite. +# Usage: +# +# ./build.sh +# ./build.sh --reset +# ./build.sh --auto [--norun] +# +# If you run this script without parameters, you will be able to +# follows the instructions and a configuration will be stored in a +# ".build" directory. +# +# Options: +# +# --reset Deletes the configuration and you can start over +# --auto Tries to build the default user configuration (release mode) +# --norun Doesn't auto-run when using --auto +# + +echo "======================= BUILD ASEPRITE HELPER ========================" + +# Check that we are running the script from the Aseprite clone directory. +pwd=$(pwd) +if [ ! -f "$pwd/README.md" ] ; then + echo "" + echo "Run build script from the Aseprite directory" + exit 1 +fi + +# Use "./build.sh --reset" to reset all the configuration (deletes +# .build directory). +if [ "$1" == "--reset" ] ; then + echo "" + echo "Resetting $pwd/.build directory" + if [ -f "$pwd/.build/builds_dir" ] ; then rm $pwd/.build/builds_dir ; fi + if [ -f "$pwd/.build/log" ] ; then rm $pwd/.build/log ; fi + if [ -f "$pwd/.build/main_skia_dir" ] ; then rm $pwd/.build/main_skia_dir ; fi + if [ -f "$pwd/.build/beta_skia_dir" ] ; then rm $pwd/.build/beta_skia_dir ; fi + if [ -f "$pwd/.build/userkind" ] ; then rm $pwd/.build/userkind ; fi + if [ -d "$pwd/.build" ] ; then rmdir $pwd/.build ; fi + echo "Done" + exit 0 +fi + +# Use "./build.sh --auto" to build the user configuration without +# questions (downloading Skia/release mode). +auto= +if [ "$1" == "--auto" ] ; then + shift + auto=1 +fi +norun= +if [ "$1" == "--norun" ] ; then + shift + norun=1 +fi + +# Platform. +if [[ "$(uname)" =~ "MINGW32" ]] || [[ "$(uname)" =~ "MINGW64" ]] || [[ "$(uname)" =~ "MSYS_NT-10.0" ]] ; then + is_win=1 + cpu=x64 + + if ! cl.exe >/dev/null 2>/dev/null ; then + echo "" + echo "MSVC compiler (cl.exe) not found in PATH" + echo "" + echo " PATH=$PATH" + echo "" + exit 1 + fi +elif [[ "$(uname)" == "Linux" ]] ; then + is_linux=1 + cpu=x64 +elif [[ "$(uname)" =~ "Darwin" ]] ; then + is_macos=1 + if [[ $(uname -m) == "arm64" ]]; then + cpu=arm64 + else + cpu=x64 + fi +fi + +# Check utilities. +if ! cmake --version >/dev/null ; then + echo "" + echo "cmake utility is not available. You can get cmake from:" + echo "" + echo " https://cmake.org/download/" + echo "" + exit 1 +fi +if ! ninja --version >/dev/null ; then + echo "" + echo "ninja utility is not available. You can get ninja from:" + echo "" + echo " https://github.com/ninja-build/ninja/releases" + echo "" + exit 1 +fi + +# Create the directory to store the configuration. +if [ ! -d "$pwd/.build" ] ; then + mkdir "$pwd/.build" +fi + +# Kind of user (User or Developer). +# For users we simplify the process (no multiple builds), for +# developers we have more options (debug mode, etc.). +if [ ! -f "$pwd/.build/userkind" ] ; then + if [ $auto ] ; then + echo "user" > $pwd/.build/userkind + else + echo "" + echo "Select what kind of user you are (press U or D keys):" + echo "" + echo " [U]ser: give a try to Aseprite" + echo " [D]eveloper: develop/modify Aseprite" + echo "" + read -sN 1 -p "[U/D]? " + echo "" + if [[ "$REPLY" == "d" || "$REPLY" == "D" ]] ; then + echo "developer" > $pwd/.build/userkind + elif [[ "$REPLY" == "u" || "$REPLY" == "U" ]] ; then + echo "user" > $pwd/.build/userkind + else + echo "Use U or D keys to select kind of user/build process" + exit 1 + fi + fi +fi + +userkind=$(echo -n $(cat $pwd/.build/userkind)) +if [ "$userkind" == "developer" ] ; then + echo "======================= BUILDING FOR DEVELOPER =======================" +else + echo "========================= BUILDING FOR USER ==========================" +fi + +# Get the builds_dir location. +if [ ! -f "$pwd/.build/builds_dir" ] ; then + if [ "$userkind" == "developer" ] ; then + # The "builds" folder is a place where all possible combination/builds + # will be stored. If the ASEPRITE_BUILD environment variable is + # defined, that's the directory, in other case for a regular "user" + # the folder will be this same directory where Aseprite was cloned. + if [[ "$ASEPRITE_BUILD" != "" ]] ; then + if [ $is_win ] ; then + builds_dir=$(cygpath "$ASEPRITE_BUILD") + else + builds_dir="$ASEPRITE_BUILD" + fi + + if [ -d "$builds_dir" ] ; then + echo "" + echo "Using ASEPRITE_BUILD environment variable for builds directory." + else + if ! mkdir "$builds_dir" ; then + echo "" + echo "The ASEPRITE_BUILD is defined but we weren't able to create the directory:" + echo "" + echo " ASEPRITE_BUILD=$builds_dir" + echo "" + echo "To solve this issue delete the ASEPRITE_BUILD variable or point it to a valid path." + exit 1 + fi + fi + else + # Default location for developers + builds_dir=$HOME/builds + + echo "" + echo "Select a folder where to leave all builds:" + echo " builds_dir/" + echo " release-x64/..." + echo " debug-x64/..." + echo "" + echo "builds_dir [$builds_dir]? " + read builds_dir_read + if [ "$builds_dir_read" != "" ] ; then + builds_dir="$builds_dir_read" + fi + fi + else + # Default location for users + builds_dir="$pwd" + + echo "" + echo "We'll build Aseprite in $builds_dir/build directory" + fi + echo "$builds_dir" > "$pwd/.build/builds_dir" +fi +# Overwrite $builds_dir variable from the config content. +builds_dir="$(echo -n $(cat $pwd/.build/builds_dir))" + +# List all builds. +builds_list="$(mktemp)" +n=1 +for file in $(ls $builds_dir/*/CMakeCache.txt 2>/dev/null | sort) ; do + if cat "$file" | grep -q "CMAKE_PROJECT_NAME:STATIC=aseprite" ; then + if [ $n -eq 1 ] ; then + echo "-- AVAILABLE BUILDS --" + fi + echo "$file" >> $builds_list + echo "$n. $file" + n=$(($n+1)) + fi +done + +# New build configuration. +build_type=RelWithDebInfo + +# No builds, so this is the first build. +if [[ $n -eq 1 ]] ; then + echo "-- FIRST BUILD --" + if [ "$userkind" == "developer" ] ; then + active_build_dir="$builds_dir/aseprite-release" + else + active_build_dir="$builds_dir/build" + fi + echo "First build directory: $active_build_dir" +else + echo "N. New build (N key)" + read -p "Select an option or number to build? " build_n + + # New build + if [[ "$build_n" == "n" || "$build_n" == "N" ]] ; then + read -p "Select build type [RELEASE/debug]? " + if [[ "${REPLY,,}" == "debug" ]] ; then + build_type=Debug + new_build_name=aseprite-debug + else + build_type=RelWithDebInfo + new_build_name=aseprite-release + fi + + read -p "Select a name [$new_build_name]? " + if [[ "$REPLY" != "" ]] ; then + new_build_name=$REPLY + fi + active_build_dir="$builds_dir/$new_build_name" + else + n=1 + for file in $(cat $builds_list) ; do + if [ "$n" == "$build_n" ] ; then + active_build_dir=$(dirname $file) + build_type=$(cat $active_build_dir/CMakeCache.txt | grep CMAKE_BUILD_TYPE | cut -d "=" -f2) + break + fi + n=$(($n+1)) + done + fi +fi + +if [ "$active_build_dir" == "" ] ; then + echo "No build selected" + exit 1 +fi + +if [ -f "$active_build_dir/CMakeCache.txt" ] ; then + source_dir=$(cat $active_build_dir/CMakeCache.txt | grep aseprite_SOURCE_DIR | cut -d "=" -f2) +else + source_dir="$pwd" +fi +branch_name=$(git --git-dir="$source_dir/.git" rev-parse --abbrev-ref HEAD) + +if [[ "$branch_name" == "main" || "$branch_name" == "beta" ]] ; then + base_branch_name="$branch_name" +else + # Get the origin (or first remote) name + remote=$(git --git-dir="$source_dir/.git" remote | grep origin) + if [ "$remote" == "" ] ; then + remote=$(git --git-dir="$source_dir/.git" remote | head -n1) + fi + + if git --git-dir="$source_dir/.git" branch --contains "$remote/beta" | grep -q "^\* $branch_name\$" ; then + base_branch_name=beta + elif git --git-dir="$source_dir/.git" branch --contains "$remote/main" | grep -q "^\* $branch_name\$" ; then + base_branch_name=main + else + echo "" + echo "Error: Branch $branch_name looks like doesn't belong to main or beta" + echo "" + exit 1 + fi +fi + +echo "=========================== CONFIGURATION ============================" +echo "Build type: $build_type" +echo "Build dir: \"$active_build_dir\"" +echo "Source dir: \"$source_dir\"" +if [ "$branch_name" != "$base_branch_name" ] ; then + echo "Branch name: $base_branch_name > $branch_name" +else + echo "Branch name: $base_branch_name" +fi + +# Required Skia for the base branch. +if [ "$base_branch_name" == "beta" ] ; then + skia_tag=m124-08a5439a6b + file_skia_dir=beta_skia_dir + possible_skia_dir_name=skia-m124 +else + skia_tag=m102-861e4743af + file_skia_dir=main_skia_dir + possible_skia_dir_name=skia +fi + +# Check Skia dependency. +if [ ! -f "$pwd/.build/$file_skia_dir" ] ; then + # Try "C:/deps/skia" or "$HOME/deps/skia" + if [[ $is_win ]] ; then + skia_dir="C:/deps/$possible_skia_dir_name" + else + skia_dir="$HOME/deps/$possible_skia_dir_name" + fi + + if [ ! -d "$skia_dir" ] ; then + echo "" + echo "Skia directory wasn't found." + echo "" + + echo "Select Skia directory to create [$skia_dir]? " + if [ ! $auto ] ; then + read skia_dir_read + if [ "$skia_dir_read" != "" ] ; then + skia_dir="$skia_dir_read" + fi + fi + mkdir -p $skia_dir || exit 1 + fi + echo $skia_dir > "$pwd/.build/$file_skia_dir" +fi +skia_dir=$(echo -n $(cat $pwd/.build/$file_skia_dir)) +if [ ! -d "$skia_dir" ] ; then + mkdir "$skia_dir" +fi + +# Only on Windows we need the Debug version of Skia to compile the +# Debug version of Aseprite. +if [[ $is_win && "$build_type" == "Debug" ]] ; then + skia_library_dir="$skia_dir/out/Debug-x64" +else + skia_library_dir="$skia_dir/out/Release-$cpu" +fi + +# If the library directory is not available, we can try to download +# the pre-built package. +if [ ! -d "$skia_library_dir" ] ; then + echo "" + echo "Skia library wasn't found." + echo "" + if [ ! $auto ] ; then + read -sN 1 -p "Download pre-compiled Skia automatically [Y/n]? " + fi + if [[ $auto || "$REPLY" == "" || "$REPLY" == "y" || "$REPLY" == "Y" ]] ; then + if [[ $is_win && "$build_type" == "Debug" ]] ; then + skia_build=Debug + else + skia_build=Release + fi + + if [ $is_win ] ; then + skia_file=Skia-Windows-$skia_build-$cpu.zip + elif [ $is_macos ] ; then + skia_file=Skia-macOS-$skia_build-$cpu.zip + else + skia_file=Skia-Linux-$skia_build-$cpu-libstdc++.zip + fi + skia_url=https://github.com/aseprite/skia/releases/download/$skia_tag/$skia_file + if [ ! -f "$skia_dir/$skia_file" ] ; then + curl -L -o "$skia_dir/$skia_file" "$skia_url" + fi + if [ ! -d "$skia_library_dir" ] ; then + unzip -n -d "$skia_dir" "$skia_dir/$skia_file" + fi + else + echo "Please follow these instructions to compile Skia manually:" + echo "" + echo " https://github.com/aseprite/skia?tab=readme-ov-file#skia-for-aseprite-and-laf" + echo "" + exit 1 + fi +fi +echo "================================ SKIA ================================" +echo "Skia directory: \"$skia_dir\"" +echo "Skia library directory: \"$skia_library_dir\"" +if [ ! -d "$skia_library_dir" ] ; then + echo " But the Skia library directory wasn't found." + exit 1 +fi + +# Building +echo "=============================== CMAKE ================================" +if [ ! -f "$active_build_dir/ninja.build" ] ; then + echo "" + echo "We are going to run cmake and then build the project." + echo "This will take some minutes." + echo "" + if [ ! $auto ] ; then + read -sN 1 -p "Press any key to continue. " + fi + + if [ $is_macos ] ; then + osx_deployment_target="-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0" + else + osx_deployment_target= + fi + + echo "Configuring Aseprite..." + if ! cmake -B "$active_build_dir" -S "$source_dir" -G Ninja \ + -DCMAKE_BUILD_TYPE=$build_type \ + $osx_deployment_target \ + -DLAF_BACKEND=skia \ + -DSKIA_DIR="$skia_dir" \ + -DSKIA_LIBRARY_DIR="$skia_library_dir" | \ + tee "$pwd/.build/log" ; then + echo "Error running cmake." + exit 1 + fi +fi +echo "============================== BUILDING ==============================" +if ! cmake --build "$active_build_dir" -- aseprite | tee "$pwd/.build/log" ; then + echo "Error building Aseprite." + exit 1 +fi + +echo "================================ DONE ================================" +if [ $is_win ] ; then exe=.exe ; else exe= ; fi +echo "Run Aseprite with the following command:" +echo "" +echo " $active_build_dir/bin/aseprite$exe" +echo "" + +# Run Aseprite in --auto mode +if [[ $auto && ! $norun ]] ; then + $active_build_dir/bin/aseprite$exe +fi