Skip to content

Commit

Permalink
build(binding): add universal macOS ARM64 dylib and static FreeType c…
Browse files Browse the repository at this point in the history
…ompilation

- Static FreeType linking flow for all OS
- Flow to build universal binaries for macOS (x86_64, aarch64)
- Simplified CI workflow by removing FreeType branches from the build matrix

Added 2 new scripts:
1. `buildSrc/scripts/vendor_freetype.sh`
2. `buildSrc/scripts/build.sh`

The first script prepares FreeType for usage in the build process.
The result of this script is used in the `GenerateLibs` task.
Other ways of building with FreeType are removed.
If it's impossible to build with FreeType, it is recommended to set `freetype=false`.

The second script aggregates commands to build native binaries.
It includes specific steps, such as creating a universal library for macOS and copying the result to the specific folder `/tmp/imgui/dst`.

Script 1 can be used for local builds. Script 2 is primarily intended for use in CI.
  • Loading branch information
SpaiR committed Aug 7, 2024
1 parent 66522fa commit 46c008e
Show file tree
Hide file tree
Showing 16 changed files with 423 additions and 220 deletions.
108 changes: 50 additions & 58 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
name: CI
on: [ push, pull_request ]

on:
push:
branches:
- main
tags:
- v*
pull_request:
branches:
- main

jobs:
build-java:
name: Build Java
Expand All @@ -20,34 +30,33 @@ jobs:
- name: Build
run: ./gradlew buildAll

# This helps to upload only jar files into the build artifact
- name: Copy Build Results to Temp
run: |
mkdir -p tmp/
cp imgui-app/build/libs/*.jar tmp/
cp imgui-binding/build/libs/*.jar tmp/
cp imgui-lwjgl3/build/libs/*.jar tmp/
- name: Upload Artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: java-libraries
path: |
imgui-app/build/libs/*.jar
imgui-binding/build/libs/*.jar
imgui-lwjgl3/build/libs/*.jar
path: tmp/*.jar

build-natives:
name: Build Native (${{ matrix.target.type }}${{ matrix.freetype && ', freetype' || '' }})
name: Build Native (${{ matrix.target.os }} - ${{ matrix.target.type }})
needs: build-java
strategy:
fail-fast: false
matrix:
freetype: [ true, false ]
target:
- os: ubuntu-latest
type: windows
expected: /tmp/imgui/libsNative/windows64/imgui-java64.dll
- os: ubuntu-latest
type: linux
expected: /tmp/imgui/libsNative/linux64/libimgui-java64.so
- os: ubuntu-latest
type: windows
- os: macos-latest
type: macos
expected: /tmp/imgui/libsNative/macosx64/libimgui-java64.dylib
- os: macos-latest
type: macosarm64
expected: /tmp/imgui/libsNative/macosxarm64/libimgui-javaarm64.dylib
runs-on: ${{ matrix.target.os }}
steps:
- name: Checkout Repository and Submodules
Expand All @@ -63,58 +72,44 @@ jobs:
distribution: liberica
cache: gradle

- name: Ant Version
run: ant -version

- name: Install MinGW-w64/GCC/G++ (Linux & Windows)
if: matrix.target.os == 'ubuntu-latest'
- name: Install Dependencies (for Windows build)
if: matrix.target.type == 'windows'
run: sudo apt install mingw-w64

- name: FreeType - Install (Linux)
if: matrix.target.os == 'ubuntu-latest' && matrix.target.type == 'linux' && matrix.freetype == true
run: sudo apt install libfreetype6-dev

- name: FreeType - Install (Windows)
if: matrix.target.os == 'ubuntu-latest' && matrix.target.type == 'windows' && matrix.freetype == true
run: |
sudo mkdir /freetype
sudo tar -xzf ./vendor/freetype-2.12.1.tar.gz -C /freetype --strip-components=1
cd /freetype
sudo ./configure --with-zlib=no --with-bzip2=no --with-png=no --with-harfbuzz=no --with-brotli=no --host=x86_64-w64-mingw32 --prefix=/usr/x86_64-w64-mingw32
sudo make
sudo make install
- name: FreeType - Install (MacOS)
if: matrix.target.os == 'macos-latest' && matrix.freetype == true
run: |
sudo mkdir /opt/freetype
sudo tar -xzf ./vendor/freetype-2.12.1.tar.gz -C /opt/freetype --strip-components=1
cd /opt/freetype
sudo ./configure CFLAGS="-arch arm64 -arch x86_64" --with-zlib=no --with-bzip2=no --with-png=no --with-harfbuzz=no --with-brotli=no
sudo make
sudo make install
- name: Build
run: ./gradlew imgui-binding:generateLibs -Denvs=${{ matrix.target.type }} -Dfreetype=${{ matrix.freetype }}
run: |
chmod +x buildSrc/scripts/build.sh
buildSrc/scripts/build.sh ${{ matrix.target.type }}
- name: Upload Artifacts
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.freetype && 'native-libraries-with-freetype' || 'native-libraries' }}
if-no-files-found: error
path: ${{ matrix.target.expected }}
name: native-library-${{ matrix.target.type }}
path: /tmp/imgui/dst/

# This required to pack all native libraries into single archive
archive-natives:
name: Archive Natives
runs-on: ubuntu-latest
needs: build-natives
steps:
- name: Merge Artifacts
uses: actions/upload-artifact/merge@v4
with:
name: native-libraries
pattern: native-library-*

update-bin:
name: Update Binaries
if: github.ref == 'refs/heads/main' && !github.event.repository.fork # runs only on the main branch and not forks (sometimes people do PRs from the main branch)
runs-on: ubuntu-latest
needs: build-natives
needs: archive-natives
steps:
- name: Checkout Repository
uses: actions/checkout@v4

- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
path: /tmp/artifacts

Expand All @@ -133,9 +128,7 @@ jobs:
- name: Update
if: steps.cmp-binding-hash.outcome != 'success'
run: |
mv /tmp/artifacts/native-libraries/* bin/
mv /tmp/artifacts/native-libraries-with-freetype/* bin/freetype/
run: mv /tmp/artifacts/native-libraries/* bin/

- name: Commit
if: steps.cmp-binding-hash.outcome != 'success'
Expand All @@ -148,7 +141,7 @@ jobs:
name: Release
if: startsWith(github.ref, 'refs/tags/v') # if tag starts with "v"
runs-on: ubuntu-latest
needs: [ build-java, build-natives ]
needs: [ build-java, archive-natives ]
steps:
- name: Checkout Repository
uses: actions/checkout@v4
Expand All @@ -163,15 +156,14 @@ jobs:
cache: gradle

- name: Download Artifacts
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
path: out/artifacts

- name: Zip Artifacts
run: |
mkdir out/archives
zip -rj out/archives/native-libraries out/artifacts/native-libraries
zip -rj out/archives/native-libraries-with-freetype out/artifacts/native-libraries-with-freetype
zip -rj out/archives/java-libraries out/artifacts/java-libraries
- name: Publish
Expand Down
91 changes: 23 additions & 68 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ To understand how to use ImGui Java - read official [documentation](https://gith
Binding adopts C++ API for Java, but almost everything can be used in the same manner.

ImGui Java has a ready to use implementation for GLFW and OpenGL API using [LWJGL3](https://www.lwjgl.org/) library. See `imgui-lwjgl3` module.<br>
Implementation is optional, yet optional to use. Advantage of Dear ImGui is total portability, so feel free to copy-paste classes or write your own implementations.
Implementation is optional to use. Advantage of Dear ImGui is total portability, so feel free to copy-paste classes or write your own implementations.

Additionally, there is an `imgui-app` module, which provides **a high abstraction layer**.<br>
It hides all low-level code under one class to extend. With it, you can build your GUI application instantly.
Expand Down Expand Up @@ -70,6 +70,10 @@ Gradle and Maven dependencies could be used for this purpose as well.
Take a note, that integration itself is a very flexible process. It could be done in one way or another. If you just need a framework for your GUI - use [Application](#application) module.
Otherwise, if you need more control, the best way is not just to repeat steps, but to understand what each step does.

### For macOS M-chip users

The macOS version of the binding is compiled as a universal binary. This means you can use it on both x86_64 and aarch64 platforms without any additional actions.

## Application

If you don't care about OpenGL and other low-level stuff, then you can use application layer from `imgui-app` module.
Expand Down Expand Up @@ -176,7 +180,6 @@ For simplicity, example of dependencies for Gradle / Maven only shows how to add
| imgui-java-natives-windows | Windows |
| imgui-java-natives-linux | Linux |
| imgui-java-natives-macos | macOS |
| imgui-java-natives-macos-arm64 | macOS-arm64 |

Take a note, that you also need to add dependencies to [LWJGL](https://www.lwjgl.org/) library. Examples below shows how to do it as well.

Expand Down Expand Up @@ -282,10 +285,10 @@ dependencies {
<summary><b>Raw Jars</b></summary>

1. Go to the [release page](https://github.com/SpaiR/imgui-java/releases/latest);
2. Download `java-libraries.zip` and `native-libraries.zip` (`native-libraries-with-freetype.zip` for FreeType font rendering);
2. Download `java-libraries.zip` and `native-libraries.zip`;
3. Get `imgui-binding-${version}.jar` and `imgui-lwjgl3-${version}.jar` from `java-libraries`, and binary libraries for required OS from `native-libraries` archive;
4. Add jars to your classpath;
5. Provide a VM option with location of files from the `native-libraries` (or `native-libraries-with-freetype`) archive.
5. Provide a VM option with location of files from the `native-libraries` archive.

VM option example:
- **-Dimgui.library.path=_${path}_**
Expand All @@ -307,7 +310,6 @@ If using Java 9 modules, ImGui Java has Automatic Module Names:
| imgui-java-natives-windows | imgui.natives.windows |
| imgui-java-natives-linux | imgui.natives.linux |
| imgui-java-natives-macos | imgui.natives.macos |
| imgui-java-natives-macos-arm64 | imgui.natives.macos-arm64 |

## Extensions

Expand All @@ -331,67 +333,14 @@ See examples in the `example` module for more information about how to use them.

## Freetype

By default, Dear ImGui uses stb-truetype to render fonts. Yet there is an option to use FreeType font renderer.
Go to the [imgui_freetype](https://github.com/ocornut/imgui/tree/256594575d95d56dda616c544c509740e74906b4/misc/freetype) to read about the difference.
Binding has this option too. Freetype especially useful when you use custom font with small (~<16px) size.
If you use the default font or a large font, stb will be fine for you.

There are two types of precompiled binaries: 1. with stb (the default one) 2. with freetype.
You can decide by yourself, which kind of libraries for any system you want to use.

Take a note, that for Linux and macOS users using of freetype will add a dependency to the `libfreetype` itself.
This is not the case for Windows users, since `dll` binaries are compiled fully statically and already include freetype in themselves.
By default, Dear ImGui uses stb-truetype to render fonts. However, there is an option to use the FreeType font renderer.
To learn about the differences, visit the [imgui_freetype](https://github.com/ocornut/imgui/tree/256594575d95d56dda616c544c509740e74906b4/misc/freetype) page.

**For fully portable application** use default binaries.<br>
You can still use freetype binaries for Windows builds without worry though.
This binding also supports the FreeType option.
FreeType is statically pre-compiled into the library, meaning it is **enabled by default** and there is no option to disable it.
Therefore, you can freely use `ImGuiFreeTypeBuilderFlags` in your font configuration.

**For better fonts** use freetype binaries.<br>
Don't forget to make clear for your Linux/Mac users, that they will need to install freetype on their systems as well.

### Dependencies

![Maven Central](https://img.shields.io/maven-central/v/io.github.spair/imgui-java-binding?color=green&label=version&style=flat-square)

Use the same native libraries as you would, but with `-ft` suffix in the end.

<details>
<summary><b>Modified Gradle Example</b></summary>

```
repositories {
mavenCentral()
}

ext {
lwjglVersion = '3.3.3'
imguiVersion = "${version}"
}

dependencies {
implementation platform("org.lwjgl:lwjgl-bom:$lwjglVersion")

['', '-opengl', '-glfw'].each {
implementation "org.lwjgl:lwjgl$it:$lwjglVersion"
implementation "org.lwjgl:lwjgl$it::natives-windows"
}
implementation "io.github.spair:imgui-java-binding:$imguiVersion"
implementation "io.github.spair:imgui-java-lwjgl3:$imguiVersion"
// This is the main difference
implementation "io.github.spair:imgui-java-natives-windows-ft:$imguiVersion"
}
```
</details>

| Native Binaries With FreeType | System |
|-----------------------------------|-------------|
| imgui-java-natives-windows-ft | Windows |
| imgui-java-natives-linux-ft | Linux |
| imgui-java-natives-macos-ft | macOS |
| imgui-java-natives-macos-arm64-ft | macOS-arm64 |

If you're using raw dll/so files, go to the [release page](https://github.com/SpaiR/imgui-java/releases/latest) and use libraries from the `native-libraries-with-freetype.zip` archive.
If you prefer not to use the FreeType font renderer, you will need to build your own binaries and use them instead.

# Binding Notice

Expand All @@ -408,7 +357,7 @@ Read [javadoc](https://javadoc.io/doc/io.github.spair/imgui-java-binding) and so

Ensure you've downloaded git submodules. That could be achieved:
- When cloning the repository: `git clone --recurse-submodules https://github.com/SpaiR/imgui-java.git`
- When the repository cloned: `git submodule init` + `git submodule update`
- When the repository cloned: `git submodule init` and `git submodule update`

### Windows

Expand All @@ -418,6 +367,7 @@ Ensure you've downloaded git submodules. That could be achieved:
* Mingw-w64 (recommended way: use [MSYS2](https://www.msys2.org/) and install [mingw-w64-x86_64-toolchain](https://packages.msys2.org/group/mingw-w64-x86_64-toolchain) group)
- Build with: `./gradlew imgui-binding:generateLibs -Denvs=windows -Dlocal`
- Run with: `./gradlew example:run -PlibPath="../imgui-binding/build/libsNative/windows64"`
- Always use `-Dlocal` flag.

### Linux

Expand All @@ -431,15 +381,20 @@ Ensure you've downloaded git submodules. That could be achieved:
- Build with: `./gradlew imgui-binding:generateLibs -Denvs=macos -Dlocal`
- Run with: `./gradlew example:run -PlibPath=../imgui-binding/build/libsNative/macosx64`

### macOS-arm64
### macOS (arm64)

- Check dependencies from "Linux" section and make sure you have them installed.
- Build with: `./gradlew imgui-binding:generateLibs -Denvs=macosarm64 -Dlocal`
- Run with: `./gradlew example:run -PlibPath=../imgui-binding/build/libsNative/macosxarm64`

In `envs` parameter next values could be used `windows`, `linux` or `macos` or `macosarm64`.<br>
In `envs` parameter next values could be used `windows`, `linux` or `macos` or `macosarm64`.

`-Dlocal` is optional and means that natives will be built under the `./imgui-binding/build/` folder. Otherwise `/tmp/imgui` folder will be used.
On Windows always use local build.

## Freetype

To build a version of the libraries with FreeType, you need to run the `buildSrc/scripts/vendor_freetype.sh` script first.
This script configures the FreeType library to be statically compiled into your project.

# License

Expand Down
34 changes: 27 additions & 7 deletions bin/README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
Folder contains libraries used by the binding and `binding.sha1` sum of the `imgui-binding/src/main` directory libraries has been built upon.
### Overview

Provide `imgui.library.path` (or `java.library.path`) VM option to the folder with one of those file (ex: `-Dimgui.library.path=./folder/path`).
In the same way you can use 'java.library.path' option instead.
The folder contains libraries used by the binding and the `binding.sha1` checksum for the `imgui-binding/src/main` directory that the libraries are built upon. These libraries are utilized during the release process.

By default, binding expects `imgui-java64` file name.
You can change that by using `imgui.library.name` VM option (ex: `-Dimgui.library.name=custom-lib-name.dll`).
### Specifying the Library Path

To specify the folder containing these files, provide the `imgui.library.path` (or `java.library.path`) VM option. For example:
```
-Dimgui.library.path=./folder/path
```
You can also use the `java.library.path` option in the same manner.

### Changing the Library Name

By default, the binding expects the file name `imgui-java64`. You can change this by using the `imgui.library.name` VM option. For example:
```
-Dimgui.library.name=custom-lib-name.dll
```

### Expected Library File Names

The expected library file names for different operating systems are:

| OS | Library |
|---------|-----------------------|
| Windows | imgui-java64.dll |
| Linux | libimgui-java64.so |
| macOS | libimgui-java64.dylib |

Freetype directory contains same libraries, but with Freetype support.
### Additional Information

- All libraries include statically compiled **FreeType**.
- The macOS version is a universal library and support x86_64 and arm64 architectures.

### Continuous Integration

Hash sum in the `binding.sha1` file is used in CI to see, if there is a need to update native binaries.
The hash sum in the `binding.sha1` file is used in continuous integration (CI) to determine if there is a need to update the native binaries.
Binary file removed bin/freetype/imgui-java64.dll
Binary file not shown.
Binary file removed bin/freetype/libimgui-java64.dylib
Binary file not shown.
Binary file removed bin/freetype/libimgui-java64.so
Binary file not shown.
Binary file removed bin/freetype/libimgui-javaarm64.dylib
Binary file not shown.
Binary file removed bin/libimgui-javaarm64.dylib
Binary file not shown.
Loading

0 comments on commit 46c008e

Please sign in to comment.