|
#!/bin/bash |
|
#---- project parameters |
|
project_name=[ProjectName] |
|
project_version=[ProjectVersion] |
|
main_class=[ProjectMainClass] |
|
vendor_name="[PorojectVendorName]" |
|
author_name="[AuthorName]<[AuthorEmail]>" |
|
SOURCE_VERSION="25" |
|
JAR_OPTS="-Xmx512m --enable-native-access=ALL-UNNAMED" |
|
#--- external dependencies version |
|
LWJGL_VERSION="3.3.3" |
|
JINPUT_VERSION="2.0.10" |
|
|
|
# Detect OS and architecture |
|
OS_NAME=$(uname -s | tr '[:upper:]' '[:lower:]') |
|
ARCH=$(uname -m | tr '[:upper:]' '[:lower:]') |
|
case "$OS_NAME" in |
|
linux*) |
|
OS="linux" ;; |
|
darwin*) |
|
if [[ "$ARCH" == "arm64" ]]; then |
|
OS="macos-arm64" |
|
else |
|
OS="macos" |
|
fi |
|
;; |
|
msys*|mingw*|cygwin*) |
|
OS="windows" ;; |
|
*) |
|
OS="linux" ;; # default to linux |
|
esac |
|
|
|
# Define natives based on OS |
|
NATIVES_SUFFIX="natives-${OS}" |
|
|
|
# JInput natives suffix mapping |
|
case "$OS" in |
|
linux) |
|
JINPUT_NATIVES="natives-linux" ;; |
|
macos|macos-arm64) |
|
JINPUT_NATIVES="natives-osx" ;; |
|
windows) |
|
JINPUT_NATIVES="natives-windows" ;; |
|
*) |
|
JINPUT_NATIVES="natives-linux" ;; |
|
esac |
|
|
|
# detect OS type to set the classpath separator |
|
if [[ "$OSTYPE" == "linux"* ]] || [[ "$OSTYPE" == "darwin"* ]]; then |
|
FS=":" |
|
else |
|
FS=";" |
|
fi |
|
|
|
# LWJGL Jars |
|
LWJGL_MODULES=("lwjgl" "lwjgl-glfw" "lwjgl-opengl" "lwjgl-stb") |
|
LWJGL_JARS="" |
|
JARS="" |
|
|
|
# Function to download JAR from Maven Central |
|
download_jar() { |
|
local group=$1 |
|
local artifact=$2 |
|
local version=$3 |
|
local classifier=$4 |
|
local dest_dir=$5 |
|
local url="https://repo1.maven.org/maven2/${group//.//}/${artifact}/${version}/${artifact}-${version}${classifier:+-$classifier}.jar" |
|
local filename="${artifact}-${version}${classifier:+-$classifier}.jar" |
|
local dest_path="${dest_dir}/${filename}" |
|
|
|
if [ ! -f "$dest_path" ]; then |
|
echo "Downloading ${filename}..." |
|
mkdir -p "$dest_dir" |
|
if command -v curl >/dev/null 2>&1; then |
|
curl -L -o "$dest_path" "$url" |
|
elif command -v wget >/dev/null 2>&1; then |
|
wget -O "$dest_path" "$url" |
|
else |
|
echo "Error: Neither curl nor wget is available for downloading." |
|
exit 1 |
|
fi |
|
else |
|
echo "${filename} already exists." |
|
fi |
|
} |
|
|
|
# Download LWJGL jars if missing |
|
LWJGL_DIR="libs/lwjgl" |
|
mkdir -p "$LWJGL_DIR" |
|
|
|
for module in "${LWJGL_MODULES[@]}"; do |
|
download_jar "org.lwjgl" "$module" "$LWJGL_VERSION" "" "$LWJGL_DIR" |
|
download_jar "org.lwjgl" "$module" "$LWJGL_VERSION" "$NATIVES_SUFFIX" "$LWJGL_DIR" |
|
|
|
jar_path="${LWJGL_DIR}/${module}-${LWJGL_VERSION}.jar" |
|
natives_path="${LWJGL_DIR}/${module}-${LWJGL_VERSION}-${NATIVES_SUFFIX}.jar" |
|
|
|
LWJGL_JARS="${LWJGL_JARS}${LWJGL_JARS:+${FS}}${jar_path}${FS}${natives_path}" |
|
JARS="${JARS}${JARS:+ }${jar_path} ${natives_path}" |
|
done |
|
|
|
# Download JInput jars if missing |
|
JINPUT_DIR="libs/jinput" |
|
mkdir -p "$JINPUT_DIR" |
|
|
|
# JInput core JAR |
|
download_jar "net.java.jinput" "jinput" "$JINPUT_VERSION" "" "$JINPUT_DIR" |
|
JINPUT_JAR="${JINPUT_DIR}/jinput-${JINPUT_VERSION}.jar" |
|
JARS="${JARS}${JARS:+ }${JINPUT_JAR}" |
|
|
|
# JInput natives (all platforms in one JAR) |
|
download_jar "net.java.jinput" "jinput" "$JINPUT_VERSION" "natives-all" "$JINPUT_DIR" |
|
JINPUT_NATIVES_JAR="${JINPUT_DIR}/jinput-${JINPUT_VERSION}-natives-all.jar" |
|
JARS="${JARS}${JARS:+ }${JINPUT_NATIVES_JAR}" |
|
|
|
# Add JInput to external jars |
|
EXTERNAL_JARS="${LWJGL_JARS}${FS}${JINPUT_JAR}${FS}${JINPUT_NATIVES_JAR}" |
|
# |
|
#--- DO NOT CHANGE THE FOLLOWING LINES --- |
|
# |
|
main_class_array=($main_class) |
|
num_main_classes=${#main_class_array[@]} |
|
SRC=./src |
|
LIBS=./libs |
|
TARGET=./target |
|
BUILD=${TARGET}/build |
|
CLASSES=${TARGET}/classes |
|
RESOURCES=${SRC}/main/resources |
|
SOURCE_ENCODING="UTF-8" |
|
JARS=libs/dependencies/ |
|
COMPILATION_OPTS="-Xlint:unchecked -Xlint:deprecation -parameters" |
|
# add your test execution commands here |
|
TEST_CLASSES=${TARGET}/test-classes |
|
TEST_RESOURCES=${SRC}/test/resources |
|
LIB_TEST=$LIBS/junit-platform-console-standalone-6.0.0.jar |
|
# define colors |
|
RED='\033[0;31m' |
|
GREEN='\033[0;32m' |
|
BLUE='\033[0;34m' |
|
NC='\033[0m' |
|
#---- process buid |
|
GIT_COMMIT_ID=$(git rev-parse HEAD) |
|
JAVA_BUILD=$(java --version | head -1 | cut -f2 -d' ') |
|
#---- check SDKMAN |
|
REQUIRED_JAVA_VERSION=$SOURCE_VERSION |
|
JAVA_BIN=$(command -v java 2>/dev/null) |
|
JAVA_VERSION_DETECTED=$($JAVA_BIN -version 2>&1 | awk -F '[\"_]' '/version/ {print $2}' | cut -d'.' -f1) |
|
if [ -z "$JAVA_BIN" ] || [ "$JAVA_VERSION_DETECTED" != "$REQUIRED_JAVA_VERSION" ]; then |
|
echo -e "${RED}Java n'est pas installé. Tentative d'installation de Java $REQUIRED_JAVA_VERSION avec SDKMAN.${NC}" |
|
# Ensure the `sdk` command is available by sourcing SDKMAN init if installed |
|
if [ -z "$(command -v sdk 2>/dev/null)" ] && [ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]; then |
|
# shellcheck source=/dev/null |
|
source "$HOME/.sdkman/bin/sdkman-init.sh" |
|
if [ -f .sdkmanrc ]; then |
|
echo "Install SDKMAN environment" |
|
sdk env install |
|
sdk env use |
|
echo "done." |
|
fi |
|
fi |
|
else |
|
echo -e "${GREEN}Java détecté: version $JAVA_VERSION_DETECTED${NC}" |
|
fi |
|
# Prepare Build |
|
rm -vrf target/ |
|
find $SRC/main/java $RESOURCES -name "*.java" |
|
mkdir -vp ${TARGET}/{classes,build/libs} |
|
# Copy runtime dependencies |
|
echo "copy runtime dependencies to ${TARGET}/build/libs" |
|
cp ${LWJGL_DIR}/*.jar ${TARGET}/build/libs/ |
|
cp ${JINPUT_DIR}/*.jar ${TARGET}/build/libs/ |
|
|
|
# Extract JInput native libraries |
|
NATIVES_DIR="${TARGET}/build/natives" |
|
mkdir -p "${NATIVES_DIR}" |
|
echo "Extracting JInput native libraries to ${NATIVES_DIR}..." |
|
unzip -o -j "${JINPUT_DIR}/jinput-${JINPUT_VERSION}-natives-all.jar" "*.so" "*.dll" "*.dylib" "*.jnilib" -d "${NATIVES_DIR}" 2>/dev/null || true |
|
|
|
# Compile sources |
|
javac ${COMPILATION_OPTS} -cp "${TARGET}/build/libs/*" $(find $SRC/main/java $RESOURCES -name "*.java") -d ${CLASSES} |
|
# create MANIFEST file |
|
cp -vr $RESOURCES/* $CLASSES |
|
echo "build jar..." |
|
for app in "${main_class_array[@]}"; do |
|
if [ $num_main_classes -eq 1 ]; then |
|
jar_name="${project_name}-${project_version}.jar" |
|
else |
|
jar_name="${project_name}-$app-${project_version}.jar" |
|
fi |
|
mkdir -p ${TARGET}/META-INF |
|
echo ">> for ${project_name}.$app..." |
|
echo """ |
|
Manifest-Version: ${project_name} |
|
Main-Class: ${app} |
|
Class-Path: ${JARS} |
|
Created-By: ${JAVA_BUILD} |
|
Implementation-Title: ${project_name} |
|
Implementation-Version: ${project_version}-build_${GIT_COMMIT_ID:0:12} |
|
Implementation-Vendor: ${vendor_name} |
|
Implementation-Author: ${author_name} |
|
""" >>${TARGET}/META-INF/MANIFEST.MF |
|
jar cvfe ${TARGET}/build/${jar_name} $app -C ${CLASSES} . |
|
# create run script |
|
if [[ "$OS" == "windows" ]]; then |
|
script_name="${project_name}.bat" |
|
echo "create run script ${script_name} ..." |
|
rm -f ${script_name} |
|
echo """@echo off |
|
java -Djava.library.path=\"${TARGET}/build/natives\" -cp \"${TARGET}/build/libs/*${FS}${TARGET}/build/${jar_name}\" core.App %* |
|
""" >${script_name} |
|
else |
|
script_name="${project_name}.sh" |
|
echo "create run script ${script_name} ..." |
|
rm -f ${script_name} |
|
echo """#!/bin/bash |
|
java -Djava.library.path=\"${TARGET}/build/natives\" -cp \"${TARGET}/build/libs/*:${TARGET}/build/${jar_name}\" core.App \$@ |
|
""" >${script_name} |
|
chmod +x ${script_name} |
|
echo "done." |
|
fi |
|
echo "done." |
|
done |
|
if ([ "$1" == "jre" ]); then |
|
echo "Creating minimal JRE..." |
|
JRE_DIR="${TARGET}/build/jre" |
|
JRE_MODULES="java.base,java.datatransfer,java.xml,java.prefs,java.desktop,java.logging,jdk.unsupported" |
|
|
|
# Remove existing JRE if present |
|
rm -rf "${JRE_DIR}" |
|
|
|
# Create minimal JRE with jlink |
|
echo "Running jlink to create minimal JRE with modules: ${JRE_MODULES}" |
|
jlink --no-header-files \ |
|
--no-man-pages \ |
|
--compress=zip-6 \ |
|
--strip-debug \ |
|
--add-modules "${JRE_MODULES}" \ |
|
--output "${JRE_DIR}" |
|
|
|
if [ $? -eq 0 ]; then |
|
echo -e "${GREEN}Minimal JRE created successfully in ${JRE_DIR}${NC}" |
|
echo "JRE size: $(du -sh ${JRE_DIR} | cut -f1)" |
|
|
|
# Create self-contained launcher script in target/build |
|
jar_name="${project_name}-${project_version}.jar" |
|
|
|
if [[ "$OS" == "windows" ]]; then |
|
launcher_name="${TARGET}/build/${project_name}.bat" |
|
echo "Creating launcher script ${launcher_name} ..." |
|
cat > "${launcher_name}" << 'EOFBAT' |
|
@echo off |
|
setlocal |
|
set SCRIPT_DIR=%~dp0 |
|
"%SCRIPT_DIR%jre\bin\java" -Djava.library.path="%SCRIPT_DIR%natives" -cp "%SCRIPT_DIR%libs\*;%SCRIPT_DIR%JARNAME" core.App %* |
|
endlocal |
|
EOFBAT |
|
sed -i "s/JARNAME/${jar_name}/g" "${launcher_name}" |
|
else |
|
launcher_name="${TARGET}/build/${project_name}.sh" |
|
echo "Creating launcher script ${launcher_name} ..." |
|
cat > "${launcher_name}" << 'EOFSH' |
|
#!/bin/bash |
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" |
|
"${SCRIPT_DIR}/jre/bin/java" -Djava.library.path="${SCRIPT_DIR}/natives" -cp "${SCRIPT_DIR}/libs/*:${SCRIPT_DIR}/JARNAME" core.App "$@" |
|
EOFSH |
|
sed -i "s/JARNAME/${jar_name}/g" "${launcher_name}" |
|
chmod +x "${launcher_name}" |
|
fi |
|
|
|
echo -e "${GREEN}Self-contained launcher created: ${launcher_name}${NC}" |
|
echo "" |
|
echo -e "${GREEN}Distribution package ready in ${TARGET}/build/${NC}" |
|
echo "Contents:" |
|
echo " - jre/ : Minimal Java Runtime" |
|
echo " - libs/ : Dependencies" |
|
echo " - natives/ : Native libraries" |
|
echo " - ${jar_name} : Application JAR" |
|
echo " - ${project_name}.sh : Launcher script" |
|
echo "" |
|
echo "Total size: $(du -sh ${TARGET}/build | cut -f1)" |
|
|
|
# Create distribution zip archive |
|
echo "" |
|
echo "Creating distribution archive..." |
|
DIST_NAME="${project_name}-${project_version}-${OS}" |
|
DIST_ZIP="${TARGET}/${DIST_NAME}.zip" |
|
rm -f "${DIST_ZIP}" |
|
|
|
# Create zip from target/build directory |
|
pushd "${TARGET}/build" > /dev/null |
|
zip -r "../${DIST_NAME}.zip" . -x "*.zip" |
|
popd > /dev/null |
|
|
|
if [ -f "${DIST_ZIP}" ]; then |
|
echo -e "${GREEN}Distribution archive created: ${DIST_ZIP}${NC}" |
|
echo "Archive size: $(du -sh ${DIST_ZIP} | cut -f1)" |
|
else |
|
echo -e "${RED}Failed to create distribution archive${NC}" |
|
fi |
|
else |
|
echo -e "${RED}Failed to create minimal JRE${NC}" |
|
exit 1 |
|
fi |
|
echo "done." |
|
fi |
|
|
|
if ([ "$1" == "test" ]); then |
|
echo "Run tests..." |
|
|
|
echo -e "|_ ${BLUE}6. Execute tests${NC}..." |
|
echo "> from : ${SRC}/test" |
|
echo "> to : ${TARGET}/test-classes" |
|
mkdir -p ${TARGET}/test-classes |
|
echo "copy test resources" |
|
cp -r ./$RESOURCES/* $TEST_CLASSES |
|
cp -r ./$TEST_RESOURCES/* $TEST_CLASSES |
|
echo "compile test classes" |
|
#list test sources |
|
find ${SRC}/main -name '*.java' >${TARGET}/sources.lst |
|
find ${SRC}/test -name '*.java' >${TARGET}/test-sources.lst |
|
javac -source $SOURCE_VERSION -encoding $SOURCE_ENCODING $COMPILATION_OPTS -cp ".${FS}$LIB_TEST${FS}${EXTERNAL_JARS}" -d $TEST_CLASSES @${TARGET}/sources.lst @${TARGET}/test-sources.lst |
|
echo "execute tests through JUnit" |
|
java $JAR_OPTS -jar $LIB_TEST execute -cp "${EXTERNAL_JARS}${FS}${CLASSES}${FS}${TEST_CLASSES}${FS}." --scan-class-path |
|
echo -e " |_ ${GREEN}done$NC" |
|
echo "- execute tests through JUnit ${SRC}/test." >>${TARGET}/build.log |
|
fi |
|
|
|
if ([ "$1" == "run" ]); then |
|
echo "Run the generated JAR(s)..." |
|
for app in "${main_class_array[@]}"; do |
|
if [ $num_main_classes -eq 1 ]; then |
|
jar_name="${project_name}-${project_version}.jar" |
|
else |
|
jar_name="${project_name}-$app-${project_version}.jar" |
|
fi |
|
echo ">> run JAR ${jar_name} ..." |
|
shift 1 |
|
java $JAR_OPTS -Djava.library.path="${TARGET}/build/natives" -cp "${TARGET}/build/libs/*${FS}${TARGET}/build/${jar_name}" core.App $@ |
|
echo "done." |
|
done |
|
fi |