Files
imgui-java/buildSrc/src/main/groovy/tool/generator/GenerateLibs.groovy
T
SpaiR e70576f322 feat(api): bump Dear ImGui from 1.88 to 1.89.9
resolves #134
resolves #135
resolves #145
resolves #220
resolves #310

- Bump imgui-node-editor to the latest coomit
- Bump implot from 0.13 to 0.16
2025-01-29 15:24:43 +02:00

202 lines
8.2 KiB
Groovy

package tool.generator
import com.badlogic.gdx.jnigen.*
import com.badlogic.gdx.utils.Architecture
import com.badlogic.gdx.utils.Os
import groovy.transform.CompileStatic
import org.gradle.api.DefaultTask
import org.gradle.api.file.CopySpec
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
@CompileStatic
class GenerateLibs extends DefaultTask {
private static final String[] INCLUDES = [
'include/imgui',
'include/imnodes',
'include/imgui-node-editor',
'include/imguizmo',
'include/implot',
// 'include/ImGuiColorTextEdit',
// 'include/ImGuiFileDialog',
'include/imgui_club/imgui_memory_editor',
'include/imgui-knobs'
]
@Internal
String group = 'build'
@Internal
String description = 'Generate imgui-java native binaries.'
private final String[] buildEnvs = System.getProperty('envs')?.split(',')
private final boolean forWindows = buildEnvs?.contains('windows')
private final boolean forLinux = buildEnvs?.contains('linux')
private final boolean forMac = buildEnvs?.contains('macos')
private final boolean forMacArm64 = buildEnvs?.contains('macosarm64')
private final boolean isLocal = System.properties.containsKey('local')
private final boolean withFreeType = Boolean.valueOf(System.properties.getProperty('freetype', 'false'))
private final String sourceDir = project.file('src/generated/java')
private final String classpath = project.file('build/classes/java/main')
private final String rootDir = (isLocal ? project.buildDir.path : '/tmp/imgui')
private final String jniDir = "$rootDir/jni"
private final String tmpDir = "$rootDir/tmp"
private final String libsDirName = 'libsNative'
@TaskAction
void generate() {
println 'Generating Native Libraries...'
println "Build targets: $buildEnvs"
println "Local: $isLocal"
println "FreeType: $withFreeType"
println '====================================='
if (!buildEnvs) {
throw new IllegalStateException('No build targets')
}
new File(jniDir).deleteDir()
new File(tmpDir).deleteDir()
new File("$rootDir/$libsDirName").deleteDir()
// Generate h/cpp files for JNI
new NativeCodeGenerator().generate(sourceDir, classpath, jniDir)
// Copy ImGui h/cpp files
project.copy { CopySpec spec ->
INCLUDES.each {
spec.from(project.rootProject.file(it)) { CopySpec s -> s.include('*.h', '*.cpp', '*.inl') }
}
spec.from(project.rootProject.file('imgui-binding/src/main/native'))
spec.into(jniDir)
spec.duplicatesStrategy = DuplicatesStrategy.INCLUDE // Allows for duplicate imconfig.h, we ensure the correct one is copied below
}
// Ensure we overwrite imconfig.h with our own
project.copy { CopySpec spec ->
spec.from(project.rootProject.file('imgui-binding/src/main/native/imconfig.h'))
spec.into(jniDir)
}
if (withFreeType) {
project.copy { CopySpec spec ->
spec.from(project.rootProject.file('include/imgui/misc/freetype')) { CopySpec it -> it.include('*.h', '*.cpp') }
spec.into("$jniDir/misc/freetype")
}
// Since we give a possibility to build library without enabled freetype - define should be set like that.
replaceSourceFileContent("imconfig.h", "//#define IMGUI_ENABLE_FREETYPE", "#define IMGUI_ENABLE_FREETYPE")
// Binding specific behavior to handle FreeType.
// By defining IMGUI_ENABLE_FREETYPE, Dear ImGui will default to using the FreeType font renderer.
// However, we modify the source code to ensure that, even with this, the STB_TrueType renderer is used instead.
// To use the FreeType font renderer, it must be explicitly forced on the atlas manually.
replaceSourceFileContent("imgui_draw.cpp", "ImGuiFreeType::GetBuilderForFreeType()", "ImFontAtlasGetBuilderForStbTruetype()")
}
// Copy dirent for ImGuiFileDialog
project.copy { CopySpec spec ->
spec.from(project.rootProject.file('include/ImGuiFileDialog/dirent')) { CopySpec s -> s.include('*.h', '*.cpp', '*.inl') }
spec.into(jniDir + '/dirent')
}
// Generate platform dependant ant configs and header files
def buildConfig = new BuildConfig('imgui-java', tmpDir, libsDirName, jniDir)
BuildTarget[] buildTargets = []
if (forWindows) {
def win64 = BuildTarget.newDefaultTarget(Os.Windows, Architecture.Bitness._64)
addFreeTypeIfEnabled(win64)
buildTargets += win64
}
if (forLinux) {
def linux64 = BuildTarget.newDefaultTarget(Os.Linux, Architecture.Bitness._64)
addFreeTypeIfEnabled(linux64)
buildTargets += linux64
}
if (forMac) {
buildTargets += createMacTarget(Architecture.x86)
}
if (forMacArm64) {
buildTargets += createMacTarget(Architecture.ARM)
}
new AntScriptGenerator().generate(buildConfig, buildTargets)
// Generate native libraries
// Comment/uncomment lines with OS you need.
def commonParams = ['-v', '-Dhas-compiler=true', '-Drelease=true', 'clean', 'postcompile'] as String[]
if (forWindows)
BuildExecutor.executeAnt(jniDir + '/build-windows64.xml', commonParams)
if (forLinux)
BuildExecutor.executeAnt(jniDir + '/build-linux64.xml', commonParams)
if (forMac)
BuildExecutor.executeAnt(jniDir + '/build-macosx64.xml', commonParams)
if (forMacArm64)
BuildExecutor.executeAnt(jniDir + '/build-macosxarm64.xml', commonParams)
BuildExecutor.executeAnt(jniDir + '/build.xml', '-v', 'pack-natives')
if (forWindows)
checkLibExist("windows64/imgui-java64.dll")
if (forLinux)
checkLibExist("linux64/libimgui-java64.so")
if (forMac)
checkLibExist("macosx64/libimgui-java64.dylib")
if (forMacArm64)
checkLibExist("macosxarm64/libimgui-java64.dylib")
}
void checkLibExist(String libName) {
def path = new File("$rootDir/$libsDirName/$libName")
if (!path.exists()) {
logger.error("Failed to build $libName!")
throw new IllegalStateException("$path does not exist")
}
}
BuildTarget createMacTarget(Architecture arch) {
def minMacOsVersion = '10.15'
def macTarget = BuildTarget.newDefaultTarget(Os.MacOsX, Architecture.Bitness._64, arch)
macTarget.libName = "libimgui-java64.dylib" // Lib for arm64 will be named the same for consistency.
macTarget.cppFlags += ' -std=c++14'
macTarget.cppFlags = macTarget.cppFlags.replace('10.7', minMacOsVersion)
macTarget.linkerFlags = macTarget.linkerFlags.replace('10.7', minMacOsVersion)
addFreeTypeIfEnabled(macTarget)
return macTarget
}
void addFreeTypeIfEnabled(BuildTarget target) {
if (!withFreeType) {
return
}
def freetypeVendorDir = project.rootProject.file('build/vendor/freetype')
if (!freetypeVendorDir.exists()) {
logger.error("$freetypeVendorDir doesn't exist! Run 'buildSrc/scripts/vendor_freetype.sh' for your platform beforehand!")
throw new IllegalStateException("Unable to build library for FreeType")
}
target.cppFlags += " -I$freetypeVendorDir/include"
target.linkerFlags += " -L${project.rootProject.file("$freetypeVendorDir/lib")}"
target.libraries += ' -lfreetype'
}
void replaceSourceFileContent(String fileName, String replaceWhat, String replaceWith) {
def sourceFile = new File("$jniDir/$fileName")
def sourceTxt = sourceFile.text
def sourceTxtModified = sourceTxt.replace(replaceWhat, replaceWith)
if (sourceTxt == sourceTxtModified) {
throw new IllegalStateException("Unable to replace [$fileName] with content [$replaceWith]!")
}
sourceFile.text = sourceTxtModified
}
}