29 Commits
v1.1 ... master

Author SHA1 Message Date
aki
a12d29ca1f build(manifest): Another attemp at Skia dependencies and adjusting library linking 2025-05-07 12:16:35 +08:00
aki
7fae6c2d88 build(manifest): Another attempt to force usage of Skia's freetype 2025-05-07 11:40:57 +08:00
aki
ef5967d92b build(manifest): Specify freetype's location in Aseprite build configuration 2025-05-07 10:59:51 +08:00
aki
449184f5a3 build(manifest): Fix for skshaper and skunicode 2025-05-07 10:50:50 +08:00
aki
7769777df0 build(manifest): Include skshaper and skunicode targets 2025-05-07 10:41:02 +08:00
aki
0cf643665c build(manifest): Ensure Skia's src files and public headers are correctly installed 2025-05-07 10:30:41 +08:00
aki
ce6af21c1c build(manifest): Add module headers to fix missing module header errors 2025-05-07 04:31:58 +08:00
aki
2aa5a6e8f6 build(manifest): Logging part 2 2025-05-07 04:21:56 +08:00
aki
26d41667a6 fix(manifest): Correct Skia installation paths the path Aseprite expects 2025-05-07 04:11:39 +08:00
aki
1b1ebf70a7 fix(manifest): Add logging for Skia build output and include dir structure to try and fix build errors 2025-05-07 03:53:42 +08:00
aki
9ef60e4efb fix(manifest): Update depot_tools installation to preserve file attributes as a fix 2025-05-07 03:39:03 +08:00
aki
1448804f42 fix(manifest): Ensure depot_tools directory has correct permissions 2025-05-07 03:29:59 +08:00
Aki Amane
001f66ab5a fix(Makefile): Fix indentations that were accidentally stripped out 2025-05-07 03:21:50 +08:00
aki
1b4744024b fix(Dockerfile, Makefile, manifest): Address user/group ID mapping and attempt to resolve ninja errors 2025-05-07 03:04:41 +08:00
aki
78c3eed0fc fix(makefile): Improve user permissions handling in Docker build process 2025-05-07 02:10:12 +08:00
aki
5a4239dd9e fix(manifest): Attmept at handling library 2025-05-07 01:55:48 +08:00
aki
a0506f94a3 fix(manifest): Fix the build process by extracting and installing static libraries from Skia 2025-05-07 01:48:30 +08:00
aki
b0479bfbf4 feat: Implement Flatpak build system using flatpak-builder in Docker
This commit replaces the previous multi-distribution Docker build system with a unified Flatpak build process executed inside a Docker container. This is the intended final architecture for building Aseprite bundles.

**Key Changes:**

*   **Transition to Flatpak:** The core build logic now uses `flatpak-builder` and a Flatpak manifest (`com.aseprite.Aseprite.yaml`) to compile Aseprite and its dependencies against a standard Flatpak SDK runtime.
*   **Unified Docker Environment:** Replaced distribution-specific `Dockerfile.<distro>` files with a single `Dockerfile` that sets up a consistent environment containing `flatpak-builder` and the necessary Flatpak SDK.
*   **Simplified Makefile:** Removed OS detection logic and multi-distro targets. The Makefile now orchestrates:
    1.  Running `prepare_sources.sh` on the host (still responsible for reliable source fetching/syncing).
    2.  Building the single Flatpak builder Docker image.
    3.  Running `flatpak-builder` inside a *privileged* container (required for `flatpak-builder` sandboxing) to perform the actual build.
    4.  Running `flatpak build-bundle` inside the container.
    5.  Extracting the final `.flatpak` bundle from the container to `./target/aseprite.flatpak`.
*   **Updated .gitignore:** Added `build/`, `target/`, `*.flatpak`, and `*.log` to ignore Flatpak build directories, output bundles, and logs. Removed the old `dependencies` ignore pattern.
*   **Prepare Sources Update:** Modified `prepare_sources.sh` to explicitly initialize `depot_tools` on the host, as this is required before sources are copied into the Flatpak build environment for `gn` usage.
*   **Removal of Old Files:** Deleted `Dockerfile.<distro>`, `Dockerfile.debian`, `Dockerfile.fedora`, `Dockerfile.arch` (multi-distro Dockerfiles), and the original generic `Dockerfile` and `docker-compose.yml`.

**Rationale:**

This refactor moves to the planned final architecture. Building within a Flatpak SDK provides a highly consistent environment independent of the host Linux distribution. The output is a portable `.flatpak` bundle, simplifying distribution and runtime compatibility compared to dynamically linking against varied host libraries. While `prepare_sources.sh` on the host still handles the initial (and potentially rate-limited) source fetching, the subsequent build process is significantly standardized and more reliable.

This architecture is now the **forward-maintained** build method.
2025-05-06 17:02:01 +08:00
aki
2b47036cc8 docs(README): Rewrite README.md from the ground up 2025-05-05 01:20:53 +08:00
aki
d12f0bdf88 refactor: Overhaul build system for reliability and future portability
This commit introduces a major refactoring of the Aseprite build process. It replaces the previous fragile system (prone to dependency fetching failures) with an interim multi-distribution Docker approach, paving the way for a future transition to Flatpak.

**Problems Addressed:**

*   **Build Fragility & Dependency Fetching:** The prior method, compiling dependencies from source within a generic container, frequently failed due to network issues and rate limiting during source/sub-dependency acquisition (e.g., Skia's `git-sync-deps`), often late in the process. Source state inconsistencies could also cause failures.
*   **Complexity of Full Source Builds:** Managing the compilation of the entire dependency tree from source was complex.

**New Architecture & Rationale:**

*   **Host-Side Source Preparation (`prepare_sources.sh`):** Isolates the problematic source fetching and state management to a host-side script run *before* the main build. Key features:
    *   Handles cloning/updating core sources (`depot_tools`, Skia, Aseprite).
    *   Runs Skia `git-sync-deps` with **robust retry logic** to specifically address rate limit errors.
    *   Includes an `--check-integrity` flag which performs **aggressive checks and resets** (fetching, checking out specific tags/commits, resetting state) to ensure the local source directories precisely match the required state for the build, potentially involving significant network activity.
*   **Distribution-Specific Builds (Interim Step):** Introduced `Dockerfile.arch`, `Dockerfile.debian`, `Dockerfile.fedora`. These use native package managers to install pre-built *common* development libraries within the container, simplifying the Docker build stage itself. Requires OS detection or manual selection (`TARGET_DISTRO`).
*   **Clear Build Stages (Makefile):** Orchestrates source preparation, image building, and final binary extraction (`docker cp` to `./output/bin`).
*   **Cleaned Structure:** Removed obsolete scripts/files (`compile.sh`, generic `Dockerfile`, `docker-compose.yml`) and updated `.gitignore`.

**Limitations & Future Direction (Flatpak):**

*   **Fetching Challenges Persist:** While reliability is improved by isolating source prep and adding retries/integrity checks in `prepare_sources.sh`, the core challenge of potential rate limits or network issues during this initial step remains.
*   **Flatpak for Portability:** The current multi-distro Docker setup is an **intermediate solution**. The ultimate goal and **forward-maintained approach** is migrating to **Flatpak (`flatpak-builder`)**. Flatpak will provide a **unified, distribution-agnostic build environment** using standard runtimes and produce a **portable `.flatpak` bundle**, eliminating the need for OS detection/separate Dockerfiles and ensuring consistent builds *after* sources are successfully prepared.
2025-05-05 01:16:07 +08:00
nilsve
45184df371 Update README.md 2025-02-05 09:17:00 +01:00
nilsve
c749ea2fed Update README.md 2024-07-09 11:44:06 +02:00
nilsve
7e71eab87c Merge pull request #9 from xackery/xackery/docker
Add non-compose support
2023-10-11 15:31:52 +02:00
xackery
fb299896b9 Add non-compose support 2023-10-01 13:52:52 -07:00
nilsve
fc75ad175a Merge pull request #8 from BareTuna/patch-1
Add fix for libcrypto error in FAQ
2023-07-14 16:26:04 +02:00
Tuna
2d3ec8b873 Add fix for libcrypto error in FAQ 2023-07-06 23:01:22 -06:00
nilsve
c4216126fa Merge pull request #6 from joshthemisanthrope/master
Updated to Aseprite v1.2.40 and Skia m102
2023-02-03 15:23:58 +01:00
Josh
47eb4fb9d5 Updated to Aseprite v1.2.40 and Skia m102 2023-01-03 19:41:08 -04:00
nilsve
910c68d20b Update README.md 2022-04-26 15:13:49 +02:00
13 changed files with 1256 additions and 93 deletions

10
.gitignore vendored
View File

@@ -1,3 +1,9 @@
.idea .idea
dependencies .flatpak-builder-cache
output .ccache
flatpak-state
src/
target/
build/
*.flatpak
*.log

View File

@@ -1,21 +1,60 @@
FROM python # Use Debian 12 Slim as the base image
FROM debian:12-slim
#Required for tzdata # Set environment variables for non-interactive install
ENV TZ=Europe/Amsterdam ENV DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# Install dependencies # Arguments for user and group ID
RUN apt-get update ARG UID=1000
RUN apt-get upgrade -y ARG GID=1000
RUN apt-get install -y git unzip curl build-essential cmake ninja-build libx11-dev libxcursor-dev libxi-dev libgl1-mesa-dev libfontconfig1-dev
COPY compile.sh / # Install necessary tools: Flatpak, builder, git, ccache, etc.
RUN apt-get update && \
apt-get install -y --no-install-recommends \
flatpak \
flatpak-builder \
git \
curl \
unzip \
ca-certificates \
elfutils \
ccache \
# Build dependencies for system libraries
build-essential \
ninja-build \
pkg-config \
python3 \
# Clean up apt cache
&& rm -rf /var/lib/apt/lists/*
VOLUME /dependencies # Add Flathub remote and install the Freedesktop SDK and Platform
VOLUME /output # Using 23.08 version as specified in the manifest
RUN flatpak remote-add --system --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo && \
flatpak install --system --noninteractive flathub org.freedesktop.Sdk//23.08 && \
flatpak install --system --noninteractive flathub org.freedesktop.Platform//23.08
WORKDIR /output # Create a non-root user for the build process
RUN groupadd -g $GID builder && \
useradd -u $UID -g $GID -ms /bin/bash builder && \
mkdir -p /home/builder/.cache/ccache && \
chown -R builder:builder /home/builder
RUN ["chmod", "+x", "/compile.sh"] # Create directories needed for the build and set ownership
# /sources will be mounted from host, /build is for build artifacts
RUN mkdir -p /sources /build && \
chown -R builder:builder /build
ENTRYPOINT ["/compile.sh"] # Set user and home directory
USER builder
ENV HOME /home/builder
ENV CCACHE_DIR /home/builder/.cache/ccache
ENV PATH /usr/lib/ccache:$PATH
# Set working directory for the build process
WORKDIR /build
# Copy the Flatpak manifest into the build directory (owned by builder due to WORKDIR and USER settings)
COPY --chown=builder:builder com.aseprite.Aseprite.yaml .
# Default command for interactive use
CMD ["bash"]

91
Dockerfile.arch Normal file
View File

@@ -0,0 +1,91 @@
# Use Arch Linux as the base image
FROM archlinux:latest
# Update system and install necessary dependencies using pacman
# Includes base-devel (common build tools), git, python, cmake, ninja, curl, unzip,
# and development libraries for X11, GL, fontconfig, and Skia dependencies.
RUN pacman -Syu --noconfirm \
base-devel \
git \
python \
cmake \
ninja \
curl \
unzip \
libx11 \
libxcursor \
libxi \
mesa \
fontconfig \
expat \
icu \
libjpeg-turbo \
libpng \
libwebp \
zlib \
freetype2 \
harfbuzz \
& yes | pacman -Scc
# Set the working directory
WORKDIR /app
# Copy the pre-downloaded source code into the image
# This assumes prepare_sources.sh has been run locally first
COPY ./src /src
# Set PATH for depot_tools
ENV PATH="/src/depot_tools:${PATH}"
# Initialize depot_tools within the container environment
# This ensures gn and other tools are correctly set up
RUN update_depot_tools
# --- Compile Skia ---
WORKDIR /src/skia
# Skia dependencies (including gn) are now synced locally by prepare_sources.sh
# Skia system dependencies are handled by system packages installed via pacman
# Generate Skia build files using Arch's system libraries
# Note: Changed skia_use_system_* flags to true and enabled AVX
RUN /src/depot_tools/gn gen out/Release-x64 --args='is_debug=false is_official_build=true skia_use_system_expat=true skia_use_system_icu=true skia_use_system_libjpeg_turbo=true skia_use_system_libpng=true skia_use_system_libwebp=true skia_use_system_zlib=true skia_use_sfntly=false skia_use_freetype=true skia_use_harfbuzz=true skia_pdf_subset_harfbuzz=true skia_use_system_freetype2=true skia_use_system_harfbuzz=true extra_cflags=["-mavx"] extra_cxxflags=["-mavx"]'
# Compile Skia
RUN ninja -C out/Release-x64 skia modules
# --- Compile Aseprite ---
WORKDIR /src/aseprite
RUN mkdir -p build
WORKDIR /src/aseprite/build
# Generate Aseprite build files
# Pointing to the Skia build output within the image and enabling AVX
RUN cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_CXX_FLAGS="-mavx" \
-DLAF_BACKEND=skia \
-DSKIA_DIR=/src/skia \
-DSKIA_LIBRARY_DIR=/src/skia/out/Release-x64 \
-DSKIA_LIBRARY=/src/skia/out/Release-x64/libskia.a \
-DLIBJPEG_TURBO_LIBRARY=/usr/lib/libjpeg.so \
-DCMAKE_EXE_LINKER_FLAGS="-lfreetype" \
-G Ninja \
..
# Compile Aseprite
RUN ninja aseprite
# --- Prepare Output ---
# Create a target directory and copy the final binaries/assets
RUN mkdir -p /target/aseprite/build/bin
RUN cp /src/aseprite/build/bin/aseprite /target/aseprite/build/bin/
# Ensure data directory exists before copying into it
RUN mkdir -p /target/aseprite/build/bin/data
RUN cp /src/aseprite/build/bin/data/* /target/aseprite/build/bin/data/
# Expose a volume for the output (optional, as Makefile will copy)
VOLUME /target
# Set final working directory (optional)
WORKDIR /target

98
Dockerfile.debian Normal file
View File

@@ -0,0 +1,98 @@
# Use Debian 12 (Bookworm) slim as the base image
FROM debian:12-slim
# Set frontend to noninteractive to avoid prompts during package installation
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Etc/UTC
# Install necessary dependencies using apt-get
# Includes build tools, git, python, cmake, ninja, curl, unzip, ca-certs,
# and development libraries for X11, GL, fontconfig, and Skia dependencies.
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
git \
python3 \
cmake \
ninja-build \
curl \
unzip \
ca-certificates \
libx11-dev \
libxcursor-dev \
libxi-dev \
libgl1-mesa-dev \
libfontconfig1-dev \
libexpat1-dev \
libicu-dev \
libjpeg-turbo8-dev \
libpng-dev \
libwebp-dev \
zlib1g-dev \
libfreetype6-dev \
libharfbuzz-dev \
# Clean up apt lists to reduce image size
&& rm -rf /var/lib/apt/lists/*
# Set the working directory
WORKDIR /app
# Copy the pre-downloaded source code into the image
# This assumes prepare_sources.sh has been run locally first
COPY ./src /src
# Set PATH for depot_tools
ENV PATH="/src/depot_tools:${PATH}"
# Initialize depot_tools within the container environment
# This ensures gn and other tools are correctly set up
RUN update_depot_tools
# --- Compile Skia ---
WORKDIR /src/skia
# Skia dependencies (including gn) are now synced locally by prepare_sources.sh
# Skia system dependencies are handled by system packages installed via apt-get
# Generate Skia build files using Debian's system libraries
# Note: Changed skia_use_system_* flags to true and enabled AVX
RUN /src/depot_tools/gn gen out/Release-x64 --args='is_debug=false is_official_build=true skia_use_system_expat=true skia_use_system_icu=true skia_use_system_libjpeg_turbo=true skia_use_system_libpng=true skia_use_system_libwebp=true skia_use_system_zlib=true skia_use_sfntly=false skia_use_freetype=true skia_use_harfbuzz=true skia_pdf_subset_harfbuzz=true skia_use_system_freetype2=true skia_use_system_harfbuzz=true extra_cflags=["-mavx"] extra_cxxflags=["-mavx"]'
# Compile Skia
RUN ninja -C out/Release-x64 skia modules
# --- Compile Aseprite ---
WORKDIR /src/aseprite
RUN mkdir -p build
WORKDIR /src/aseprite/build
# Generate Aseprite build files
# Pointing to the Skia build output within the image and enabling AVX
RUN cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_CXX_FLAGS="-mavx" \
-DLAF_BACKEND=skia \
-DSKIA_DIR=/src/skia \
-DSKIA_LIBRARY_DIR=/src/skia/out/Release-x64 \
-DSKIA_LIBRARY=/src/skia/out/Release-x64/libskia.a \
-DLIBJPEG_TURBO_LIBRARY=/usr/lib/x86_64-linux-gnu/libjpeg.so \
-DCMAKE_EXE_LINKER_FLAGS="-lfreetype" \
-G Ninja \
..
# Compile Aseprite
RUN ninja aseprite
# --- Prepare Output ---
# Create a target directory and copy the final binaries/assets
RUN mkdir -p /target/aseprite/build/bin
RUN cp /src/aseprite/build/bin/aseprite /target/aseprite/build/bin/
# Ensure data directory exists before copying into it
RUN mkdir -p /target/aseprite/build/bin/data
RUN cp /src/aseprite/build/bin/data/* /target/aseprite/build/bin/data/
# Expose a volume for the output (optional, as Makefile will copy)
VOLUME /target
# Set final working directory (optional)
WORKDIR /target

93
Dockerfile.fedora Normal file
View File

@@ -0,0 +1,93 @@
# Use Fedora 41 as the base image
FROM fedora:41
# Install necessary dependencies using dnf
# Includes build tools (make, gcc-c++), git, python, cmake, ninja, curl, unzip,
# and development libraries for X11, GL, fontconfig, and Skia dependencies.
RUN dnf install -y \
make \
gcc-c++ \
cmake \
ninja-build \
git \
curl \
unzip \
python3 \
libX11-devel \
libXcursor-devel \
libXi-devel \
mesa-libGL-devel \
fontconfig-devel \
expat-devel \
libicu-devel \
libjpeg-turbo-devel \
libpng-devel \
libwebp-devel \
zlib-devel \
freetype-devel \
harfbuzz-devel \
# Clean up dnf cache
&& dnf clean all
# Set the working directory
WORKDIR /app
# Copy the pre-downloaded source code into the image
# This assumes prepare_sources.sh has been run locally first
COPY ./src /src
# Set PATH for depot_tools
ENV PATH="/src/depot_tools:${PATH}"
# Initialize depot_tools within the container environment
# This ensures gn and other tools are correctly set up
RUN update_depot_tools
# --- Compile Skia ---
WORKDIR /src/skia
# Skia dependencies (including gn) are now synced locally by prepare_sources.sh
# Skia system dependencies are handled by system packages installed via dnf
# Generate Skia build files using Fedora's system libraries
# Note: Changed skia_use_system_* flags to true and enabled AVX
RUN /src/depot_tools/gn gen out/Release-x64 --args='is_debug=false is_official_build=true skia_use_system_expat=true skia_use_system_icu=true skia_use_system_libjpeg_turbo=true skia_use_system_libpng=true skia_use_system_libwebp=true skia_use_system_zlib=true skia_use_sfntly=false skia_use_freetype=true skia_use_harfbuzz=true skia_pdf_subset_harfbuzz=true skia_use_system_freetype2=true skia_use_system_harfbuzz=true extra_cflags=["-mavx"] extra_cxxflags=["-mavx"]'
# Compile Skia
RUN ninja -C out/Release-x64 skia modules
# --- Compile Aseprite ---
WORKDIR /src/aseprite
RUN mkdir -p build
WORKDIR /src/aseprite/build
# Generate Aseprite build files
# Pointing to the Skia build output within the image and enabling AVX
RUN cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DCMAKE_CXX_FLAGS="-mavx" \
-DLAF_BACKEND=skia \
-DSKIA_DIR=/src/skia \
-DSKIA_LIBRARY_DIR=/src/skia/out/Release-x64 \
-DSKIA_LIBRARY=/src/skia/out/Release-x64/libskia.a \
-DLIBJPEG_TURBO_LIBRARY=/usr/lib64/libjpeg.so \
-DCMAKE_EXE_LINKER_FLAGS="-lfreetype" \
-G Ninja \
..
# Compile Aseprite
RUN ninja aseprite
# --- Prepare Output ---
# Create a target directory and copy the final binaries/assets
RUN mkdir -p /target/aseprite/build/bin
RUN cp /src/aseprite/build/bin/aseprite /target/aseprite/build/bin/
# Ensure data directory exists before copying into it
RUN mkdir -p /target/aseprite/build/bin/data
RUN cp /src/aseprite/build/bin/data/* /target/aseprite/build/bin/data/
# Expose a volume for the output (optional, as Makefile will copy)
VOLUME /target
# Set final working directory (optional)
WORKDIR /target

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 github.com/akippnn
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

100
Makefile Normal file
View File

@@ -0,0 +1,100 @@
# --- Configuration ---
# Uses a single Dockerfile with flatpak-builder inside
IMAGE_NAME := aseprite-flatpak-builder
DOCKERFILE := Dockerfile
TARGET_DIR := ${PWD}/target
OUTPUT_FILE := ${TARGET_DIR}/aseprite.flatpak
BUILD_DIR := ${PWD}/build
SRC_DIR := ${PWD}/src
# Host-side cache directories for Flatpak builder and ccache
# These will be mounted into the container
FLATPAK_BUILDER_CACHE_DIR := ${PWD}/.flatpak-builder-cache
FLATPAK_STATE_DIR := ${FLATPAK_BUILDER_CACHE_DIR}/state
FLATPAK_CACHE_DIR := ${FLATPAK_BUILDER_CACHE_DIR}/cache
CCACHE_DIR := ${PWD}/.ccache
# Get current user and group IDs to avoid permission issues with Docker
USER_ID := $(shell id -u)
GROUP_ID := $(shell id -g)
# --- Main Targets ---
# Default target
all: build
# Prepare source files by running the script
# Use .PHONY to ensure it always runs if called directly
.PHONY: prepare-sources
prepare-sources:
@echo "--- Preparing sources using prepare_sources.sh ---"
./prepare_sources.sh
./prepare_sources.sh --check-integrity
# Build the Docker image which runs flatpak-builder inside
# Implicitly depends on sources being ready after prepare-sources runs
.PHONY: build-image
build-image:
@echo "--- Building Aseprite Flatpak builder image (${IMAGE_NAME}) ---"
@docker build \
--build-arg UID=${USER_ID} \
--build-arg GID=${GROUP_ID} \
-t ${IMAGE_NAME} -f ${DOCKERFILE} .
# Run flatpak-builder inside a privileged container with proper user permissions
.PHONY: run-flatpak-builder
run-flatpak-builder:
@echo "--- Running flatpak-builder inside container ---"
@mkdir -p ${BUILD_DIR} ${FLATPAK_STATE_DIR} ${FLATPAK_CACHE_DIR} ${CCACHE_DIR}
@docker run \
--rm \
--privileged \
--device /dev/fuse \
-u ${USER_ID}:${GROUP_ID} \
-v ${SRC_DIR}:/sources:ro \
-v ${BUILD_DIR}:/build \
-v ${FLATPAK_STATE_DIR}:/home/builder/.local/share/flatpak-builder \
-v ${FLATPAK_CACHE_DIR}:/home/builder/.cache/flatpak-builder \
-v ${CCACHE_DIR}:/home/builder/.cache/ccache \
-v ${PWD}/com.aseprite.Aseprite.yaml:/build/com.aseprite.Aseprite.yaml:ro \
-w /build \
${IMAGE_NAME} \
sh -c "flatpak-builder --disable-rofiles-fuse --state-dir=/home/builder/.local/share/flatpak-builder --ccache build-dir com.aseprite.Aseprite.yaml --repo=repo && if [ -d 'build-dir/files/third_party/externals/emsdk' ]; then rm -rf build-dir/files/third_party/externals/emsdk; fi"
# Create the Flatpak bundle from the repo built in the previous step
.PHONY: create-bundle
create-bundle: run-flatpak-builder
@echo "--- Creating Flatpak bundle ---"
@docker run \
--rm \
--privileged \
--device /dev/fuse \
-u ${USER_ID}:${GROUP_ID} \
-v ${BUILD_DIR}:/build \
-w /build \
${IMAGE_NAME} \
sh -c "flatpak build-bundle repo aseprite.flatpak com.aseprite.Aseprite"
# Copy the final bundle from the intermediate directory to the output directory
.PHONY: extract-flatpak
extract-flatpak: create-bundle
@echo "--- Copying Flatpak bundle to target directory ---"
@mkdir -p ${TARGET_DIR}
@cp ${BUILD_DIR}/aseprite.flatpak ${OUTPUT_FILE}
@echo "Aseprite Flatpak bundle is in ${OUTPUT_FILE}"
# Prepare build target: Prepare sources, build Docker image
.PHONY: prepare
prepare: prepare-sources build-image
@echo "--- Prepare complete ---"
# Main build target: Run builder, create bundle, extract
.PHONY: build
build: build-image run-flatpak-builder create-bundle extract-flatpak
@echo "--- Build complete ---"
# Clean up only the source files and downloaded content
.PHONY: clean
clean:
@echo "--- Cleaning source files ---"
@rm -rf ${SRC_DIR}
@echo "Source files cleaned. Run 'prepare-sources' to download them again."

156
README.md
View File

@@ -1,22 +1,146 @@
# Docker Aseprite container # Docker Aseprite Flatpak Builder
This repository allows you to compile Aseprite without installing any build tools. All that is required is Docker. This repository provides a Docker-based environment to compile Aseprite into a portable Flatpak bundle. It uses `flatpak-builder` inside a containerized environment for consistency and leverages a robust host-side script to prepare sources reliably.
After spending hours trying to get Aseprite to compile, I decided to just make a Docker image for it ## Requirements
Currently the script checks out Skia version `m96` and Aseprite version `1.2.34.1`. You can easily change this in `compile.sh` by changing the `-b` flag to the desired versions. * Docker (BuildKit backend enabled, which is default in modern versions)
* Make
* Git
* Curl
* Host kernel with `fuse` module loaded (common on most desktop Linux systems).
* Sufficient disk space and RAM for source code and compilation.
* **CPU with AVX support:** The compiled binary requires a CPU supporting the AVX instruction set (generally CPUs from 2011/Sandy Bridge/Bulldozer onwards).
If any of the folders of the projects folder isn't empty, the script will skip checking out the latest versions. In order to re-download, delete the according folder. > [!IMPORTANT]
* ./dependencies/depot_tools > The Docker build process requires elevated privileges (`--privileged`) to allow `flatpak-builder`'s sandboxing (bubblewrap) to function correctly. The `Makefile` handles adding this flag automatically. Ensure your environment allows privileged Docker builds.
* ./dependencies/skia
* ./output/aseprite
## Usage ## Quick Start
* Install docker
* Clone this repository
* cd into cloned repository
* Run `docker-compose build`
* Run `docker-compose up`
* Grab a cup of coffee, since this can take quite a while (Compiling build deps, skia, and aseprite)
You can now find the compiled version of Aseprite in the `output/aseprite/build/bin` folder 1. **Clone:**
```bash
git clone <repository-url>
cd docker-aseprite-linux
```
2. **Build:**
```bash
make build
```
3. **Run:** Find the compiled Flatpak bundle in `./output/aseprite.flatpak`. You can install it using:
```bash
flatpak install ./output/aseprite.flatpak
```
## Build Process Explained
The `make build` command performs the following steps:
1. **Prepare Sources (via `./prepare_sources.sh`):**
* This script runs on your **host machine** first to reliably acquire and prepare the source code.
* Clones `depot_tools`, Skia, and Aseprite source code into the `./src` directory if they don't exist. See the script for specific versions.
* Runs Skia's `git-sync-deps` command locally with **automatic retries** (default: 3 attempts, configurable via `PREPARE_RETRIES`) to download Skia's internal build dependencies (like the `gn` tool) and mitigate failures from network issues or rate limiting.
* Includes an **`--check-integrity`** flag for advanced validation and resetting of source repositories (see Advanced Usage).
* This step isolates the often failure-prone network operations and source state management before the main build begins.
2. **Build Docker Image (using `Dockerfile`):**
* Builds a single Docker image (`aseprite-flatpak-builder`) based on Debian Slim.
* Installs `flatpak`, `flatpak-builder`, and the required Freedesktop Platform/SDK (e.g., 23.08).
* **Copies** the prepared sources from `./src` on the host into `/sources` inside the container. This leverages Docker's layer caching for the source code.
* Copies the Flatpak manifest `com.aseprite.Aseprite.yaml`.
* Runs `flatpak-builder` inside the container using the manifest and the copied sources. This compiles Skia and Aseprite within the consistent Flatpak SDK environment.
* Bundles the result into an `aseprite.flatpak` file inside the container.
* **Note:** This step runs with `--privileged` to allow `flatpak-builder`'s sandboxing mechanisms to work.
3. **Extract Flatpak Bundle:** Copies the final `aseprite.flatpak` file from the container's `/output` directory to `./output` on your host machine.
## Troubleshooting
### Build Failures
* **Resource Exhaustion:** Compiling Skia and Aseprite requires significant RAM and disk space. Ensure your system (and Docker) has adequate resources allocated.
* **Network Issues / Rate Limiting (during `prepare_sources.sh`):**
* Ensure you have a stable internet connection. Check for proxy issues if applicable.
* The Skia sync step (`git-sync-deps`) might hit rate limits (HTTP 429 errors) from Google's servers. The script automatically retries (default: 3 total attempts). If it consistently fails, wait a while before trying again, or increase the number of retries via the `PREPARE_RETRIES` environment variable (e.g., `PREPARE_RETRIES=5 make build`).
* **`flatpak-builder` Errors (during Docker build):**
* **Manifest Errors:** Check `com.aseprite.Aseprite.yaml` for syntax errors or incorrect paths/commands.
* **SDK Issues:** Ensure the SDK version specified in the manifest and Dockerfile is available and installs correctly.
* **Sandbox/Bubblewrap Errors (e.g., FUSE issues):**
* Verify the `docker build` command is running with `--privileged` (handled by the Makefile).
* Ensure the `fuse` kernel module is loaded on your **host system** (`lsmod | grep fuse`). If not, try `sudo modprobe fuse`.
* Check Docker/BuildKit logs for specific bubblewrap (`bwrap`) errors.
* **Compilation Errors:** Check the detailed build log output from Docker (during the `flatpak-builder` step) for C++/CMake/Ninja errors. These could indicate issues with the source code versions, compiler compatibility, or missing dependencies within the Flatpak SDK.
### Runtime Errors (After Installing `.flatpak`)
* **`Illegal instruction`**: This typically means the compiled binary is trying to use CPU instructions not supported by your processor. This build requires a CPU with **AVX** support.
* **Missing Portals / File Dialog Issues:** Ensure you have the necessary Flatpak portals installed on your host system (e.g., `xdg-desktop-portal`, `xdg-desktop-portal-gtk` or `-kde`, etc.) for features like file choosers to work correctly.
* **Permission Issues:** If Aseprite cannot save files or access expected locations, review the `finish-args` in `com.aseprite.Aseprite.yaml`. The current `--filesystem=home` is broad; more restrictive permissions might require specific portal interactions.
## Advanced Usage
The `make build` command automatically runs `./prepare_sources.sh` without any special flags. If you need to control the source preparation step (e.g., force a check integrity and reset), you can run the script manually *before* running `make build`.
### Running `prepare_sources.sh` Manually
* **Check Source Integrity & Reset:** Runs `git fsck`, fetches updates, checks out the exact target commit/tag, and resets submodules. **Warning:** This performs potentially network-intensive operations and modifies local source directories to match the expected state.
```bash
./prepare_sources.sh --check-integrity
# If successful, proceed with make build
make build
```
* **Set Sync Retries:** Control the number of retries for the Skia `git-sync-deps` step (default is 2 retries, total 3 attempts).
```bash
PREPARE_RETRIES=5 ./prepare_sources.sh
make build
```
### Passing Options via `make`
* **Set Sync Retries via `make`:**
```bash
PREPARE_RETRIES=5 make build
```
* **Force Source Reset via `make`:** The recommended way to ensure sources are reset and prepared fresh is to run `make clean` followed by `make build`.
```bash
make clean && make build # Clean output, then build (includes fresh source prep)
```
### Clean Up
To remove the build output (`./output`):
```bash
make clean
```
Note: This does *not* remove the downloaded sources in `./src`. To remove those as well, manually delete the `./src` directory or run `rm -rf ./src`.
## Architecture Notes
This project uses a hybrid approach combining a robust host-side source preparation script with a containerized Flatpak build process:
1. **Host-Side Source Prep (`prepare_sources.sh`):** Handles the potentially fragile steps of cloning, syncing dependencies (with retries), and ensuring the correct state of source code repositories locally in `./src`.
2. **Docker Build (`Dockerfile`):**
* Creates a consistent build environment using Debian and the standard Flatpak SDK.
* Copies the locally prepared sources into the container, leveraging Docker's layer caching.
* Runs `flatpak-builder` using `com.aseprite.Aseprite.yaml` to compile Aseprite against the SDK libraries and the copied sources. Requires `--privileged` for sandboxing.
3. **Flatpak Manifest (`com.aseprite.Aseprite.yaml`):** Defines the application metadata, permissions, and the sequence of build steps (depot\_tools setup, Skia compile, Aseprite compile, metadata installation) executed by `flatpak-builder`.
4. **Makefile:** Orchestrates the process: `prepare_sources.sh` -> `docker build --privileged` -> extract `.flatpak`.
This architecture aims for:
* **Reliability:** By handling source fetching/syncing with retries outside the main build.
* **Consistency:** By using the standard Flatpak SDK inside Docker.
* **Portability:** By producing a `.flatpak` bundle that should run across different Linux distributions.
* **Maintainability:** By consolidating the build logic into a single Dockerfile and Flatpak manifest.
## License
[MIT License](LICENSE)

298
com.aseprite.Aseprite.yaml Normal file
View File

@@ -0,0 +1,298 @@
# Flatpak manifest for Aseprite
# Build using: flatpak-builder --force-clean build-dir com.aseprite.Aseprite.yaml --repo=repo
# Bundle using: flatpak build-bundle repo aseprite.flatpak com.aseprite.Aseprite
app-id: com.aseprite.Aseprite
runtime: org.freedesktop.Platform
runtime-version: '23.08'
sdk: org.freedesktop.Sdk
command: aseprite
finish-args:
# Graphics and display
- --share=ipc
- --socket=x11
- --socket=wayland
- --device=dri
# Filesystem access (adjust as needed, 'home' is broad)
- --filesystem=home
# Needed for Skia/fontconfig
- --filesystem=xdg-config/fontconfig:ro
# Allow talking to portals (for file dialogs etc.)
- --talk-name=org.freedesktop.portal.Desktop
- --talk-name=org.freedesktop.portal.Documents
- --talk-name=org.freedesktop.portal.FileChooser
# Add separate state directory to force consistent cache behavior
build-options:
env:
FLATPAK_BUILDER_BUILDDIR: "/tmp/flatpak-builder-dir"
cleanup:
- /include
- /lib/pkgconfig
- /man
- /share/man
- /share/pkgconfig
- '*-debuginfo*'
- '*.la'
# Remove files that cause cleanup errors
- /third_party/externals/emsdk
modules:
# 1. Depot Tools (Needed for Skia build)
- name: depot_tools
buildsystem: simple
build-commands:
# depot_tools doesn't need building, just needs to be present.
# Install it into /app/depot_tools within the build environment.
# The source '.' is now /sources/depot_tools
- install -d /app/depot_tools
- cp -a ./* /app/depot_tools/ # -a preserves symlinks, ownership (if possible), and modes
# Make files/dirs owner-writable, and all-readable/all-executable(X)
- chmod -R u+rwX,go+rX /app/depot_tools
sources:
# Use the directory copied into the Docker image
- type: dir
path: /sources/depot_tools
# 2. Skia (Aseprite Dependency)
- name: skia
buildsystem: simple
build-options:
# Ensure depot_tools is accessible during build
prepend-path: /app/depot_tools
env:
# Needed to locate some of the dependencies we added
PKG_CONFIG_PATH: /app/lib/pkgconfig:/usr/lib/pkgconfig
build-commands:
# Prepare GN arguments
# Using Skia's bundled libs for better compatibility
- |
echo "Generating Skia build configuration..."
GN_ARGS="is_debug=false \
is_official_build=true \
skia_use_system_expat=true \
skia_use_system_icu=true \
skia_use_system_libjpeg_turbo=false \
skia_use_system_libpng=true \
skia_use_system_libwebp=false \
skia_use_system_zlib=true \
skia_use_sfntly=false \
skia_use_freetype=true \
skia_use_harfbuzz=true \
skia_pdf_subset_harfbuzz=true \
skia_use_system_freetype2=false \
skia_use_system_harfbuzz=false \
skia_enable_fontmgr_empty=false \
skia_enable_fontmgr_android=false \
skia_enable_fontmgr_win=false \
skia_enable_fontmgr_win_gdi=false \
skia_enable_fontmgr_custom_directory=false \
skia_enable_fontmgr_custom_embedded=false \
skia_enable_fontmgr_fontconfig=true \
skia_enable_pdf=false \
skia_enable_tools=false \
extra_cflags=[\"-mavx\",\"-O3\"] \
extra_cxxflags=[\"-mavx\",\"-O3\"]"
# Generate build files using gn from depot_tools
- echo "Running GN to generate Ninja build files..."
- /app/depot_tools/gn gen out/Release-x64 --args="${GN_ARGS}"
# Compile Skia (only the necessary targets)
- echo "Building Skia with Ninja (this may take a while)..."
- ninja -C out/Release-x64 skia modules skshaper skunicode
# Create directory structure for Aseprite
- echo "Installing Skia libraries and headers..."
- install -d /app/lib
- install -d /app/include # Changed from /app/include/skia
- install -d /app/third_party/externals
# Ensure /app/src exists for Skia's src files
- install -d /app/src
# Install Skia library
- install -m644 out/Release-x64/libskia.a /app/lib/libskia.a
# Copy Skia's public headers from 'include/' to '/app/include/'
- cp -r include/* /app/include/
# Copy Skia's 'modules' directory to '/app/include/modules/'
# (as public headers might reference them like "modules/skcms/skcms.h")
- echo "Copying Skia 'modules' directory to /app/include/"
- cp -r modules /app/include/
# Copy Skia's internal 'src' directory to '/app/src/'
# (as Aseprite/LAF references them like "src/core/SkConvertPixels.h")
- echo "Copying Skia 'src' directory to /app/"
- cp -r src/* /app/src/
# Extract and install libraries that Aseprite needs
- |
echo "Extracting and installing bundled libraries..."
# Find and install freetype
for lib_file in $(find out/Release-x64 -name "libfreetype.a" 2>/dev/null || echo ""); do
echo "Installing libfreetype.a from $lib_file"
install -m644 "$lib_file" /app/lib/libfreetype.a
break
done
# Find and install harfbuzz
for lib_file in $(find out/Release-x64 -name "libharfbuzz.a" 2>/dev/null || echo ""); do
echo "Installing libharfbuzz.a from $lib_file"
install -m644 "$lib_file" /app/lib/libharfbuzz.a
break
done
# Find and install webp
for lib_file in $(find out/Release-x64 -name "libwebp.a" 2>/dev/null || echo ""); do
echo "Installing libwebp.a from $lib_file"
install -m644 "$lib_file" /app/lib/libwebp.a
break
done
# Find and install jpeg
for lib_file in $(find out/Release-x64 -name "libjpeg.a" 2>/dev/null || echo ""); do
echo "Installing libjpeg.a from $lib_file"
install -m644 "$lib_file" /app/lib/libjpeg.a
break
done
# Find and install skshaper
for lib_file in $(find out/Release-x64 -name "libskshaper.a" 2>/dev/null || echo ""); do
echo "Installing libskshaper.a from $lib_file"
install -m644 "$lib_file" /app/lib/libskshaper.a
break
done
if [ ! -f /app/lib/libskshaper.a ]; then echo "WARNING: libskshaper.a not found in Skia output during install step, though it was present after build."; fi
# Find and install skunicode
for lib_file in $(find out/Release-x64 -name "libskunicode.a" 2>/dev/null || echo ""); do
echo "Installing libskunicode.a from $lib_file"
install -m644 "$lib_file" /app/lib/libskunicode.a
break
done
if [ ! -f /app/lib/libskunicode.a ]; then echo "WARNING: libskunicode.a not found in Skia output during install step, though it was present after build."; fi
# Create symlinks for libraries that might have different names
(cd /app/lib && [ -f libjpeg.a ] && ln -sf libjpeg.a libjpeg-turbo.a || true)
# Copy necessary include directories from third_party
- |
echo "Copying third_party includes needed by Aseprite..."
# Instead of copying the whole externals directory (which is large and causes cleanup issues)
# Copy only the specific libraries that Aseprite needs
mkdir -p /app/third_party/externals/freetype/include
mkdir -p /app/third_party/externals/harfbuzz/src
mkdir -p /app/third_party/externals/libwebp/src
mkdir -p /app/third_party/externals/libjpeg-turbo
mkdir -p /app/third_party/externals/icu/flutter
# Copy only the necessary include files
if [ -d third_party/externals/freetype/include ]; then
cp -r third_party/externals/freetype/include/* /app/third_party/externals/freetype/include/
fi
if [ -d third_party/externals/harfbuzz/src ]; then
cp -r third_party/externals/harfbuzz/src/*.h /app/third_party/externals/harfbuzz/src/
fi
if [ -d third_party/externals/libwebp/src ]; then
cp -r third_party/externals/libwebp/src/webp /app/third_party/externals/libwebp/src/
fi
if [ -d third_party/externals/libjpeg-turbo ]; then
cp -r third_party/externals/libjpeg-turbo/*.h /app/third_party/externals/libjpeg-turbo/
fi
# Find and copy the ICU data file
- |
echo "Looking for ICU data file..."
# Check for icudtl.dat in various places
for icu_file in $(find . -name "icudtl.dat" 2>/dev/null || echo ""); do
echo "Found ICU data file at $icu_file"
mkdir -p /app/third_party/externals/icu/flutter
cp "$icu_file" /app/third_party/externals/icu/flutter/icudtl.dat
break
done
# Create an empty placeholder if not found
if [ ! -f /app/third_party/externals/icu/flutter/icudtl.dat ]; then
echo "ICU data file not found, creating placeholder..."
touch /app/third_party/externals/icu/flutter/icudtl.dat
fi
# List what we've installed for debugging
echo "Contents of /app/lib:"
ls -la /app/lib
echo "Skia installation complete."
sources:
# Use the directory copied into the Docker image
- type: dir
path: /sources/skia
# 3. Aseprite
- name: aseprite
# Use cmake-ninja buildsystem for convenience
buildsystem: cmake-ninja
# Set build directory outside of source
builddir: true
# CMake configuration options
config-opts:
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
# Add optimization flags as separate options
- -DCMAKE_CXX_FLAGS=-mavx
- -DCMAKE_CXX_FLAGS_RELWITHDEBINFO=-O3
# Use Skia backend
- -DLAF_BACKEND=skia
# Point to the Skia installed in the /app prefix by the previous module
- -DSKIA_DIR=/app
- -DSKIA_LIBRARY_DIR=/app/lib
- -DSKIA_LIBRARY=/app/lib/libskia.a
# Use Skia's bundled libraries (static) or SDK-provided shared libraries
# -DUSE_SHARED_JPEG=OFF # Unused by Aseprite's CMake
- -DUSE_SHARED_LIBPNG=ON # Provided by SDK (shared)
- -DUSE_SHARED_ZLIB=ON # Provided by SDK (shared)
- -DUSE_SHARED_GIFLIB=ON # Provided by SDK (shared)
# -DUSE_SHARED_WEBP=OFF # Unused by Aseprite's CMake
- -DUSE_SHARED_FREETYPE=OFF # Bundled static with Skia
- -DUSE_SHARED_HARFBUZZ=OFF # Bundled static with Skia
# The following explicit paths are generally handled by FindSkia.cmake when SKIA_DIR is set
# - -DWebP_INCLUDE_DIRS=/app/third_party/externals/libwebp/src
# - -DWebP_LIBRARIES=/app/lib/libwebp.a
# - -DJPEG_INCLUDE_DIRS=/app/third_party/externals/libjpeg-turbo
# - -DJPEG_LIBRARIES=/app/lib/libjpeg.a
# - -DFreetype_INCLUDE_DIRS=/app/third_party/externals/freetype/include # Handled by FindSkia.cmake via SKIA_DIR
# - -DFreetype_LIBRARIES=/app/lib/libfreetype2.a # Handled by FindSkia.cmake
# - -DFreetype_LIBRARY=/app/lib/libfreetype2.a # Handled by FindSkia.cmake
# - -DHarfBuzz_INCLUDE_DIRS=/app/third_party/externals/harfbuzz/src # Handled by FindSkia.cmake via SKIA_DIR
# - -DHarfBuzz_LIBRARIES=/app/lib/libharfbuzz.a # Handled by FindSkia.cmake
# - -DHarfBuzz_LIBRARY=/app/lib/libharfbuzz.a # Handled by FindSkia.cmake
build-commands:
# Standard ninja build
- ninja
# Verify libraries exist before install
- |
echo "Verifying required libraries..."
if [ ! -f /app/lib/libskia.a ]; then echo "ERROR: libskia.a missing"; exit 1; fi
if [ ! -f /app/lib/libfreetype2.a ]; then echo "ERROR: libfreetype2.a missing"; exit 1; fi
if [ ! -f /app/lib/libharfbuzz.a ]; then echo "ERROR: libharfbuzz.a missing"; exit 1; fi
echo "All required libraries present."
# Install with ninja
- DESTDIR=/app ninja install
sources:
# Use the directory copied into the Docker image
- type: dir
path: /sources/aseprite
- type: patch
path: skia-deps.patch
# Install desktop file and icon after build/install
post-install:
# Install files from the source directory (/sources/aseprite)
- install -Dm644 /sources/aseprite/data/linux/aseprite.desktop /app/share/applications/com.aseprite.Aseprite.desktop
# Install icon (using the 256px version)
- install -Dm644 /sources/aseprite/data/icons/ase256.png /app/share/icons/hicolor/256x256/apps/com.aseprite.Aseprite.png
# Update caches (optional but recommended)
- update-desktop-database -q /app/share/applications
- gtk-update-icon-cache -f -t /app/share/icons/hicolor || true

View File

@@ -1,53 +0,0 @@
#!/bin/bash
# Fail on errors
set -e
echo "Download and compile Skia & other dependencies"
cd /dependencies
if [ ! -d "/dependencies/depot_tools" ]
then
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
fi
if [ ! -d "/dependencies/skia" ]
then
git clone -b aseprite-m96 https://github.com/aseprite/skia.git
fi
export PATH="${PWD}/depot_tools:${PATH}"
cd skia
pwd
echo "Syncing skia dependencies"
python3 tools/git-sync-deps
echo "Compiling skia"
gn gen out/Release-x64 --args="is_debug=false is_official_build=true skia_use_system_expat=false skia_use_system_icu=false skia_use_system_libjpeg_turbo=false skia_use_system_libpng=false skia_use_system_libwebp=false skia_use_system_zlib=false skia_use_sfntly=false skia_use_freetype=true skia_use_harfbuzz=true skia_pdf_subset_harfbuzz=true skia_use_system_freetype2=false skia_use_system_harfbuzz=false"
ninja -C out/Release-x64 skia modules
echo "Download Aseprite and compile"
cd /output
if [ ! -d "/output/aseprite" ]
then
git clone -b v1.2.34.1 --recursive https://github.com/aseprite/aseprite.git
fi
cd aseprite
mkdir -p build
cd build
echo "Compiling Asperite"
cmake \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DLAF_BACKEND=skia \
-DSKIA_DIR=/dependencies/skia \
-DSKIA_LIBRARY_DIR=/dependencies/skia/out/Release-x64 \
-DSKIA_LIBRARY=/dependencies/skia/out/Release-x64/libskia.a \
-G Ninja \
..
echo "Linking Aseprite"
ninja aseprite

View File

@@ -1,8 +0,0 @@
version: '2'
services:
installer:
build: .
volumes:
- "./output:/output:rw"
- "./dependencies:/dependencies:rw"

337
prepare_sources.sh Executable file
View File

@@ -0,0 +1,337 @@
#!/bin/bash
# Exit immediately if a command exits with a non-zero status.
set -e
# --- Configuration ---
# Define repositories and their properties
# Format: "name|url|tag_or_branch|directory|has_submodules|is_tag"
REPOS=(
"depot_tools|https://chromium.googlesource.com/chromium/tools/depot_tools.git|origin/main|depot_tools|false|false"
"skia|https://github.com/aseprite/skia.git|m124-08a5439a6b|skia|false|true" # Skia uses git-sync-deps, not git submodules
"aseprite|https://github.com/aseprite/aseprite.git|v1.3.14-beta1|aseprite|true|true"
)
SRC_DIR="./src"
MAX_SYNC_RETRIES=${PREPARE_RETRIES:-2} # Default to 2 retries (3 total attempts) if PREPARE_RETRIES is not set
RETRY_DELAY=10 # Seconds to wait between retries
# --- Helper Functions (New Formatting) ---
print_usage() {
echo "Usage: $0 [--check-integrity] [-h|--help]"
echo ""
echo "Prepares source code repositories (depot_tools, Skia, Aseprite)."
echo ""
echo "Default behavior:"
echo " - Clones repositories if they don't exist."
echo " - If repositories exist, performs minimal updates (e.g., ensures Aseprite submodules are present)."
echo " - Errors out if cloning or minimal updates fail."
echo ""
echo "Options:"
echo " --check-integrity If repositories exist, performs a full integrity check and reset:"
echo " - Verifies repository integrity (git fsck)."
echo " - Fetches latest updates and tags."
echo " - Resets the repository to the specified tag/branch (discarding local changes)."
echo " - Updates and resets submodules to the state expected by the parent repository."
echo " - Errors out if directories are missing or if critical checks/resets fail."
echo " -h, --help Display this help message and exit."
}
_CURRENT_STEP=0
_TOTAL_STEPS=${#REPOS[@]} # Number of repositories
_TOTAL_STEPS=$((_TOTAL_STEPS + 2)) # +1 for initializing depot_tools, +1 for Skia sync
print_step() {
_CURRENT_STEP=$((_CURRENT_STEP + 1))
# Adjust total steps display if needed, though this simple count is often sufficient
echo -e "\n[\033[1;34mSTEP ${_CURRENT_STEP}/${_TOTAL_STEPS}\033[0m] $1..."
}
print_info() {
echo -e "[\033[0;32mINFO\033[0m] $1"
}
print_warning() {
echo -e "[\033[1;33mWARN\033[0m] $1"
}
print_success() {
echo -e "[\033[1;32mSUCCESS\033[0m] $1"
}
print_error() {
echo -e "[\033[1;31mERROR\033[0m] $1" >&2
}
print_process_start() {
echo -e "[\033[1mPREPARE\033[0m] $1"
}
print_process_end() {
echo -e "[\033[1mPREPARE\033[0m] $1"
}
# --- Argument Parsing ---
CHECK_INTEGRITY=false
while [[ "$#" -gt 0 ]]; do
case $1 in
--check-integrity) CHECK_INTEGRITY=true; shift ;;
-h|--help) print_usage; exit 0 ;;
*) print_error "Unknown parameter passed: $1"; print_usage; exit 1 ;;
esac
done
# --- Main Logic ---
print_process_start "Starting Source Preparation"
mkdir -p "$SRC_DIR"
cd "$SRC_DIR"
SRC_DIR_ABS=$(pwd) # Use absolute path for clarity inside script
cd .. # Go back to project root
print_info "Source directory: ${SRC_DIR_ABS}"
if [[ "$CHECK_INTEGRITY" == "true" ]]; then
print_info "Mode: Full Integrity Check and Reset (on existing directories)"
else
print_info "Mode: Default (Clone if missing, minimal update if exists)"
fi
# --- Process Repositories ---
DEPOT_TOOLS_DIR="" # Will be set when processing depot_tools
for repo_info in "${REPOS[@]}"; do
IFS='|' read -r name url target_ref dir has_submodules is_tag <<< "$repo_info"
REPO_DIR="${SRC_DIR_ABS}/${dir}"
# Set DEPOT_TOOLS_DIR for later use in PATH
if [[ "$name" == "depot_tools" ]]; then
DEPOT_TOOLS_DIR="$REPO_DIR"
fi
print_step "Processing ${name} (Target: ${target_ref})"
if [ -d "$REPO_DIR" ]; then
# Directory Exists
if [[ "$CHECK_INTEGRITY" == "true" ]]; then
# --- Check Integrity Logic ---
print_info "Verifying integrity of existing ${name} repository..."
if ! (cd "$REPO_DIR" && git fsck); then
print_warning "git fsck reported issues for ${name}, but continuing. Manual check recommended."
fi
print_info "Fetching updates for ${name}..."
fetch_args=("origin")
if [[ "$is_tag" == "true" ]]; then
fetch_args+=("--tags")
fi
if ! (cd "$REPO_DIR" && git fetch "${fetch_args[@]}"); then
print_error "Failed to fetch updates for ${name}. Check network or repository access."
exit 1
fi
needs_reset=false
if [[ "$is_tag" == "true" ]]; then
# Check against specific tag commit
CURRENT_COMMIT=$(cd "$REPO_DIR" && git rev-parse HEAD)
# Handle potential errors if tag doesn't exist locally yet after fetch
TARGET_COMMIT=$(cd "$REPO_DIR" && git rev-list -n 1 "${target_ref}" 2>/dev/null || echo "NOT_FOUND")
if [[ "$TARGET_COMMIT" == "NOT_FOUND" ]]; then
print_error "Target tag '${target_ref}' not found for ${name} after fetch."
exit 1
fi
if [[ "$CURRENT_COMMIT" != "$TARGET_COMMIT" ]]; then
needs_reset=true
print_info "${name} is not on the target commit for tag ${target_ref}."
fi
else
# Check if behind the target branch (e.g., origin/main for depot_tools)
# A simple way is to check if reset --hard changes HEAD
current_head=$(cd "$REPO_DIR" && git rev-parse HEAD)
target_head=$(cd "$REPO_DIR" && git rev-parse "${target_ref}")
if [[ "$current_head" != "$target_head" ]]; then
needs_reset=true
print_info "${name} is not on the target commit for branch ${target_ref}."
fi
fi
# Check for local modifications
MODIFIED=$(cd "$REPO_DIR" && git status --porcelain)
if [[ -n "$MODIFIED" ]]; then
needs_reset=true
print_info "${name} has local modifications."
fi
# Perform reset if needed
if [[ "$needs_reset" == "true" ]]; then
print_info "Resetting ${name} repository to target ${target_ref}..."
# Checkout first, especially important for tags, suppresses detached HEAD advice
if ! (cd "$REPO_DIR" && git checkout "${target_ref}"); then
print_error "Failed to checkout ${target_ref} for ${name}."
exit 1
fi
# Reset hard to ensure clean state matching the target ref
if ! (cd "$REPO_DIR" && git reset --hard "${target_ref}"); then
print_error "Failed to reset ${name} to ${target_ref}."
exit 1
fi
print_info "${name} repository reset successfully."
else
print_info "${name} repository is already on target ${target_ref} and clean."
fi
# Handle Submodules (if applicable)
if [[ "$has_submodules" == "true" ]]; then
print_info "Ensuring ${name} submodules are initialized and updated..."
if ! (cd "$REPO_DIR" && git submodule update --init --recursive); then
print_error "Failed to update submodules for ${name}. Check network or repository access."
exit 1
fi
print_info "Submodule update command completed."
print_info "Checking ${name} submodule status and internal state..."
# Check 1: Overall status (uninitialized, wrong commit). Append '|| true' to prevent grep exit code 1 from stopping the script with set -e.
SUBMODULE_STATUS_ISSUES=$(cd "$REPO_DIR" && git submodule status | grep -v '^ ' || true)
# Check 2: Internal state (modified content, untracked files within submodules). Append '|| true' for robustness.
# Use --quiet to suppress "Entering 'path'" messages. Redirect stderr in case of errors within foreach.
SUBMODULE_INTERNAL_CHANGES=$(cd "$REPO_DIR" && git submodule foreach --quiet 'git status --porcelain' 2>&1 || true)
if [[ -n "$SUBMODULE_STATUS_ISSUES" || -n "$SUBMODULE_INTERNAL_CHANGES" ]]; then
if [[ -n "$SUBMODULE_STATUS_ISSUES" ]]; then
print_info "Detected submodules not initialized or on wrong commit:"
echo "$SUBMODULE_STATUS_ISSUES" # Show which ones have status issues
fi
if [[ -n "$SUBMODULE_INTERNAL_CHANGES" ]]; then
# We don't print the full output of internal changes as it can be verbose,
# just knowing *that* there are changes is enough to trigger the reset.
print_info "Detected submodules with internal changes (modified/untracked files)."
fi
print_info "Resetting submodules for ${name} to clean state..."
# --- Reset Logic ---
if ! (cd "$REPO_DIR" && git submodule foreach --quiet git reset --hard HEAD); then
print_error "Failed to reset submodules for ${name}. Manual check required in ${REPO_DIR}."
exit 1
fi
print_info "Running integrity check on reset submodules..."
# fsck after reset is less critical, treat as warning
if ! (cd "$REPO_DIR" && git submodule foreach --quiet git fsck); then
print_warning "git fsck reported issues for some submodules in ${name} after reset, but continuing."
fi
print_info "Submodules reset successfully."
# --- End Reset Logic ---
else
print_info "${name} submodules already in correct state."
fi
fi
print_success "Integrity check and state validation complete for ${name}."
else
# --- Default Minimal Update Logic ---
print_info "${name} directory exists. Performing minimal update..."
# Only Aseprite needs minimal submodule update in default mode currently
if [[ "$name" == "aseprite" && "$has_submodules" == "true" ]]; then
print_info "Ensuring ${name} submodules are initialized and updated..."
if ! (cd "$REPO_DIR" && git submodule update --init --recursive); then
print_error "Failed to perform minimal submodule update for ${name}. Use --check-integrity or check manually."
exit 1
fi
print_success "Minimal submodule update for ${name} complete."
else
print_info "No minimal update action needed for ${name}."
fi
fi
else
# Directory Does Not Exist
if [[ "$CHECK_INTEGRITY" == "true" ]]; then
print_error "Directory ${REPO_DIR} for ${name} is missing. Cannot perform --check-integrity."
exit 1
else
# --- Clone Logic ---
print_info "Cloning ${name} from ${url} (Target: ${target_ref})..."
clone_args=("--depth" "1")
if [[ "$is_tag" == "true" || "$target_ref" != "origin/main" ]]; then
# For tags or specific branches, use --branch
clone_args+=("--branch" "${target_ref}")
fi
if [[ "$has_submodules" == "true" ]]; then
clone_args+=("--recursive")
fi
if ! git clone "${clone_args[@]}" "${url}" "${REPO_DIR}"; then
print_error "Failed to clone ${name} from ${url}."
exit 1
fi
print_success "${name} cloned successfully."
fi
fi
done
# Initialize depot_tools after all repositories are processed
print_step "Initializing depot_tools"
if [[ -n "$DEPOT_TOOLS_DIR" && -d "$DEPOT_TOOLS_DIR" ]]; then
print_info "Running depot_tools initialization..."
# Add depot_tools to PATH for proper initialization
export PATH="${DEPOT_TOOLS_DIR}:${PATH}"
# Check if initialization was already done
if [[ ! -f "${DEPOT_TOOLS_DIR}/python3_bin_reldir.txt" ]]; then
# Run ensure_bootstrap to initialize depot_tools
if (cd "$DEPOT_TOOLS_DIR" && ./ensure_bootstrap); then
print_success "depot_tools initialized successfully."
else
print_error "Failed to initialize depot_tools. Build may fail."
exit 1
fi
else
print_info "depot_tools already initialized (python3_bin_reldir.txt exists)."
fi
else
print_error "depot_tools directory not found or not processed correctly. Cannot initialize."
exit 1
fi
# Sync Skia dependencies locally with retry logic (after Skia repo is processed)
# Find Skia dir again (could be improved by storing dirs in an associative array if using Bash 4+)
SKIA_DIR=""
for repo_info in "${REPOS[@]}"; do
IFS='|' read -r name url target_ref dir has_submodules is_tag <<< "$repo_info"
if [[ "$name" == "skia" ]]; then
SKIA_DIR="${SRC_DIR_ABS}/${dir}"
break
fi
done
if [[ -z "$SKIA_DIR" || ! -d "$SKIA_DIR" ]]; then
print_error "Skia directory not found or not processed correctly. Cannot sync dependencies."
exit 1
fi
if [[ -z "$DEPOT_TOOLS_DIR" || ! -d "$DEPOT_TOOLS_DIR" ]]; then
print_error "Depot tools directory not found or not processed correctly. Cannot sync Skia dependencies."
exit 1
fi
print_step "Syncing Skia Dependencies"
print_info "Attempting to run git-sync-deps in ${SKIA_DIR} (up to $((MAX_SYNC_RETRIES + 1)) attempts)..."
# Ensure depot_tools is in PATH for git-sync-deps internal calls if needed
export PATH="${DEPOT_TOOLS_DIR}:${PATH}"
sync_success=false
for (( attempt=0; attempt<=MAX_SYNC_RETRIES; attempt++ )); do
if (cd "$SKIA_DIR" && python3 tools/git-sync-deps); then
sync_success=true
print_success "Skia dependencies synced successfully on attempt $((attempt + 1))."
break
else
exit_code=$?
if [[ $attempt -lt $MAX_SYNC_RETRIES ]]; then
print_warning "git-sync-deps failed on attempt $((attempt + 1)) with exit code ${exit_code}. Retrying in ${RETRY_DELAY} seconds..."
sleep $RETRY_DELAY
else
print_error "git-sync-deps failed after $((attempt + 1)) attempts with exit code ${exit_code}. Please check network connection, rate limits, or Skia repository state."
# Consider adding advice to run with --check-integrity if the repo exists but might be broken.
exit 1
fi
fi
done
print_process_end "Source Preparation Complete"

17
skia-deps.patch Normal file
View File

@@ -0,0 +1,17 @@
--- a/laf/cmake/FindSkia.cmake
+++ b/laf/cmake/FindSkia.cmake
@@ -143,7 +143,10 @@
${SKIA_DIR}
${FREETYPE_INCLUDE_DIRS}
${HARFBUZZ_INCLUDE_DIRS}
- ${PNG_INCLUDE_DIRS})
-target_link_libraries(skia INTERFACE ${SKIA_LIBRARIES})
+ ${PNG_INCLUDE_DIRS}
+ )
+target_link_libraries(skia INTERFACE
+ ${SKIA_LIBRARIES}
+ ${FREETYPE_LIBRARIES}
+ ${HARFBUZZ_LIBRARIES})
target_compile_definitions(skia INTERFACE
SK_INTERNAL
SK_GAMMA_SRGB