| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,355 @@ | ||
| # Copyright (c) the JPEG XL Project Authors. All rights reserved. | ||
| # | ||
| # Use of this source code is governed by a BSD-style | ||
| # license that can be found in the LICENSE file. | ||
|
|
||
| # Workflow for building the release binaries. | ||
| # | ||
| # This workflow runs as a post-submit step, when pushing to main or the release | ||
| # branches (v*.*.x), and when creating a release in GitHub. | ||
| # | ||
| # In the GitHub release case, in addition to build the release binaries it also | ||
| # uploads the binaries to the given release automatically. | ||
|
|
||
| name: Release build / deploy | ||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| - v*.*.x | ||
| release: | ||
| types: [ published ] | ||
|
|
||
| jobs: | ||
| ubuntu_static_x86_64: | ||
| name: Release linux x86_64 static | ||
| runs-on: [ubuntu-latest] | ||
| steps: | ||
| - name: Install build deps | ||
| run: | | ||
| sudo apt update | ||
| sudo apt install -y \ | ||
| asciidoc \ | ||
| clang \ | ||
| cmake \ | ||
| doxygen \ | ||
| libbrotli-dev \ | ||
| libgdk-pixbuf2.0-dev \ | ||
| libgif-dev \ | ||
| libgtest-dev \ | ||
| libgtk2.0-dev \ | ||
| libjpeg-dev \ | ||
| libopenexr-dev \ | ||
| libpng-dev \ | ||
| libwebp-dev \ | ||
| ninja-build \ | ||
| pkg-config \ | ||
| # | ||
| echo "CC=clang" >> $GITHUB_ENV | ||
| echo "CXX=clang++" >> $GITHUB_ENV | ||
| - name: Checkout the source | ||
| uses: actions/checkout@v2 | ||
| with: | ||
| submodules: true | ||
| fetch-depth: 1 | ||
|
|
||
| - name: Build | ||
| env: | ||
| SKIP_TEST: 1 | ||
| run: | | ||
| ./ci.sh release \ | ||
| -DJPEGXL_DEP_LICENSE_DIR=/usr/share/doc \ | ||
| -DJPEGXL_STATIC=ON \ | ||
| -DBUILD_TESTING=OFF \ | ||
| -DJPEGXL_ENABLE_VIEWERS=OFF \ | ||
| -DJPEGXL_ENABLE_PLUGINS=OFF \ | ||
| -DJPEGXL_ENABLE_OPENEXR=OFF \ | ||
| - name: Package release tarball | ||
| run: | | ||
| cd build | ||
| tar -zcvf ${{ runner.workspace }}/release_file.tar.gz \ | ||
| LICENSE* tools/{cjxl,djxl,benchmark_xl} | ||
| - name: Upload artifacts | ||
| uses: actions/upload-artifact@v2 | ||
| with: | ||
| name: jxl-linux-x86_64-static | ||
| path: ${{ runner.workspace }}/release_file.tar.gz | ||
|
|
||
| - name: Upload binaries to release | ||
| if: github.event_name == 'release' | ||
| uses: svenstaro/upload-release-action@v1-release | ||
| with: | ||
| repo_token: ${{ secrets.GITHUB_TOKEN }} | ||
| file: ${{ runner.workspace }}/release_file.tar.gz | ||
| asset_name: jxl-linux-x86_64-static-${{ github.event.release.tag_name }}.tar.gz | ||
| tag: ${{ github.ref }} | ||
| overwrite: true | ||
|
|
||
|
|
||
| # Build .deb packages Ubuntu/Debian | ||
| release_ubuntu_pkg: | ||
| name: .deb packages / ${{ matrix.os }} | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| os: | ||
| - ubuntu:20.04 | ||
| - ubuntu:18.04 | ||
| - debian:buster | ||
| - debian:bullseye | ||
| - debian:bookworm | ||
| - debian:sid | ||
|
|
||
| container: | ||
| image: ${{ matrix.os }} | ||
|
|
||
| steps: | ||
| - name: Set env | ||
| shell: 'bash' | ||
| id: 'env' | ||
| run: | | ||
| artifact_name="jxl-debs-amd64-${matrix_os/:/-}" | ||
| echo ${artifact_name} | ||
| echo "::set-output name=artifact_name::${artifact_name}" | ||
| env: | ||
| matrix_os: ${{ matrix.os }} | ||
|
|
||
| - name: Install build deps | ||
| run: | | ||
| apt update | ||
| DEBIAN_FRONTEND=noninteractive apt install -y \ | ||
| build-essential \ | ||
| devscripts \ | ||
| # | ||
| - name: Install git (only 18.04) | ||
| if: matrix.os == 'ubuntu:18.04' | ||
| # Ubuntu 18.04 ships with git 2.17 but we need 2.18 or newer for | ||
| # actions/checkout@v2 to work | ||
| shell: 'bash' | ||
| run: | | ||
| apt install -y \ | ||
| libcurl4-openssl-dev \ | ||
| libexpat1-dev \ | ||
| libssl-dev \ | ||
| wget \ | ||
| zlib1g-dev \ | ||
| # | ||
| git_version="2.32.0" | ||
| wget -nv \ | ||
| "https://github.com/git/git/archive/refs/tags/v${git_version}.tar.gz" | ||
| tar -zxf "v${git_version}.tar.gz" | ||
| cd "git-${git_version}" | ||
| make prefix=/usr -j4 install | ||
| - name: Checkout the source | ||
| uses: actions/checkout@v2 | ||
| with: | ||
| submodules: true | ||
| fetch-depth: 1 | ||
|
|
||
| - name: Stamp non-release versions | ||
| # Stamps the built package with the commit date as part of the version | ||
| # after the version number so newer release candidates can override older | ||
| # ones. | ||
| if: github.event_name != 'release' | ||
| shell: 'bash' | ||
| run: | | ||
| # Committer timestamp. | ||
| set -x | ||
| commit_timestamp=$(git show -s --format=%ct) | ||
| commit_datetime=$(date --utc "--date=@${commit_timestamp}" '+%Y%m%d%H%M%S') | ||
| commit_ref=$(git rev-parse --short HEAD) | ||
| sem_version=$(dpkg-parsechangelog --show-field Version) | ||
| sem_version="${sem_version%%-*}" | ||
| deb_version="${sem_version}~alpha${commit_datetime}-0+git${commit_ref}" | ||
| dch -M --distribution unstable -b --newversion "${deb_version}" \ | ||
| "Stamping build with version ${deb_version}" | ||
| - name: Stamp release versions | ||
| # Mark the version as released | ||
| if: github.event_name == 'release' | ||
| shell: 'bash' | ||
| run: | | ||
| if head -n1 debian/changelog | grep UNRELEASED; then | ||
| dch -M --distribution unstable --release '' | ||
| fi | ||
| - name: Install gtest (only 18.04) | ||
| if: matrix.os == 'ubuntu:18.04' | ||
| # In Ubuntu 18.04 no package installed the libgtest.a. libgtest-dev | ||
| # installs the source files only. | ||
| run: | | ||
| apt install -y libgtest-dev cmake | ||
| for prj in googletest googlemock; do | ||
| (cd /usr/src/googletest/${prj}/ && | ||
| cmake CMakeLists.txt -DCMAKE_INSTALL_PREFIX=/usr && | ||
| make all install) | ||
| done | ||
| # Remove libgmock-dev dependency in Ubuntu 18.04. It doesn't exist there. | ||
| sed '/libgmock-dev,/d' -i debian/control | ||
| - name: Remove libjxl-gimp-plugin package (only 18.04) | ||
| if: matrix.os == 'ubuntu:18.04' | ||
| run: | | ||
| # Gimp 2.8 is not supported. | ||
| sed -i '/Package: libjxl-gimp-plugin/,/^$/d' debian/control | ||
| - name: Build hwy | ||
| run: | | ||
| apt build-dep -y ./third_party/highway | ||
| ./ci.sh debian_build highway | ||
| dpkg -i build/debs/libhwy-dev_*_amd64.deb | ||
| - name: Build libjxl | ||
| run: | | ||
| apt build-dep -y . | ||
| ./ci.sh debian_build jpeg-xl | ||
| - name: Stats | ||
| run: | | ||
| ./ci.sh debian_stats | ||
| - name: Upload artifacts | ||
| uses: actions/upload-artifact@v2 | ||
| with: | ||
| name: ${{ steps.env.outputs.artifact_name }} | ||
| path: | | ||
| build/debs/*jxl*.* | ||
| - name: Package release tarball | ||
| if: github.event_name == 'release' | ||
| run: | | ||
| (cd build/debs/; find -maxdepth 1 -name '*jxl*.*') | \ | ||
| tar -zcvf release_file.tar.gz -C build/debs/ -T - | ||
| - name: Upload binaries to release | ||
| if: github.event_name == 'release' | ||
| uses: svenstaro/upload-release-action@v1-release | ||
| with: | ||
| repo_token: ${{ secrets.GITHUB_TOKEN }} | ||
| file: release_file.tar.gz | ||
| asset_name: ${{ steps.env.outputs.artifact_name }}-${{ github.event.release.tag_name }}.tar.gz | ||
| tag: ${{ github.ref }} | ||
| overwrite: true | ||
|
|
||
|
|
||
| windows_build: | ||
| name: Windows Build (vcpkg / ${{ matrix.triplet }}) | ||
| runs-on: [windows-latest] | ||
| strategy: | ||
| matrix: | ||
| include: | ||
| - triplet: x86-windows-static | ||
| arch: '-A Win32' | ||
| - triplet: x64-windows-static | ||
| arch: '-A x64' | ||
|
|
||
| env: | ||
| VCPKG_VERSION: '2021.05.12' | ||
| VCPKG_ROOT: vcpkg | ||
| VCPKG_DISABLE_METRICS: 1 | ||
|
|
||
| steps: | ||
| - name: Checkout the source | ||
| uses: actions/checkout@v2 | ||
| with: | ||
| submodules: true | ||
| fetch-depth: 2 | ||
|
|
||
| - uses: actions/cache@v2 | ||
| id: cache-vcpkg | ||
| with: | ||
| path: vcpkg | ||
| key: ${{ runner.os }}-vcpkg-${{ env.VCPKG_VERSION }}-${{ matrix.triplet }} | ||
|
|
||
| - name: Download vcpkg | ||
| if: steps.cache-vcpkg.outputs.cache-hit != 'true' | ||
| # wget doesn't seem to work under bash. | ||
| shell: 'powershell' | ||
| run: | | ||
| C:\msys64\usr\bin\wget.exe -nv ` | ||
| https://github.com/microsoft/vcpkg/archive/refs/tags/${{ env.VCPKG_VERSION }}.zip ` | ||
| -O vcpkg.zip | ||
| - name: Bootstrap vcpkg | ||
| if: steps.cache-vcpkg.outputs.cache-hit != 'true' | ||
| shell: 'bash' | ||
| run: | | ||
| set -x | ||
| unzip -q vcpkg.zip | ||
| rm -rf ${VCPKG_ROOT} | ||
| mv vcpkg-${VCPKG_VERSION} ${VCPKG_ROOT} | ||
| ${VCPKG_ROOT}/bootstrap-vcpkg.sh | ||
| - name: Install libraries with vcpkg | ||
| shell: 'bash' | ||
| run: | | ||
| set -x | ||
| ${VCPKG_ROOT}/vcpkg --triplet ${{ matrix.triplet }} install \ | ||
| giflib \ | ||
| libjpeg-turbo \ | ||
| libpng \ | ||
| libwebp \ | ||
| # | ||
| - name: Configure | ||
| shell: 'bash' | ||
| run: | | ||
| set -x | ||
| mkdir build | ||
| cmake -Bbuild -H. ${{ matrix.arch }} \ | ||
| -DBUILD_TESTING=OFF \ | ||
| -DCMAKE_BUILD_TYPE=Release \ | ||
| -DCMAKE_INSTALL_PREFIX=`pwd`/prefix \ | ||
| -DCMAKE_TOOLCHAIN_FILE=${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake \ | ||
| -DJPEGXL_ENABLE_OPENEXR=OFF \ | ||
| -DJPEGXL_ENABLE_PLUGINS=OFF \ | ||
| -DJPEGXL_ENABLE_TCMALLOC=OFF \ | ||
| -DJPEGXL_ENABLE_VIEWERS=OFF \ | ||
| -DVCPKG_TARGET_TRIPLET=${{ matrix.triplet }} \ | ||
| # | ||
| - name: Build | ||
| shell: 'bash' | ||
| run: | | ||
| set -x | ||
| cmake --build build --config Release | ||
| - name: Install | ||
| shell: 'bash' | ||
| run: | | ||
| set -x | ||
| cmake --build build --config Release --target install | ||
| for pkg in giflib libjpeg-turbo libpng libwebp zlib; do | ||
| cp vcpkg/installed/${{matrix.triplet}}/share/${pkg}/copyright \ | ||
| prefix/bin/LICENSE.${pkg} | ||
| done | ||
| cp third_party/sjpeg/COPYING prefix/bin/LICENSE.sjpeg | ||
| cp third_party/skcms/LICENSE prefix/bin/LICENSE.skcms | ||
| cp third_party/highway/LICENSE prefix/bin/LICENSE.highway | ||
| cp third_party/brotli/LICENSE prefix/bin/LICENSE.brotli | ||
| cp LICENSE prefix/bin/LICENSE.libjxl | ||
| - name: Upload artifacts | ||
| uses: actions/upload-artifact@v2 | ||
| with: | ||
| name: jxl-${{matrix.triplet}} | ||
| path: | | ||
| prefix/bin/* | ||
| - name: Package release zip | ||
| if: github.event_name == 'release' | ||
| shell: 'powershell' | ||
| run: | | ||
| Compress-Archive -Path prefix\bin\* ` | ||
| -DestinationPath ${{ runner.workspace }}\release_file.zip | ||
| - name: Upload binaries to release | ||
| if: github.event_name == 'release' | ||
| uses: svenstaro/upload-release-action@v1-release | ||
| with: | ||
| repo_token: ${{ secrets.GITHUB_TOKEN }} | ||
| file: ${{ runner.workspace }}/release_file.zip | ||
| asset_name: jxl-${{matrix.triplet}}.zip | ||
| tag: ${{ github.ref }} | ||
| overwrite: true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,3 @@ | ||
| usr/bin/* | ||
| usr/share/man/man1/cjxl.1 | ||
| usr/share/man/man1/djxl.1 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,4 @@ | ||
| usr/include/jxl/*.h | ||
| usr/lib/*/*.a | ||
| usr/lib/*/*.so | ||
| usr/lib/*/pkgconfig/*.pc |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| usr/lib/*/gdk-pixbuf-*/*/loaders/* | ||
| usr/share/mime/packages/image-jxl.xml | ||
| usr/share/thumbnailers/jxl.thumbnailer |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| usr/lib/gimp |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1 @@ | ||
| usr/lib/*/libjxl*.so.* |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,17 @@ | ||
| #!/usr/bin/make -f | ||
|
|
||
| include /usr/share/dpkg/pkg-info.mk | ||
|
|
||
| %: | ||
| dh $@ --buildsystem=cmake | ||
|
|
||
| override_dh_auto_configure: | ||
| # TODO(deymo): Remove the DCMAKE_BUILD_TYPE once builds without NDEBUG | ||
| # are as useful as Release builds. | ||
| dh_auto_configure -- \ | ||
| -DJPEGXL_VERSION=$(DEB_VERSION) \ | ||
| -DCMAKE_BUILD_TYPE=RelWithDebInfo \ | ||
| -DJPEGXL_FORCE_SYSTEM_GTEST=ON \ | ||
| -DJPEGXL_FORCE_SYSTEM_BROTLI=ON \ | ||
| -DJPEGXL_FORCE_SYSTEM_HWY=ON \ | ||
| -DJPEGXL_ENABLE_PLUGINS=ON |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| # Developing for Windows with MSYS2 | ||
|
|
||
| [MSYS2](https://www.msys2.org/) ("minimal system 2") is a software distribution and a development platform based on MinGW and Cygwin. It provides a Unix-like environment to build code on Windows. These instructions were written with a 64-bit instance of Windows 10 running on a VM. They may also work on native instances of Windows and other versions of Windows. | ||
|
|
||
| ## Build Environments | ||
|
|
||
| MSYS2 provides multiple development [environments](https://www.msys2.org/docs/environments/). By convention, they are referred to in uppercase. They target slightly different platforms, runtime libraries, and compiler toolchains. For example, to build for 32-bit Windows, use the MINGW32 environment. For interoperability with Visual Studio projects, use the UCRT64 environment. | ||
|
|
||
| Since all of the build environments are built on top of the MSYS environment, **all updates and package installation must be done from within the MSYS environment**. After making any package changes, `exit` all MSYS2 terminals and restart the desired build-environment. This reminder is repeated multiple times throughout this guide. | ||
|
|
||
| * **MINGW32:** To compile for 32-bit Windows (on 64-bit Windows), use packages from the `mingw32` group. Package names are prefixed with `mingw-w64-i686`. The naming scheme may be different on the 32-bit version of MSYS2. | ||
|
|
||
| * **MINGW64:** This is the primary environment to building for 64-bit Windows. It uses the older MSVCRT runtime, which is widely available across Windows systems. Package names are prefixed with `mingw-w64-x86_64`. | ||
|
|
||
| * **UCRT64:** The Universal C Runtime (UCRT) is used by recent versions of Microsoft Visual Studio. It ships by default with Windows 10. For older versions of Windows, it must be provided with the application or installed by the user. Package names are prefixed with `mingw-w64-ucrt-x86_64`. | ||
|
|
||
| * **CLANG64:** Unfortunately, the `gimp` packages are not available for the CLANG64 environment. However, `libjxl` will otherwise build in this environment if the appropriate packages are installed. Packages are prefixed with `mingw-w64-clang-x86_64`. | ||
|
|
||
| ## Install and Upgrade MSYS2 | ||
|
|
||
| Download MSYS2 from the homepage. Install at a location without any spaces on a drive with ample free space. After installing the packages used in this guide, MSYS2 used about 15GB of space. | ||
|
|
||
| Toward the end of installation, select the option to run MSYS2 now. A command-line window will open. Run the following command, and answer the prompts to update the repository and close the terminal. | ||
|
|
||
| ```bash | ||
| pacman -Syu | ||
| ``` | ||
|
|
||
| Now restart the MSYS environment and run the following command to complete updates: | ||
|
|
||
| ```bash | ||
| pacman -Su | ||
| ``` | ||
|
|
||
| ## Package Management | ||
|
|
||
| Packages are organized in groups, which share the build environment name, but in lower case. Then they have name prefixes that indicate which group they belong to. Consider this package search: `pacman -Ss cmake` | ||
|
|
||
| ``` | ||
| mingw32/mingw-w64-i686-cmake | ||
| mingw64/mingw-w64-x86_64-cmake | ||
| ucrt64/mingw-w64-ucrt-x86_64-cmake | ||
| clang64/mingw-w64-clang-x86_64-cmake | ||
| msys/cmake | ||
| ``` | ||
|
|
||
| We can see the organization `group/prefix-name`. When installing packages, the group name is optional. | ||
|
|
||
| ```bash | ||
| pacman -S mingw-w64-x86_64-cmake | ||
| ``` | ||
|
|
||
| For tools that need to be aware of the compiler to function, install the package that corresponds with the specific build-environment you plan to use. For `cmake`, install the `mingw64` version. The generic `msys/cmake` will not function correctly because it will not find the compiler. For other tools, the generic `msys` version is adequate, like `msys/git`. | ||
|
|
||
| To remove packages, use: | ||
|
|
||
| ```bash | ||
| pacman -Rsc [package-name] | ||
| ``` | ||
|
|
||
| ## Worst-Case Scenario... | ||
|
|
||
| If packages management is done within a build environment other than MSYS, the environment structure will be disrupted and compilation will likely fail. If this happens, it may be necessary to reinstall MSYS2. | ||
|
|
||
| 1. Rename the `msys64` folder to `msys64.bak`. | ||
|
|
||
| 2. Use the installer to reinstall MSYS2 to `msys64`. | ||
|
|
||
| 3. Copy packages from `msys64.bak/var/cache/pacman/pkg/` to the new installation to save download time and bandwidth. | ||
|
|
||
| 4. Use `pacman` from within the MSYS environment to install and update packages. | ||
|
|
||
| 5. After successfully building a project, it is safe to delete `msys64.bak` | ||
|
|
||
| ## The MING64 Environment | ||
|
|
||
| Next set up the MING64 environment. The following commands should be run within the MSYS environment. `pacman -S` is used to install packages. The `--needed` argument prevents packages from being reinstalled. | ||
|
|
||
| ```bash | ||
| pacman -S --needed base-devel mingw-w64-x86_64-toolchain | ||
| pacman -S git mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja \ | ||
| mingw-w64-x86_64-gtest mingw-w64-x86_64-giflib \ | ||
| mingw-w64-x86_64-libpng mingw-w64-x86_64-libjpeg-turbo | ||
| ``` | ||
|
|
||
| ## Build `libjxl` | ||
|
|
||
| Download the source from the libjxl [releases](https://github.com/libjxl/libjxl/releases) page. Alternatively, you may obtain the latest development version with `git`. Run `./deps.sh` to ensure additional third-party dependencies are downloaded. | ||
|
|
||
| Start the MINGW64 environment, create a build directory within the source directory, and configure with `cmake`. | ||
|
|
||
| ```bash | ||
| mkdir build | ||
| cd build | ||
| cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \ | ||
| -DBUILD_TESTING=OFF -DJPEGXL_ENABLE_BENCHMARK=OFF \ | ||
| -DJPEGXL_ENABLE_PLUGINS=ON -DJPEGXL_ENABLE_MANPAGES=OFF \ | ||
| -DJPEGXL_FORCE_SYSTEM_BROTLI=ON \ | ||
| -DJPEGXL_FORCE_SYSTEM_GTEST=ON .. | ||
| ``` | ||
|
|
||
| Check the output to see if any dependencies were missed and need to be installed. Adding `-G Ninja` may be helpful, but on my computer, Ninja was selected by default. Remember that package changes must be done from the MSYS environment. Then exit all MSYS2 terminals and restart the build environment. | ||
|
|
||
| If all went well, you may now run `cmake` to build `libjxl`: | ||
|
|
||
| ```bash | ||
| cmake --build . | ||
| ``` | ||
|
|
||
| Do not be alarmed by the compiler warnings. They are a caused by differences between gcc/g++ and clang. The build should complete successfully. Then `cjxl`, `djxl`, `jxlinfo`, and others can be run from within the build environment. Moving them into the native Windows environment requires resolving `dll` issues that are beyond the scope of this document. | ||
|
|
||
| ## The `clang` Compiler | ||
|
|
||
| To use the `clang` compiler, install the packages that correspond with the environment you wish to use. Remember to make package changes from within the MSYS environment. | ||
|
|
||
| ``` | ||
| mingw-w64-i686-clang | ||
| mingw-w64-i686-clang-tools-extra | ||
| mingw-w64-i686-clang-compiler-rt | ||
| mingw-w64-x86_64-clang | ||
| mingw-w64-x86_64-clang-tools-extra | ||
| mingw-w64-x86_64-clang-compiler-rt | ||
| mingw-w64-ucrt64-x86_64-clang | ||
| mingw-w64-ucrt64-x86_64-clang-tools-extra | ||
| mingw-w64-ucrt64-x86_64-clang-compiler-rt | ||
| ``` | ||
|
|
||
| After the `clang` compiler is installed, 'libjxl' can be built with the `./ci.sh` script. | ||
|
|
||
| ```bash | ||
| ./ci.sh opt -DBUILD_TESTING=OFF -DJPEGXL_ENABLE_BENCHMARK=OFF \ | ||
| -DJPEGXL_ENABLE_MANPAGES=OFF -DJPEGXL_FORCE_SYSTEM_BROTLI=ON \ | ||
| -DJPEGXL_FORCE_SYSTEM_GTEST=ON | ||
| ``` | ||
|
|
||
| On my computer, `doxygen` packages needed to be installed to proceed with building. Use `pacman -Ss doxygen` to find the packages to install. | ||
|
|
||
| ## The GIMP Plugin | ||
|
|
||
| To build the GIMP plugin, install the relevant `gimp` package. This will also install dependencies. Again, perform package management tasks from only the MSYS environment. Then restart the build environment. | ||
|
|
||
| ```bash | ||
| pacman -S mingw-w64-i686-gimp | ||
| pacman -S mingw-w64-x86_64-gimp | ||
| pacman -S mingw-w64-ucrt-x86_64-gimp | ||
| ``` | ||
|
|
||
| If `clang` is installed, you can use the `./ci.sh` script to build. Otherwise, navigate to the build directory to reconfigure and build with `cmake`. | ||
|
|
||
| ```bash | ||
| cd build | ||
| rm -r C* | ||
| cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \ | ||
| -DBUILD_TESTING=OFF -DJPEGXL_ENABLE_BENCHMARK=OFF \ | ||
| -DJPEGXL_ENABLE_PLUGINS=ON -DJPEGXL_ENABLE_MANPAGES=OFF \ | ||
| -DJPEGXL_FORCE_SYSTEM_BROTLI=ON \ | ||
| -DJPEGXL_FORCE_SYSTEM_GTEST=ON .. | ||
| ``` | ||
|
|
||
| Fortunately, the plugin works without installing `dll` files. To test the plugin: | ||
|
|
||
| 1. [Download](https://www.gimp.org/downloads/) and install the stable version of GIMP (currently 2.10.24). | ||
|
|
||
| 2. Create a new folder: `C:\Program Files\GIMP 2\lib\gimp\2.0\plug-ins\file-jxl` | ||
|
|
||
| 3. Copy `build/plugins/gimp/file-jxl.exe` to the new folder. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| # Cross Compiling for Windows with Crossroad | ||
|
|
||
| [Crossroad](https://pypi.org/project/crossroad/) is a tool to set up cross-compilation environments on GNU/Linux distributions. These instructions assume a Debian/Ubuntu system. However, they can likely be adapted to other Linux environments. Since Ubuntu can be run on Windows through WSL, these instruction may be useful for developing directly on Windows. | ||
|
|
||
| ## Install Crossroad | ||
|
|
||
| Crossroad requires tools included with `python3-docutils` and `mingw-w64`. They may be installed using: | ||
|
|
||
| ```bash | ||
| sudo aptitude install python3-docutils mingw-w64 | ||
| ``` | ||
|
|
||
| The `zstandard` python package is also required, but is not available in the repositories. It may be installed using `pip`. | ||
|
|
||
| ```bash | ||
| pip3 install zstandard | ||
| ``` | ||
|
|
||
| After the dependencies are installed, crossroad itself maybe installed with `pip`. | ||
|
|
||
| ```bash | ||
| pip3 install crossroad | ||
| ``` | ||
|
|
||
| If there are errors while running crossroad, it may need to be downloaded and installed directly using `setup.py`. Instructions are on the crossroad homepage. | ||
|
|
||
| ## Update Debian Alternatives | ||
|
|
||
| Since `libjxl` uses C++ features that require posix threads, the symlinks used by the Debian alternative system need to be updated: | ||
|
|
||
| ```bash | ||
| sudo update-alternatives --config x86_64-w64-mingw32-g++ | ||
| ``` | ||
|
|
||
| Select the option that indicates `posix` usage. Repeat for `gcc` and `i686`: | ||
|
|
||
| ```bash | ||
| sudo update-alternatives --config x86_64-w64-mingw32-gcc | ||
| sudo update-alternatives --config i686-w64-mingw32-gcc | ||
| sudo update-alternatives --config i686-w64-mingw32-g++ | ||
| ``` | ||
|
|
||
| ## Create a New Crossroad Project | ||
|
|
||
| Crossroad supports the following platforms: | ||
|
|
||
| ``` | ||
| native Native platform (x86_64 GNU/Linux) | ||
| android-x86 Generic Android/Bionic on x86 | ||
| android-mips64 Generic Android/Bionic on MIPS64 | ||
| android-x86-64 Generic Android/Bionic on x86-64 | ||
| w64 Windows 64-bit | ||
| w32 Windows 32-bit | ||
| android-arm64 Generic Android/Bionic on ARM64 | ||
| android-mips Generic Android/Bionic on MIPS | ||
| android-arm Generic Android/Bionic on ARM | ||
| ``` | ||
|
|
||
| To begin cross compiling for Windows, a new project needs to be created: | ||
|
|
||
| ```bash | ||
| crossroad w64 [project-name] | ||
| ``` | ||
|
|
||
| ## Install Dependencies | ||
|
|
||
| Since the `gimp` development package is required to build the GIMP plugin and also includes most of the packages required by `libjxl`, install it first. | ||
|
|
||
| ```bash | ||
| crossroad install gimp | ||
| ``` | ||
|
|
||
| `gtest` and `brotli` are also required. | ||
|
|
||
| ```bash | ||
| crossroad install gtest brotli | ||
| ``` | ||
|
|
||
| If any packages are later found to be missing, you may search for them using: | ||
|
|
||
| ```bash | ||
| crossroad search [...] | ||
| ``` | ||
|
|
||
| ## Build `libjxl` | ||
|
|
||
| Download the source from the libjxl [releases](https://github.com/libjxl/libjxl/releases) page. Alternatively, you may obtain the latest development version with `git`. Run `./deps.sh` to ensure additional third-party dependencies are downloaded. Unfortunately, the script `./ci.sh` does not work with Crossroad, so `cmake` will need to be called directly. | ||
|
|
||
| Create a build directory within the source directory. If you haven't already, start your crossroad project and run `cmake`: | ||
|
|
||
| ```bash | ||
| mkdir build | ||
| cd build | ||
| crossroad w64 libjxl | ||
| crossroad cmake -DCMAKE_BUILD_TYPE=Release \ | ||
| -DBUILD_TESTING=OFF -DJPEGXL_ENABLE_BENCHMARK=OFF \ | ||
| -DJPEGXL_ENABLE_PLUGINS=ON -DJPEGXL_FORCE_SYSTEM_BROTLI=ON \ | ||
| -DJPEGXL_FORCE_SYSTEM_GTEST=ON .. | ||
| ``` | ||
|
|
||
| Check the output to see if any dependencies were missed and need to be installed. If all went well, you may now run `cmake` to build `libjxl`: | ||
|
|
||
| ```bash | ||
| cmake --build . | ||
| ``` | ||
|
|
||
| ## Try out the GIMP Plugin | ||
|
|
||
| To install and try out out the GIMP plugin: | ||
|
|
||
| 1. [Download](https://www.gimp.org/downloads/) and install the stable version of GIMP (currently 2.10.24). | ||
|
|
||
| 2. Create a new folder: `C:\Program Files\GIMP 2\lib\gimp\2.0\plug-ins\file-jxl` | ||
|
|
||
| 3. Copy `build/plugins/gimp/file-jxl.exe` to the new folder. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| # Fuzzing | ||
|
|
||
| Fuzzing is a technique to find potential bugs by providing randomly generated | ||
| invalid inputs. To detect potential bugs such as programming errors we use | ||
| fuzzing in combination with ASan (Address Sanitizer), MSan (Memory Sanitizer), | ||
| UBSan (Undefined Behavior Sanitizer) and asserts in the code. An invalid input | ||
| will likely produce a decoding error (some API function returning error), which | ||
| is absolutely not a problem, but what it should not do is access memory out of | ||
| bounds, use uninitialized memory or hit a false assert condition. | ||
|
|
||
| ## Automated Fuzzing with oss-fuzz | ||
|
|
||
| libjxl fuzzing is integrated into [oss-fuzz](https://github.com/google/oss-fuzz) | ||
| as the project `libjxl`. oss-fuzz regularly runs the fuzzers on the `main` | ||
| branch and reports bugs into their bug tracker which remains private until the | ||
| bugs are fixed in main. | ||
|
|
||
| ## Fuzzer targets | ||
|
|
||
| There are several fuzzer executable targets defined in the `tools/` directory | ||
| to fuzz different parts of the code. The main one is `djxl_fuzzer`, which uses | ||
| the public C decoder API to attempt to decode an image. The fuzzer input is not | ||
| directly the .jxl file, the last few bytes of the fuzzer input are used to | ||
| decide *how* will the API be used (if preview is requested, the pixel format | ||
| requested, if the .jxl input data is provided altogether, etc) and the rest of | ||
| the fuzzer input is provided as the .jxl file to the decoder. Some bugs might | ||
| reproduce only if the .jxl input is decoded in certain way. | ||
|
|
||
| The remaining fuzzer targets execute a specific portion the codec that might be | ||
| easier to fuzz independently from the whole codec. | ||
|
|
||
| ## Reproducing fuzzer bugs | ||
|
|
||
| A fuzzer target, like `djxl_fuzzer` accepts as a parameter one or more files | ||
| that will be used as inputs. This runs the fuzzer program in test-only mode | ||
| where no new inputs are generated and only the provided files are tested. This | ||
| is the easiest way to reproduce a bug found by the fuzzer using the generated | ||
| test case from the bug report. | ||
|
|
||
| oss-fuzz uses a specific compiler version and flags, and it is built using | ||
| Docker. Different compiler versions will have different support for detecting | ||
| certain actions as errors, so we want to reproduce the build from oss-fuzz as | ||
| close as possible. To reproduce the build as generated by oss-fuzz there are a | ||
| few helper commands in `ci.sh` as explained below. | ||
|
|
||
| ### Generate the gcr.io/oss-fuzz/libjxl image | ||
|
|
||
| First you need the ossfuzz libjxl builder image. This is the base oss-fuzz | ||
| builder image with a few dependencies installed. To generate it you need to | ||
| check out the oss-fuzz project and build it: | ||
|
|
||
| ```bash | ||
| git clone https://github.com/google/oss-fuzz.git ~/oss-fuzz | ||
| cd ~/oss-fuzz | ||
| sudo infra/helper.py build_image libjxl | ||
| ``` | ||
|
|
||
| This will create the `gcr.io/oss-fuzz/libjxl` docker image. You can check if it | ||
| was created verifying that it is listed in the output of the `sudo docker image | ||
| ls` command. | ||
|
|
||
| ### Build the fuzzer targets with oss-fuzz | ||
|
|
||
| To build the fuzzer targets from the current libjxl source checkout, use the | ||
| `./ci.sh ossfuzz_msan` command for MSan, `./ci.sh ossfuzz_asan` command for ASan | ||
| or `./ci.sh ossfuzz_ubsan` command for UBSan. All the `JXL_ASSERT` and | ||
| `JXL_DASSERT` calls are enabled in all the three modes. These ci.sh helpers will | ||
| reproduce the oss-fuzz docker call to build libjxl mounting the current source | ||
| directory into the Docker container. Ideally you will run this command in a | ||
| different build directory separated from your regular builds. | ||
|
|
||
| For example, for MSan builds run: | ||
|
|
||
| ```bash | ||
| BUILD_DIR=build-fuzzmsan ./ci.sh ossfuzz_msan | ||
| ``` | ||
|
|
||
| After this, the fuzzer program will be generated in the build directory like | ||
| for other build modes: `build-fuzzmsan/tools/djxl_fuzzer`. | ||
|
|
||
| ### Iterating changes with oss-fuzz builds | ||
|
|
||
| After modifying the source code to fix the fuzzer-found bug, or to include more | ||
| debug information, you can rebuild only a specific fuzzer target to save on | ||
| rebuilding time and immediately run the test case again. For example, for | ||
| rebuilding and testing only `djxl_fuzzer` in MSan mode we can run: | ||
|
|
||
| ```bash | ||
| BUILD_DIR=build-fuzzmsan ./ci.sh ossfuzz_msan djxl_fuzzer && build-fuzzmsan/tools/djxl_fuzzer path/to/testcase.bin | ||
| ``` | ||
|
|
||
| When MSan and ASan fuzzers fail they will print a stack trace at the point where | ||
| the error occurred, and some related information. To make these these stack | ||
| traces useful we need to convert the addresses to function names and source file | ||
| names and lines, which is done with the "symbolizer". For UBSan to print a stack | ||
| trace we need to set the `UBSAN_OPTIONS` environment variables when running the | ||
| fuzzer. | ||
|
|
||
| Set the following environment variables when testing the fuzzer binaries. Here | ||
| `clang` should match the compiler version used by the container, you can pass a | ||
| different compiler version in the following example by first installing the | ||
| clang package for that version outside the container and using `clang-NN` | ||
| (for example `clang-11`) instead of `clang` in the following commands: | ||
|
|
||
| ```bash | ||
| symbolizer=$($(realpath $(which clang)) -print-prog-name=llvm-symbolizer) | ||
| export MSAN_SYMBOLIZER_PATH="${symbolizer}" | ||
| export UBSAN_SYMBOLIZER_PATH="${symbolizer}" | ||
| export ASAN_SYMBOLIZER_PATH="${symbolizer}" | ||
| export ASAN_OPTIONS=detect_leaks=1 | ||
| export UBSAN_OPTIONS=print_stacktrace=1 | ||
| ``` | ||
|
|
||
| Note: The symbolizer binary must be a program called `llvm-symbolizer`, any | ||
| other file name will fail. There are normally symlinks already installed with | ||
| the right name which the `-print-prog-name` would print. | ||
|
|
||
| ## Running the fuzzers locally | ||
|
|
||
| Running the fuzzer targets in fuzzing mode can be achieved by running them with | ||
| no parameters, or better with a parameter with the path to a *directory* | ||
| containing a seed of files to use as a starting point. Note that passing a | ||
| directory is considered a corpus to use for fuzzing while passing a file is | ||
| considered an input to evaluate. Multi-process fuzzing is also supported. For | ||
| details about all the fuzzing options run: | ||
|
|
||
| ```bash | ||
| build-fuzzmsan/tools/djxl_fuzzer -help=1 | ||
| ``` | ||
|
|
||
| ## Writing fuzzer-friendly code | ||
|
|
||
| Fuzzing on itself can't find programming bugs unless an input makes the program | ||
| perform an invalid operation (read/write out of bounds, perform an undefined | ||
| behavior operation, etc). You can help the fuzzer find invalid situations by | ||
| adding asserts: | ||
|
|
||
| * `JXL_ASSERT()` is enabled in Release mode by default. It can be disabled | ||
| with `-DJXL_ENABLE_ASSERT=0` but the intention is that it will run for all | ||
| the users in released code. If performance of the check is not an issue (like | ||
| checks done once per image, once per channel, once per group, etc) a | ||
| JXL_ASSERT is appropriate. A failed assert is preferable to an out of bounds | ||
| write. | ||
|
|
||
| * `JXL_DASSERT()` is only enabled in Debug builds, which includes all the ASan, | ||
| MSan and UBSan builds. Performance of these checks is not an issue if kept | ||
| within reasonable limits (automated msan/asan test should finish withing 1 | ||
| hour for example). Fuzzing is more effective when the given input runs | ||
| faster, so keep that in mind when adding a complex DASSERT that runs multiple | ||
| times per output pixel. | ||
|
|
||
| * For MSan builds it is also possible to specify that certain values must be | ||
| initialized. This is automatic for values that are used to make decisions | ||
| (like when used in an `if` statement or in the ternary operator condition) | ||
| but those checks can be made explicit for image data using the | ||
| `JXL_CHECK_IMAGE_INITIALIZED(image, rect)` macro. This helps document and | ||
| check (only in MSan builds) that a given portion of the image is expected to | ||
| be initialized, allowing to catch errors earlier in the process. | ||
|
|
||
| ## Dealing with use-of-uninitialized memory | ||
|
|
||
| In MSan builds it is considered an error to *use* uninitialized memory. Using | ||
| the memory normally requires something like a decision / branch based on the | ||
| uninitialized value, just running `memcpy()` or simple arithmetic over | ||
| uninitialized memory is not a problem. Notably, computing `DemoteTo()`, | ||
| `NearestInt()` or similar expressions that create a branch based on the value of | ||
| the uninitialized memory will trigger an MSan error. | ||
|
|
||
| In libjxl we often run vectorized operations over a series of values, rounding | ||
| up to the next multiple of a vector size, thus operating over uninitialized | ||
| values past the end of the requested region. These values are part of the image | ||
| padding but are not initialized. This behavior would not create an MSan error | ||
| unless the processing includes operations like `NearestInt()`. For such cases | ||
| the preferred solution is to use `msan::UnpoisonMemory` over the portion of | ||
| memory of the last SIMD vector before processing, and then running | ||
| `msan::PoisonMemory` over the corresponding value in the output side. A note | ||
| including why this is safe to do must be added, for example if the processing | ||
| doesn't involve any cross-lane computation. | ||
|
|
||
| Initializing padding memory in MSan builds is discouraged because it may hide | ||
| bugs in functions that weren't supposed to read from the padding. Initializing | ||
| padding memory in all builds, including Release builds, would mitigate the | ||
| MSan potential security issue but it would hide the logic bug for a longer time | ||
| and potentially incur in a performance hit. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,262 @@ | ||
| # libjxl release process | ||
|
|
||
| This guide documents the release process for the libjxl project. | ||
|
|
||
| libjxl follows the [semantic versioning](https://semver.org/spec/v2.0.0.html) | ||
| specification for released versions. Releases are distributed as tags in the git | ||
| repository with the semantic version prefixed by the letter "v". For example, | ||
| release version "0.3.7" will have a git tag "v0.3.7". | ||
|
|
||
| The public API is explicitly defined as C headers in the `lib/include` | ||
| directory, normally installed in your include path. All other headers are | ||
| internal API and are not covered by the versioning rules. | ||
|
|
||
| ## Development and release workflow | ||
|
|
||
| New code development is performed on the `main` branch of the git repository. | ||
| Pre-submit checks enforce minimum build and test requirements for new patches | ||
| that balance impact and test latency, but not all checks are performed before | ||
| pull requests are merged. Several slower checks only run *after* the code has | ||
| been merged to `main`, resulting in some errors being detected hours after the | ||
| code is merged or even days after in the case of fuzzer-detected bugs. | ||
|
|
||
| Release tags are cut from *release branches*. Each MAJOR.MINOR version has its | ||
| own release branch, for example releases `0.5`, `0.5.1`, `0.5.2`, ... would have | ||
| tags `v0.5`, `v0.5.1`, `v0.5.2`, ... on commits from the `v0.5.x` branch. | ||
| `v0.5.x` is a branch name, not a tag name, and doesn't represent a released | ||
| version since semantic versioning requires that the PATCH is a non-negative | ||
| number. Released tags don't each one have their own release branch, all releases | ||
| from the same MAJOR.MINOR version will share the same branch. | ||
|
|
||
| The main purpose of the release branch is to stabilize the code before a | ||
| release. This involves including fixes to existing bugs but **not** including | ||
| new features. New features often come with new bugs which take time to fix, so | ||
| having a release branch allows us to cherry-pick *bug fixes* from the `main` | ||
| branch into the release branch without including the new *features* from `main`. | ||
| For this reason it is important to make small commits in `main` and separate bug | ||
| fixes from new features. | ||
|
|
||
| After the initial minor release (`M.N`, for example `0.5.0` or just `0.5`) the | ||
| release branch is used to continue to cherry-pick fixes to be included in a | ||
| patch release, for example a version `0.5.1` release. Patch fixes are only meant | ||
| to fix security bugs or other critical bugs that can't wait until the next major | ||
| or minor release. | ||
|
|
||
| Release branches *may* continue to be maintained even after the next minor or | ||
| major version has been released to support users that can't update to a newer | ||
| minor release. In that case, the same process applies to all the maintained | ||
| release branches. | ||
|
|
||
| A release branch with specific cherry-picks from `main` means that the release | ||
| code is actually a version of the code that never existed in the `main` branch, | ||
| so it needs to be tested independently. Pre-submit and post-submit tests run on | ||
| release branches (branches matching `v*.*.x`) but extra manual checks should be | ||
| performed before a release, specially if multiple bug fixes interact with each | ||
| other. Take this into account when selecting which commits to include in a | ||
| release. The objective is to have a stable version that can be used without | ||
| problems for months. Having the latest improvements at the time the release tag | ||
| is created is a non-goal. | ||
|
|
||
| ## Creating a release branch | ||
|
|
||
| A new release branch is needed before creating a new major or minor release, | ||
| that is, a new release where the MAJOR or MINOR numbers are increased. Patch | ||
| releases, where only the PATCH number is increased, reuse the branch from the | ||
| previous release of the same MAJOR and MINOR numbers. | ||
|
|
||
| The following instructions assume that you followed the recommended [libjxl git | ||
| setup](developing_in_github.md) where `origin` points to the upstream | ||
| libjxl/libjxl project, otherwise use the name of your upstream remote repository | ||
| instead of `origin`. | ||
|
|
||
| The release branch is normally created from the latest work in `main` at the | ||
| time the branch is created, but it is possible to create the branch from an | ||
| older commit if the current `main` is particularly unstable or includes commits | ||
| that were not intended to be included in the release. The following example | ||
| creates the branch `v0.5.x` from the latest commit in main (`origin/main`), if a | ||
| different commit is to be used then replace `origin/main` with the SHA of that | ||
| commit. Change the `v0.5.x` branch name to the one you are creating. | ||
|
|
||
| ```bash | ||
| git fetch origin main | ||
| git push git@github.com:libjxl/libjxl.git origin/main:refs/heads/v0.5.x | ||
| ``` | ||
|
|
||
| Here we use the SSH URL explicitly since you are pushing to the `libjxl/libjxl` | ||
| project directly to a branch there. If you followed the guide `origin` will have | ||
| the HTTPS URL which wouldn't normally let you push since you wouldn't be | ||
| authenticated. The `v*.*.x` branches are [GitHub protected | ||
| branches](https://docs.github.com/en/github/administering-a-repository/defining-the-mergeability-of-pull-requests/about-protected-branches) | ||
| in our repository, however you can push to a protected branch when *creating* it | ||
| but you can't directly push to it after it is created. To include more changes | ||
| in the release branch see the "Cherry-picking fixes to a release" section below. | ||
|
|
||
| ## Creating a merge label | ||
|
|
||
| We use GitHub labels in Pull Requests to keep track of the changes that should | ||
| be merged into a given release branch. For this purpose create a new label for | ||
| each new MAJOR.MINOR release branch called `merge-MAJOR.MINOR`, for example, | ||
| `merge-0.5`. | ||
|
|
||
| In the [edit labels](https://github.com/libjxl/libjxl/issues/labels) page, click | ||
| on "New label" and create the label. Pick your favorite color. | ||
|
|
||
| Labels are a GitHub-only concept and are not represented in git. You can add the | ||
| label to a Pull Request even after it was merged, whenever it is decided that | ||
| the Pull Request should be included in the given release branch. Adding the | ||
| label doesn't automatically merge it to the release branch. | ||
|
|
||
| ## Update the versioning number | ||
|
|
||
| The version number (as returned by `JxlDecoderVersion`) in the source code in | ||
| `main` must match the semantic versioning of a release. After the release | ||
| branch is created the code in `main` will only be included in the next major | ||
| or minor release. Right after a release branch update the version targeting the | ||
| next release. Artifacts from `main` should include the new (unreleased) version, | ||
| so it is important to update it. For example, after the `v0.5.x` branch is | ||
| created from main, you should update the version on `main` to `0.6`. | ||
|
|
||
| To help update it, run this helper command (in a Debian-based system): | ||
|
|
||
| ```bash | ||
| ./ci.sh bump_version 0.6 | ||
| ``` | ||
|
|
||
| This will update the version in the following files: | ||
|
|
||
| * `lib/CMakeLists.txt` | ||
| * `lib/lib.gni`, automatically updated with `tools/build_cleaner.py --update`. | ||
| * `debian/changelog` to create the Debian package release with the new version. | ||
| Debian changelog shouldn't repeat the library changelog, instead it should | ||
| include changes to the packaging scripts. | ||
|
|
||
| ## Cherry-pick fixes to a release | ||
|
|
||
| After a Pull Request that should be included in a release branch has been merged | ||
| to `main` it can be cherry-picked to the release branch. Before cherry-picking a | ||
| change to a release branch it is important to check that it doesn't introduce | ||
| more problems, in particular it should run for some time in `main` to make sure | ||
| post-submit tests and the fuzzers run on it. Waiting for a day is a good idea. | ||
|
|
||
| Most of the testing is done on the `main` branch, so be careful with what | ||
| commits are cherry-picked to a branch. Refactoring code is often not a good | ||
| candidate to cherry-pick. | ||
|
|
||
| To cherry-pick a single commit to a release branch (in this example to `v0.5.x`) | ||
| you can run: | ||
|
|
||
| ```bash | ||
| git fetch origin | ||
| git checkout origin/v0.5.x -b merge_to_release | ||
| git cherry-pick -x SHA_OF_MAIN_COMMIT | ||
| # -x will annotate the cherry-pick with the original SHA_OF_MAIN_COMMIT value. | ||
| # If not already mentioned in the original commit, add the original PR number to | ||
| # the commit, for example add "(cherry picked from PR #NNNN)". | ||
| git commit --amend | ||
| ``` | ||
|
|
||
| The `SHA_OF_MAIN_COMMIT` is the hash of the commit as it landed in main. Use | ||
| `git log origin/main` to list the recent main commits and their hashes. | ||
|
|
||
| Making sure that the commit message on the cherry-picked commit contains a | ||
| reference to the original pull request (like `#NNNN`) is important. It creates | ||
| an automatic comment in the original pull request notifying that it was | ||
| mentioned in another commit, helping keep track of the merged pull requests. If | ||
| the original commit was merged with the "Squash and merge" policy it will | ||
| automatically contain the pull request number on the first line, if this is not | ||
| the case you can amend the commit message of the cherry-pick to include a | ||
| reference. | ||
|
|
||
| Multiple commits can be cherry-picked and tested at once to save time. Continue | ||
| running `git cherry-pick` and `git commit --amend` multiple times for all the | ||
| commits you need to cherry-pick, ideally in the same order they were merged on | ||
| the `main` branch. At the end you will have a local branch with multiple commits | ||
| on top of the release branch. | ||
|
|
||
| Finally, upload your changes to *your fork* like normal, except that when | ||
| creating a pull request select the desired release branch as a target: | ||
|
|
||
| ```bash | ||
| git push myfork merge_to_release | ||
| ``` | ||
|
|
||
| If you used the [guide](developing_in_github.md) `myfork` would be `origin` in | ||
| that example. Click on the URL displayed, which will be something like | ||
|
|
||
| `https://github.com/mygithubusername/libjxl/pull/new/merge_to_release` | ||
|
|
||
| In the "Open a pull request" page, change the drop-down base branch from | ||
| "base: main" (the default) to the release branch you are targeting. | ||
|
|
||
| The pull request approval and pre-submit rules apply as with normal pull | ||
| requests to the `main` branch. | ||
|
|
||
| **Important:** When merging multiple cherry-picks use "Rebase and merge" policy, | ||
| not the squash one since otherwise you would discard the individual commit | ||
| message references from the git history in the release branch. | ||
|
|
||
| ## Publishing a release | ||
|
|
||
| Once a release tag is created it must not be modified, so you need to prepare | ||
| the changes before creating the release. Make sure you checked the following: | ||
|
|
||
| * The semantic version number in the release branch (see `lib/CMakeLists.txt`) | ||
| matches the number you intend to release, all three MAJOR, MINOR and PATCH | ||
| should match. Otherwise send a pull request to the release branch to | ||
| update them. | ||
|
|
||
| * The GitHub Actions checks pass on the release branch. Look for the green | ||
| tick next to the last commit on the release branch. This should be visible | ||
| on the branch page, for example: https://github.com/libjxl/libjxl/tree/v0.5.x | ||
|
|
||
| * There no open fuzzer-found bugs for the release branch. The most effective | ||
| way is to [run the fuzzer](fuzzing.md) on the release branch for a while. You | ||
| can seed the fuzzer with corpus generated by oss-fuzz by [downloading | ||
| it](https://google.github.io/oss-fuzz/advanced-topics/corpora/#downloading-the-corpus), | ||
| for example `djxl_fuzzer` with libFuzzer will use: | ||
| gs://libjxl-corpus.clusterfuzz-external.appspot.com/libFuzzer/libjxl_djxl_fuzzer | ||
|
|
||
| * Manually check that images encode/decode ok. | ||
|
|
||
| * Manually check that downstream projects compile with our code. Sometimes | ||
| bugs on build scripts are only detected when other projects try to use our | ||
| library. For example, test compiling | ||
| [imagemagick](https://github.com/ImageMagick/ImageMagick) and Chrome. | ||
|
|
||
| A [GitHub | ||
| "release"](https://docs.github.com/en/github/administering-a-repository/releasing-projects-on-github/about-releases) | ||
| consists of two different concepts: | ||
|
|
||
| * a git "tag": this is a name (`v` plus the semantic version number) with a | ||
| commit hash associated, defined in the git repository. Most external projects | ||
| will use git tags or HTTP URLs to these tags to fetch the code. | ||
|
|
||
| * a GitHub "release": this is a GitHub-only concept and is not represented in | ||
| git other than by having a git tag associated with the release. A GitHub | ||
| release has a given source code commit SHA associated (through the tag) but | ||
| it *also* contains release notes and optional binary files attached to the | ||
| release. | ||
|
|
||
| Releases from the older GitLab repository only have a git tag in GitHub, while | ||
| newer releases have both a git tag and a release entry in GitHub. | ||
|
|
||
| To publish a release open the [New Release | ||
| page](https://github.com/libjxl/libjxl/releases/new) and follow these | ||
| instructions: | ||
|
|
||
| * Set the "Tag version" as "v" plus the semantic version number. Omit the ".0" | ||
| when the PATCH version is 0, for example use "v0.5" or "v0.5.1" but not | ||
| "v0.5.0". | ||
|
|
||
| * Select the "Target" as your release branch. For a "v0.5" release tag you | ||
| would use the "v0.5.x" branch. | ||
|
|
||
| * Use the version number as the release title. | ||
|
|
||
| * Copy-paste the relevant section of the [CHANGELOG.md](../CHANGELOG.md) to the | ||
| release notes into the release notes. Add any other information pertaining | ||
| the release itself that are not included in the CHANGELOG.md, although prefer | ||
| to include those in the CHANGELOG.md file. You can switch to the Preview tab | ||
| to see the results. | ||
|
|
||
| * Finally click "Publish release" and go celebrate with the team. 🎉 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # JPEG XL software support | ||
|
|
||
| This document attempts to keep track of software that is using libjxl to support JPEG XL. | ||
| This list serves several purposes: | ||
|
|
||
| - thank/acknowledge other projects for integrating jxl support | ||
| - point end-users to software that can read/write jxl | ||
| - keep track of the adoption status of jxl | ||
| - in case of a (security) bug in libjxl, it's easier to see who might be affected and check if they are updated (in case they use static linking) | ||
|
|
||
| Please add missing software to this list. | ||
|
|
||
| ## Browsers | ||
|
|
||
| - Chromium: behind a flag since version 91, [tracking bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1178058) | ||
| - Firefox: behind a flag since version 90, [tracking bug](https://bugzilla.mozilla.org/show_bug.cgi?id=1539075) | ||
| - Safari: not supported, [tracking bug](https://bugs.webkit.org/show_bug.cgi?id=208235) | ||
| - Edge: behind a flag since version 91, start with `.\msedge.exe --enable-features=JXL` | ||
| - Opera: behind a flag since version 77. | ||
|
|
||
| ## Image libraries | ||
|
|
||
| - [ImageMagick](https://imagemagick.org/): supported since 7.0.10-54 | ||
| - [libvips](https://libvips.github.io/libvips/): supported since 8.11 | ||
| - [Imlib2](https://github.com/alistair7/imlib2-jxl) | ||
|
|
||
| ## OS-level support / UI frameworks / file browser plugins | ||
|
|
||
| - Qt / KDE: [plugin available](https://github.com/novomesk/qt-jpegxl-image-plugin) | ||
| - GDK-pixbuf: plugin available in libjxl repo | ||
| - [gThumb](https://ubuntuhandbook.org/index.php/2021/04/gthumb-3-11-3-adds-jpeg-xl-support/) | ||
| - [MacOS viewer/QuickLook plugin](https://github.com/yllan/JXLook) | ||
| - [Windows Imaging Component](https://github.com/mirillis/jpegxl-wic) | ||
| - [Windows thumbnail handler](https://github.com/saschanaz/jxl-winthumb) | ||
| - [OpenMandriva Lx (since 4.3 RC)](https://www.openmandriva.org/en/news/article/openmandriva-lx-4-3-rc-available-for-testing) | ||
| - [KaOS (since 2021.06)](https://news.itsfoss.com/kaos-2021-06-release/) | ||
|
|
||
| ## Image editors | ||
|
|
||
| - GIMP: plugin available in libjxl repo, no official support, [tracking bug](https://gitlab.gnome.org/GNOME/gimp/-/issues/4681) | ||
| - Photoshop: no plugin available yet, no official support yet | ||
|
|
||
| ## Image viewers | ||
|
|
||
| - [XnView](https://www.xnview.com/en/) | ||
| - [ImageGlass](https://imageglass.org/) | ||
| - Any viewer based on Qt, KDE, GDK-pixbuf, ImageMagick, libvips or imlib2 (see above) | ||
| - Qt viewers: gwenview, digiKam, KolourPaint, KPhotoAlbum, LXImage-Qt, qimgv, qView, nomacs, VookiImageViewer, PhotoQt | ||
| - GTK viewers: Eye of Gnome (eog), gThumb, Geeqie | ||
|
|
||
| ## Online tools | ||
|
|
||
| - [Squoosh](https://squoosh.app/) | ||
| - [Cloudinary](https://cloudinary.com/blog/cloudinary_supports_jpeg_xl) | ||
| - [MConverter](https://mconverter.eu/) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # Copyright (c) the JPEG XL Project Authors. All rights reserved. | ||
| # | ||
| # Use of this source code is governed by a BSD-style | ||
| # license that can be found in the LICENSE file. | ||
|
|
||
| add_executable(decode_oneshot ${CMAKE_CURRENT_LIST_DIR}/decode_oneshot.cc) | ||
| target_link_libraries(decode_oneshot jxl_dec jxl_threads) | ||
| add_executable(encode_oneshot ${CMAKE_CURRENT_LIST_DIR}/encode_oneshot.cc) | ||
| target_link_libraries(encode_oneshot jxl jxl_threads) | ||
|
|
||
| add_executable(jxlinfo ${CMAKE_CURRENT_LIST_DIR}/jxlinfo.c) | ||
| target_link_libraries(jxlinfo jxl) | ||
|
|
||
| if(NOT ${SANITIZER} STREQUAL "none") | ||
| # Linking a C test binary with the C++ JPEG XL implementation when using | ||
| # address sanitizer is not well supported by clang 9, so force using clang++ | ||
| # for linking this test if a sanitizer is used. | ||
| set_target_properties(jxlinfo PROPERTIES LINKER_LANGUAGE CXX) | ||
| endif() # SANITIZER != "none" |