Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
name: PR CI

on:
on:
pull_request:
branches:
- master
paths-ignore:
- 'scripts/**'
- '**/*.md'
push:
branches:
- master
paths-ignore:
- 'scripts/**'
- '**/*.md'

jobs:
build-linux-jdk8-fx:
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/scripts-android.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
name: Test Android build scripts

'on':
pull_request:
paths:
- 'scripts/**'
- 'BUILDING.md'
push:
branches:
- master
paths:
- 'scripts/**'
- 'BUILDING.md'

jobs:
build-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup workspace
run: ./scripts/setup-workspace.sh -q -DskipTests
- name: Build Android port
run: |
source tools/env.sh
echo "JAVA_HOME=$JAVA_HOME"
java -version
echo "JAVA_HOME_17=$JAVA_HOME_17"
"$JAVA_HOME_17/bin/java" -version
./scripts/build-android-port.sh -q -DskipTests
28 changes: 28 additions & 0 deletions .github/workflows/scripts-ios.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: Test iOS build scripts

'on':
pull_request:
paths:
- 'scripts/**'
- 'BUILDING.md'
push:
branches:
- master
paths:
- 'scripts/**'
- 'BUILDING.md'

jobs:
build-ios:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Setup workspace
run: ./scripts/setup-workspace.sh -q -DskipTests
- name: Build iOS port
run: |
source tools/env.sh
echo "JAVA_HOME=$JAVA_HOME"
java -version
./scripts/build-ios-port.sh -q -DskipTests
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,6 @@ target
pom.xml.versionsBackup
pom.xml.releaseBackup
pom.xml.tag
!maven/**/*.zip
!maven/**/*.zip
/tools/
tools.sh
74 changes: 74 additions & 0 deletions BUILDING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Building Codename One

This guide explains how to build Codename One from source using Maven. It provides reproducible steps to compile the core framework and its Android and iOS ports.

## Prerequisites

- **JDK 11**
- **JDK 17** for building the Android port
- **Apache Maven 3.6+**
- macOS with Xcode (required only for the iOS port)

The helper scripts in the `scripts/` directory download these dependencies when they are not already installed.

### Installing JDKs on Linux

Download binaries from [Adoptium](https://adoptium.net):

```bash
# JDK 11 (Linux x64; adjust `_x64_linux_` for your platform)
curl -L -o temurin11.tar.gz https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.28%2B6/OpenJDK11U-jdk_x64_linux_hotspot_11.0.28_6.tar.gz
tar xf temurin11.tar.gz
export JAVA_HOME=$PWD/jdk-11.0.28+6

# JDK 17 (Linux x64; adjust `_x64_linux_` for your platform)
curl -L -o temurin17.tar.gz https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.16%2B8/OpenJDK17U-jdk_x64_linux_hotspot_17.0.16_8.tar.gz
tar xf temurin17.tar.gz
export JAVA_HOME_17=$PWD/jdk-17.0.16+8

export PATH="$JAVA_HOME/bin:$PATH"
```

## Preparing the workspace

Clone the repository and run the setup script to download JDK 11 and JDK 17, install Maven, build the core modules, and install the Maven archetypes. This step must be performed before building any ports.

```bash
git clone https://github.com/codenameone/CodenameOne
cd CodenameOne
./scripts/setup-workspace.sh -DskipTests
source tools/env.sh
```

The script runs `mvn install` in `maven/`, installs `cn1-maven-archetypes`, and ensures `~/.codenameone/CodeNameOneBuildClient.jar` is installed by invoking the `cn1:install-codenameone` Maven goal. If that goal fails, the script copies the jar from `maven/CodeNameOneBuildClient.jar`. After the script finishes, `tools/env.sh` contains environment variables for the provisioned JDKs and Maven. Downloads are placed in a temporary directory outside the repository to keep the workspace clean.

## Building the Android port

The Android port uses JDK 17 for compilation while Maven runs with JDK 11. Javadoc generation is skipped to avoid known Maven report issues. Run the build script:

```bash
./scripts/build-android-port.sh -DskipTests
```

Artifacts are placed in `maven/android/target`.

## Building the iOS port

The iOS port can only be built on macOS with Xcode installed. Run the iOS script:

```bash
./scripts/build-ios-port.sh -DskipTests
```

Artifacts are produced in `maven/ios/target`.

## Convenience scripts

- `setup-workspace.sh` – installs Maven, downloads JDK 11 and JDK 17 to a temporary directory, builds the core modules, installs Maven archetypes, provisions the Codename One build client, and writes `tools/env.sh`.
- `build-android-port.sh` – builds the Android port using JDK 11 for Maven and JDK 17 for compilation.
- `build-ios-port.sh` – builds the iOS port on macOS with JDK 11.

## Further reading

- Blog post: <https://www.codenameone.com/blog/building-codename-one-from-source-maven-edition.html>
- Maven developers guide: <https://shannah.github.io/codenameone-maven-manual/>
43 changes: 43 additions & 0 deletions scripts/build-android-port.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Build Codename One Android port using JDK 11 for Maven and JDK 17 for compilation
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"

if [ -f "$ROOT/tools/env.sh" ]; then
source "$ROOT/tools/env.sh"
else
./scripts/setup-workspace.sh -q -DskipTests
source "$ROOT/tools/env.sh"
fi

if ! "${JAVA_HOME:-}/bin/java" -version 2>&1 | grep -q '11\.0'; then
./scripts/setup-workspace.sh -q -DskipTests
source "$ROOT/tools/env.sh"
fi
if ! "${JAVA_HOME:-}/bin/java" -version 2>&1 | grep -q '11\.0'; then
echo "Failed to provision JDK 11" >&2
exit 1
fi
if ! "${JAVA_HOME_17:-}/bin/java" -version 2>&1 | grep -q '17\.0'; then
./scripts/setup-workspace.sh -q -DskipTests
source "$ROOT/tools/env.sh"
fi
if ! "${JAVA_HOME_17:-}/bin/java" -version 2>&1 | grep -q '17\.0'; then
echo "Failed to provision JDK 17" >&2
exit 1
fi

export PATH="$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH"
"$JAVA_HOME/bin/java" -version
"$JAVA_HOME_17/bin/java" -version
"$MAVEN_HOME/bin/mvn" -version

BUILD_CLIENT="$HOME/.codenameone/CodeNameOneBuildClient.jar"
if [ ! -f "$BUILD_CLIENT" ]; then
if ! "$MAVEN_HOME/bin/mvn" -q -f maven/pom.xml cn1:install-codenameone "$@"; then
[ -f maven/CodeNameOneBuildClient.jar ] && cp maven/CodeNameOneBuildClient.jar "$BUILD_CLIENT" || true
fi
fi

"$MAVEN_HOME/bin/mvn" -q -f maven/pom.xml -pl android -am -Dmaven.javadoc.skip=true -Djava.awt.headless=true clean install "$@"
39 changes: 39 additions & 0 deletions scripts/build-ios-port.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# Build Codename One iOS port (macOS only)
set -euo pipefail
if [[ "$(uname)" != "Darwin" ]]; then
echo "The iOS port can only be built on macOS with Xcode installed." >&2
exit 1
fi
if ! command -v xcodebuild >/dev/null; then
echo "Xcode command-line tools not found." >&2
exit 1
fi
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
if [ -f "$ROOT/tools/env.sh" ]; then
source "$ROOT/tools/env.sh"
else
./scripts/setup-workspace.sh -q -DskipTests
source "$ROOT/tools/env.sh"
fi
if ! "${JAVA_HOME:-}/bin/java" -version 2>&1 | grep -q '11\.0'; then
./scripts/setup-workspace.sh -q -DskipTests
source "$ROOT/tools/env.sh"
fi
if ! "${JAVA_HOME:-}/bin/java" -version 2>&1 | grep -q '11\.0'; then
echo "Failed to provision JDK 11" >&2
exit 1
fi
export PATH="$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH"
"$JAVA_HOME/bin/java" -version
"$MAVEN_HOME/bin/mvn" -version

BUILD_CLIENT="$HOME/.codenameone/CodeNameOneBuildClient.jar"
if [ ! -f "$BUILD_CLIENT" ]; then
if ! "$MAVEN_HOME/bin/mvn" -q -f maven/pom.xml cn1:install-codenameone "$@"; then
[ -f maven/CodeNameOneBuildClient.jar ] && cp maven/CodeNameOneBuildClient.jar "$BUILD_CLIENT" || true
fi
fi

"$MAVEN_HOME/bin/mvn" -q -f maven/pom.xml -pl ios -am -Djava.awt.headless=true clean install "$@"
125 changes: 125 additions & 0 deletions scripts/setup-workspace.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/usr/bin/env bash
###
# Prepare Codename One workspace by installing Maven, provisioning JDK 8 and JDK 17,
# building core modules, and installing Maven archetypes.
###
set -euo pipefail

log() {
echo "[setup-workspace] $1"
}

ROOT="$(cd "$(dirname "$0")/.." && pwd)"
ENV_DIR="$ROOT/tools"
mkdir -p "$ENV_DIR"

# Place downloaded tools outside the repository so it isn't filled with binaries
DOWNLOAD_DIR="${TMPDIR:-/tmp}/codenameone-tools"
mkdir -p "$DOWNLOAD_DIR"

JAVA_HOME="${JAVA_HOME:-}"
JAVA_HOME_17="${JAVA_HOME_17:-}"
MAVEN_HOME="${MAVEN_HOME:-}"

log "Detecting host platform"
os_name=$(uname -s)
arch_name=$(uname -m)
case "$os_name" in
Linux) os="linux" ;;
Darwin) os="mac" ;;
*) echo "Unsupported OS: $os_name" >&2; exit 1 ;;
esac
case "$arch_name" in
x86_64|amd64) arch="x64" ;;
arm64|aarch64) arch="aarch64" ;;
*) echo "Unsupported architecture: $arch_name" >&2; exit 1 ;;
esac

# Determine platform-specific JDK download URLs
arch_jdk8="$arch"
if [ "$os" = "mac" ] && [ "$arch" = "aarch64" ]; then
arch_jdk8="x64"
fi

JDK8_URL="https://github.com/adoptium/temurin8-binaries/releases/download/jdk8u462-b08/OpenJDK8U-jdk_${arch_jdk8}_${os}_hotspot_8u462b08.tar.gz"
JDK17_URL="https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.16%2B8/OpenJDK17U-jdk_${arch}_${os}_hotspot_17.0.16_8.tar.gz"
MAVEN_URL="https://archive.apache.org/dist/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz"

install_jdk() {
local url="$1" dest_var="$2"
local tmp="$DOWNLOAD_DIR/jdk.tgz"
log "Downloading JDK from $url"
curl -fL "$url" -o "$tmp"
local top
top=$(tar -tzf "$tmp" 2>/dev/null | head -1 | cut -d/ -f1 || true)
tar -xzf "$tmp" -C "$DOWNLOAD_DIR"
rm "$tmp"
local home="$DOWNLOAD_DIR/$top"
if [ -d "$home/Contents/Home" ]; then
home="$home/Contents/Home"
fi
eval "$dest_var=\"$home\""
}

log "Ensuring JDK 8 is available"
if [ ! -x "${JAVA_HOME:-}/bin/java" ] || ! "${JAVA_HOME:-}/bin/java" -version 2>&1 | grep -q '8\.0'; then
log "Provisioning JDK 8 (this may take a while)..."
install_jdk "$JDK8_URL" JAVA_HOME
else
log "Using existing JDK 8 at $JAVA_HOME"
fi

log "Ensuring JDK 17 is available"
if [ ! -x "${JAVA_HOME_17:-}/bin/java" ] || ! "${JAVA_HOME_17:-}/bin/java" -version 2>&1 | grep -q '17\.0'; then
log "Provisioning JDK 17 (this may take a while)..."
install_jdk "$JDK17_URL" JAVA_HOME_17
else
log "Using existing JDK 17 at $JAVA_HOME_17"
fi

log "Ensuring Maven is available"
if ! [ -x "${MAVEN_HOME:-}/bin/mvn" ]; then
tmp="$DOWNLOAD_DIR/maven.tgz"
log "Downloading Maven from $MAVEN_URL"
curl -fL "$MAVEN_URL" -o "$tmp"
tar -xzf "$tmp" -C "$DOWNLOAD_DIR"
rm "$tmp"
MAVEN_HOME="$DOWNLOAD_DIR/apache-maven-3.9.6"
else
log "Using existing Maven at $MAVEN_HOME"
fi

log "Writing environment to $ENV_DIR/env.sh"
cat > "$ENV_DIR/env.sh" <<ENV
export JAVA_HOME="$JAVA_HOME"
export JAVA_HOME_17="$JAVA_HOME_17"
export MAVEN_HOME="$MAVEN_HOME"
export PATH="\$JAVA_HOME/bin:\$MAVEN_HOME/bin:\$PATH"
ENV

source "$ENV_DIR/env.sh"

log "JDK 8 version:"; "$JAVA_HOME/bin/java" -version
log "JDK 17 version:"; "$JAVA_HOME_17/bin/java" -version
log "Maven version:"; "$MAVEN_HOME/bin/mvn" -version

PATH="$JAVA_HOME/bin:$MAVEN_HOME/bin:$PATH"

log "Building Codename One core modules"
"$MAVEN_HOME/bin/mvn" -q -f maven/pom.xml -DskipTests -Djava.awt.headless=true install "$@"

BUILD_CLIENT="$HOME/.codenameone/CodeNameOneBuildClient.jar"
log "Ensuring CodeNameOneBuildClient.jar is installed"
if [ ! -f "$BUILD_CLIENT" ]; then
if ! "$MAVEN_HOME/bin/mvn" -f maven/pom.xml cn1:install-codenameone "$@"; then
log "Falling back to copying CodeNameOneBuildClient.jar"
mkdir -p "$(dirname "$BUILD_CLIENT")"
cp maven/CodeNameOneBuildClient.jar "$BUILD_CLIENT" || true
fi
fi

log "Installing cn1-maven-archetypes"
if [ ! -d cn1-maven-archetypes ]; then
git clone https://github.com/shannah/cn1-maven-archetypes
fi
(cd cn1-maven-archetypes && "$MAVEN_HOME/bin/mvn" -q -DskipTests -DskipITs=true -Dinvoker.skip=true install)
8 changes: 7 additions & 1 deletion vm/JavaAPI/src/java/io/ByteArrayOutputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ public String toString(String charsetName) throws UnsupportedEncodingException {
*/
@Override
public synchronized void write(byte[] buffer, int offset, int len) {
Arrays.checkOffsetAndCount(buffer.length, offset, len);
checkOffsetAndCount(buffer.length, offset, len);
if (len == 0) {
return;
}
Expand All @@ -201,6 +201,12 @@ public synchronized void write(byte[] buffer, int offset, int len) {
this.count += len;
}

static void checkOffsetAndCount(int arrayLength, int offset, int count) {
if ((offset | count) < 0 || offset > arrayLength || arrayLength - offset < count) {
throw new ArrayIndexOutOfBoundsException(offset);
}
}

/**
* Writes the specified byte {@code oneByte} to the OutputStream. Only the
* low order byte of {@code oneByte} is written.
Expand Down
Loading
Loading