From 55983c9dee1439683b745845f1555a32150d96c7 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sun, 4 Jan 2026 05:22:29 +0200 Subject: [PATCH 01/13] Add runtime stack overflow test --- vm/ByteCodeTranslator/src/nativeMethods.m | 9 ++- .../src/java/lang/StackOverflowError.java | 44 ++++++++++++ .../CleanTargetIntegrationTest.java | 23 ++++++ .../tools/translator/CompilerHelper.java | 62 ++++++++++++---- .../StackOverflowErrorCompilationTest.java | 70 +++++++++++++++++++ 5 files changed, 194 insertions(+), 14 deletions(-) create mode 100644 vm/JavaAPI/src/java/lang/StackOverflowError.java create mode 100644 vm/tests/src/test/java/com/codename1/tools/translator/StackOverflowErrorCompilationTest.java diff --git a/vm/ByteCodeTranslator/src/nativeMethods.m b/vm/ByteCodeTranslator/src/nativeMethods.m index 6a6eb6abbc..962e57ae8e 100644 --- a/vm/ByteCodeTranslator/src/nativeMethods.m +++ b/vm/ByteCodeTranslator/src/nativeMethods.m @@ -21,6 +21,8 @@ #include "java_lang_Float.h" #include "java_lang_Runnable.h" #include "java_lang_Throwable.h" +#include "java_lang_StackOverflowError.h" +#include "java_lang_VirtualMachineError.h" #include "java_lang_StringBuilder.h" #include "java_util_HashMap.h" #include "java_util_HashMap_Entry.h" @@ -1550,9 +1552,14 @@ void initMethodStack(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject, int THROW_NULL_POINTER_EXCEPTION(); } #endif + if (threadStateData->callStackOffset >= CN1_MAX_STACK_CALL_DEPTH - 1) { + JAVA_OBJECT stackOverflow = __NEW_INSTANCE_java_lang_StackOverflowError(threadStateData); + java_lang_Throwable_fillInStack__(threadStateData, stackOverflow); + throwException(threadStateData, stackOverflow); + return; + } memset(&threadStateData->threadObjectStack[threadStateData->threadObjectStackOffset], 0, sizeof(struct elementStruct) * (localsStackSize + stackSize)); threadStateData->threadObjectStackOffset += localsStackSize + stackSize; - CODENAME_ONE_ASSERT(threadStateData->callStackOffset < CN1_MAX_STACK_CALL_DEPTH - 1); threadStateData->callStackClass[threadStateData->callStackOffset] = classNameId; threadStateData->callStackMethod[threadStateData->callStackOffset] = methodNameId; threadStateData->callStackOffset++; diff --git a/vm/JavaAPI/src/java/lang/StackOverflowError.java b/vm/JavaAPI/src/java/lang/StackOverflowError.java new file mode 100644 index 0000000000..5b6913a931 --- /dev/null +++ b/vm/JavaAPI/src/java/lang/StackOverflowError.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Codename One designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Codename One through http://www.codenameone.com/ if you + * need additional information or have any questions. + */ + +package java.lang; + +/** + * Thrown when a stack overflow occurs because an application recurses too deeply. + * Since: JDK1.0, CLDC 1.0 + */ +public class StackOverflowError extends VirtualMachineError { + /** + * Constructs a StackOverflowError with no detail message. + */ + public StackOverflowError() { + } + + /** + * Constructs a StackOverflowError with the specified detail message. + * @param s the detail message. + */ + public StackOverflowError(String s) { + super(s); + } +} diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 78f148ea92..6a91b75635 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -202,6 +202,29 @@ static String runCommand(List command, Path workingDir) throws Exception return output; } + static CommandResult runCommandWithResult(List command, Path workingDir) throws Exception { + ProcessBuilder builder = new ProcessBuilder(command); + builder.directory(workingDir.toFile()); + builder.redirectErrorStream(true); + Process process = builder.start(); + String output; + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8))) { + output = reader.lines().collect(Collectors.joining("\n")); + } + int exit = process.waitFor(); + return new CommandResult(exit, output); + } + + static final class CommandResult { + final int exitCode; + final String output; + + CommandResult(int exitCode, String output) { + this.exitCode = exitCode; + this.output = output; + } + } + static void patchCn1Globals(Path srcRoot) throws IOException { Path cn1Globals = srcRoot.resolve("cn1_globals.h"); String content = new String(Files.readAllBytes(cn1Globals), StandardCharsets.UTF_8); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java index 39864a0872..c93fa1cfe4 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java @@ -136,7 +136,17 @@ public String toString() { } } - public static boolean compileAndRun(String code, String expectedOutput) throws Exception { + public static class ExecutionResult { + public final int exitCode; + public final String output; + + public ExecutionResult(int exitCode, String output) { + this.exitCode = exitCode; + this.output = output; + } + } + + public static ExecutionResult compileAndRunForResult(String code) throws Exception { // Find a suitable compiler (e.g. JDK 8 targeting 1.8) List compilers = getAvailableCompilers("1.8"); if (compilers.isEmpty()) { @@ -170,7 +180,7 @@ public static boolean compileAndRun(String code, String expectedOutput) throws E compileArgs.add(sourceDir.resolve("Main.java").toString()); if (compile(config.jdkHome, compileArgs) != 0) { - return false; + return new ExecutionResult(-1, "javac failed"); } // Merge javaApiDir into classesDir so translator finds dependencies @@ -210,12 +220,15 @@ public static boolean compileAndRun(String code, String expectedOutput) throws E "#endif\n"; java.nio.file.Files.write(objectHeader, headerContent.getBytes(java.nio.charset.StandardCharsets.UTF_8)); } - java.nio.file.Path stubs = srcRoot.resolve("runtime_stubs.c"); - String content = "#include \"cn1_globals.h\"\n" + - "#include \n" + - "#include \n" + - "#include \n" + - "#include \n" + + java.nio.file.Path stubs = srcRoot.resolve("runtime_stubs.c"); + String content = "#include \"cn1_globals.h\"\n" + + "#include \"java_lang_StackOverflowError.h\"\n" + + "#include \"java_lang_Throwable.h\"\n" + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + "\n" + "struct my_java_lang_String {\n" + " JAVA_OBJECT __codenameOneParentClsReference;\n" + @@ -320,11 +333,24 @@ public static boolean compileAndRun(String code, String expectedOutput) throws E "}\n" + "\n" + "void initMethodStack(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT __cn1ThisObject, int stackSize, int localsStackSize, int classNameId, int methodNameId) {\n" + - " threadStateData->threadObjectStackOffset += localsStackSize;\n" + + " if (threadStateData->callStackOffset >= CN1_MAX_STACK_CALL_DEPTH - 1) {\n" + + " JAVA_OBJECT stackOverflow = __NEW_INSTANCE_java_lang_StackOverflowError(threadStateData);\n" + + " java_lang_Throwable_fillInStack__(threadStateData, stackOverflow);\n" + + " throwException(threadStateData, stackOverflow);\n" + + " return;\n" + + " }\n" + + " memset(&threadStateData->threadObjectStack[threadStateData->threadObjectStackOffset], 0, sizeof(struct elementStruct) * (localsStackSize + stackSize));\n" + + " threadStateData->threadObjectStackOffset += localsStackSize + stackSize;\n" + + " threadStateData->callStackClass[threadStateData->callStackOffset] = classNameId;\n" + + " threadStateData->callStackMethod[threadStateData->callStackOffset] = methodNameId;\n" + + " threadStateData->callStackOffset++;\n" + "}\n" + "\n" + "void releaseForReturn(CODENAME_ONE_THREAD_STATE, int cn1LocalsBeginInThread) {\n" + " threadStateData->threadObjectStackOffset = cn1LocalsBeginInThread;\n" + + " if (threadStateData->callStackOffset > 0) {\n" + + " threadStateData->callStackOffset--;\n" + + " }\n" + "}\n" + "\n" + "void releaseForReturnInException(CODENAME_ONE_THREAD_STATE, int cn1LocalsBeginInThread, int methodBlockOffset) {\n" + @@ -351,7 +377,12 @@ public static boolean compileAndRun(String code, String expectedOutput) throws E "}\n" + "\n" + "void throwException(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT obj) {\n" + - " (void)obj;\n" + + " if (obj != JAVA_NULL && obj->__codenameOneParentClsReference != 0 && obj->__codenameOneParentClsReference->clsName != NULL) {\n" + + " fprintf(stderr, \"Exception thrown: %s\\n\", obj->__codenameOneParentClsReference->clsName);\n" + + " } else {\n" + + " fprintf(stderr, \"Exception thrown: %p\\n\", obj);\n" + + " }\n" + + " fflush(stderr);\n" + " exit(1);\n" + "}\n" + "\n" + @@ -543,15 +574,20 @@ public static boolean compileAndRun(String code, String expectedOutput) throws E CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); java.nio.file.Path executable = buildDir.resolve("ExecutorApp"); - String output = CleanTargetIntegrationTest.runCommand(Arrays.asList(executable.toString()), buildDir); - return output.contains(expectedOutput); + CleanTargetIntegrationTest.CommandResult result = CleanTargetIntegrationTest.runCommandWithResult(Arrays.asList(executable.toString()), buildDir); + return new ExecutionResult(result.exitCode, result.output); } finally { // cleanup? } } - private static void compileJavaAPI(java.nio.file.Path outputDir) throws IOException, InterruptedException { + public static boolean compileAndRun(String code, String expectedOutput) throws Exception { + ExecutionResult result = compileAndRunForResult(code); + return result.exitCode == 0 && result.output.contains(expectedOutput); + } + + static void compileJavaAPI(java.nio.file.Path outputDir) throws IOException, InterruptedException { java.nio.file.Files.createDirectories(outputDir); java.nio.file.Path javaApiRoot = java.nio.file.Paths.get("..", "JavaAPI", "src").normalize().toAbsolutePath(); List sources = new ArrayList<>(); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/StackOverflowErrorCompilationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/StackOverflowErrorCompilationTest.java new file mode 100644 index 0000000000..7faa769731 --- /dev/null +++ b/vm/tests/src/test/java/com/codename1/tools/translator/StackOverflowErrorCompilationTest.java @@ -0,0 +1,70 @@ +package com.codename1.tools.translator; + +import org.junit.jupiter.api.Test; +import org.objectweb.asm.ClassReader; + +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class StackOverflowErrorCompilationTest { + + @Test + void javaApiBuildProducesStackOverflowAndVirtualMachineErrors() throws Exception { + Path outputDir = Files.createTempDirectory("java-api-classes"); + + CompilerHelper.compileJavaAPI(outputDir); + + Path vmErrorClass = outputDir.resolve("java/lang/VirtualMachineError.class"); + Path stackOverflowClass = outputDir.resolve("java/lang/StackOverflowError.class"); + + assertTrue(Files.exists(vmErrorClass), "VirtualMachineError class should be generated"); + assertTrue(Files.exists(stackOverflowClass), "StackOverflowError class should be generated"); + + ClassReader vmErrorReader = new ClassReader(Files.readAllBytes(vmErrorClass)); + assertEquals("java/lang/Error", vmErrorReader.getSuperName(), + "VirtualMachineError should extend Error"); + + ClassReader stackOverflowReader = new ClassReader(Files.readAllBytes(stackOverflowClass)); + assertEquals("java/lang/VirtualMachineError", stackOverflowReader.getSuperName(), + "StackOverflowError should extend VirtualMachineError"); + } + + @Test + void translatedRuntimeRaisesStackOverflowOnDeepRecursion() throws Exception { + String code = "package test;\n" + + "public class Main {\n" + + " private static native void print(String s);\n" + + " static long ping(int depth, long salt) {\n" + + " long guard = salt ^ depth;\n" + + " byte[] pad = new byte[32];\n" + + " pad[(depth & 7)] = (byte)guard;\n" + + " if (depth <= 0) return guard + pad[0];\n" + + " long branch = pong(depth - 1, guard + pad[0]);\n" + + " return branch + pad[1] + guard;\n" + + " }\n" + + " static long pong(int depth, long salt) {\n" + + " long shuffle = salt + depth;\n" + + " return ping(depth - 1, shuffle) ^ shuffle;\n" + + " }\n" + + " public static void main(String[] args) {\n" + + " try {\n" + + " print(String.valueOf(ping(1600, System.nanoTime())));\n" + + " } catch (StackOverflowError err) {\n" + + " print(\"Caught: \" + err.getClass().getName());\n" + + " print(err.toString());\n" + + " }\n" + + " }\n" + + "}\n"; + + CompilerHelper.ExecutionResult result = CompilerHelper.compileAndRunForResult(code); + + assertTrue(result.exitCode != 0, "Translated binary should surface the overflow instead of running to completion"); + assertNotEquals(139, result.exitCode, "Stack overflow should be surfaced as an exception, not a crash"); + assertTrue(result.output.contains("StackOverflowError"), + () -> "Runtime output should mention StackOverflowError\nOutput:\n" + result.output); + } +} From 97de45c9dc4dda144387d2b1824c00c2e5728060 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sun, 4 Jan 2026 05:47:35 +0200 Subject: [PATCH 02/13] Fix translator header prototypes --- .../tools/translator/CompilerHelper.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java index c93fa1cfe4..1e0fc3a5b6 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java @@ -2,6 +2,7 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -205,6 +206,7 @@ public static ExecutionResult compileAndRunForResult(String code) throws Excepti java.nio.file.Path distDir = outputDir.resolve("dist"); java.nio.file.Path srcRoot = distDir.resolve("ExecutorApp-src"); CleanTargetIntegrationTest.patchCn1Globals(srcRoot); + patchStaticGetterPrototypes(srcRoot); // Write basic stubs java.nio.file.Path ioFileHeader = srcRoot.resolve("java_io_File.h"); @@ -607,4 +609,20 @@ static void compileJavaAPI(java.nio.file.Path outputDir) throws IOException, Int compiler.run(null, null, null, args.toArray(new String[0])); } + + private static void patchStaticGetterPrototypes(java.nio.file.Path srcRoot) throws IOException { + java.nio.file.Files.walk(srcRoot) + .filter(p -> p.toString().endsWith(".h")) + .forEach(p -> { + try { + String original = new String(java.nio.file.Files.readAllBytes(p), StandardCharsets.UTF_8); + String patched = original.replaceAll("(get_static_[A-Za-z0-9_]+)\\(\\);", "$1(CODENAME_ONE_THREAD_STATE);"); + if (!original.equals(patched)) { + java.nio.file.Files.write(p, patched.getBytes(StandardCharsets.UTF_8)); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } } From da9cf0da5103cefdc7d104f7c0be18057acb2899 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sun, 4 Jan 2026 07:23:23 +0200 Subject: [PATCH 03/13] Relax literal-range warning for executor builds --- .../codename1/tools/translator/CleanTargetIntegrationTest.java | 3 ++- .../java/com/codename1/tools/translator/CompilerHelper.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 6a91b75635..0d14e873dc 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -109,7 +109,8 @@ void generatesRunnableHelloWorldUsingCleanTarget(CompilerHelper.CompilerConfig c "-S", distDir.toString(), "-B", buildDir.toString(), "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" + "-DCMAKE_OBJC_COMPILER=clang", + "-DCMAKE_C_FLAGS=-Wno-error=literal-range" ), distDir); runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java index 1e0fc3a5b6..6c09b4a845 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java @@ -570,7 +570,8 @@ public static ExecutionResult compileAndRunForResult(String code) throws Excepti "-S", distDir.toString(), "-B", buildDir.toString(), "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" + "-DCMAKE_OBJC_COMPILER=clang", + "-DCMAKE_C_FLAGS=-Wno-error=literal-range" ), distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); From e1800741c128b61812627c2e8cda5a569c740592 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sun, 4 Jan 2026 19:40:22 +0200 Subject: [PATCH 04/13] Ensure executor builds suppress literal-range warnings in CMakeLists --- .../tools/translator/CleanTargetIntegrationTest.java | 10 ++++++++++ .../com/codename1/tools/translator/CompilerHelper.java | 4 +++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 0d14e873dc..e583142ddc 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -100,6 +100,7 @@ void generatesRunnableHelloWorldUsingCleanTarget(CompilerHelper.CompilerConfig c writeRuntimeStubs(srcRoot); replaceLibraryWithExecutableTarget(cmakeLists, srcRoot.getFileName().toString()); + relaxLiteralRangeWarnings(cmakeLists); Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); @@ -189,6 +190,15 @@ static void replaceLibraryWithExecutableTarget(Path cmakeLists, String sourceDir Files.write(cmakeLists, replacement.getBytes(StandardCharsets.UTF_8)); } + static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { + String content = new String(Files.readAllBytes(cmakeLists), StandardCharsets.UTF_8); + String flagLine = "set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wno-error=literal-range\")"; + if (!content.contains(flagLine)) { + content = flagLine + "\n" + content; + Files.write(cmakeLists, content.getBytes(StandardCharsets.UTF_8)); + } + } + static String runCommand(List command, Path workingDir) throws Exception { ProcessBuilder builder = new ProcessBuilder(command); builder.directory(workingDir.toFile()); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java index 6c09b4a845..ddd6eadc37 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java @@ -560,7 +560,9 @@ public static ExecutionResult compileAndRunForResult(String code) throws Excepti java.nio.file.Files.write(stubs, content.getBytes(java.nio.charset.StandardCharsets.UTF_8)); - CleanTargetIntegrationTest.replaceLibraryWithExecutableTarget(outputDir.resolve("dist").resolve("CMakeLists.txt"), "ExecutorApp-src"); + java.nio.file.Path cmakeLists = outputDir.resolve("dist").resolve("CMakeLists.txt"); + CleanTargetIntegrationTest.replaceLibraryWithExecutableTarget(cmakeLists, "ExecutorApp-src"); + CleanTargetIntegrationTest.relaxLiteralRangeWarnings(cmakeLists); java.nio.file.Path buildDir = distDir.resolve("build"); java.nio.file.Files.createDirectories(buildDir); From 45406874b96ce63c63e0104e0d2fc607dc220715 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Sun, 4 Jan 2026 20:55:39 +0200 Subject: [PATCH 05/13] Silence literal-range warnings in executor builds --- .../tools/translator/CleanTargetIntegrationTest.java | 4 ++-- .../java/com/codename1/tools/translator/CompilerHelper.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index e583142ddc..26f779d12b 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -111,7 +111,7 @@ void generatesRunnableHelloWorldUsingCleanTarget(CompilerHelper.CompilerConfig c "-B", buildDir.toString(), "-DCMAKE_C_COMPILER=clang", "-DCMAKE_OBJC_COMPILER=clang", - "-DCMAKE_C_FLAGS=-Wno-error=literal-range" + "-DCMAKE_C_FLAGS=-Wno-error=literal-range -Wno-literal-range" ), distDir); runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); @@ -192,7 +192,7 @@ static void replaceLibraryWithExecutableTarget(Path cmakeLists, String sourceDir static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { String content = new String(Files.readAllBytes(cmakeLists), StandardCharsets.UTF_8); - String flagLine = "set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wno-error=literal-range\")"; + String flagLine = "set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wno-error=literal-range -Wno-literal-range\")"; if (!content.contains(flagLine)) { content = flagLine + "\n" + content; Files.write(cmakeLists, content.getBytes(StandardCharsets.UTF_8)); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java index ddd6eadc37..c0415eaf12 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java @@ -573,7 +573,7 @@ public static ExecutionResult compileAndRunForResult(String code) throws Excepti "-B", buildDir.toString(), "-DCMAKE_C_COMPILER=clang", "-DCMAKE_OBJC_COMPILER=clang", - "-DCMAKE_C_FLAGS=-Wno-error=literal-range" + "-DCMAKE_C_FLAGS=-Wno-error=literal-range -Wno-literal-range" ), distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); From 45b896ead3927a2e6c2698d81b46909bbbe21dc7 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 5 Jan 2026 03:59:47 +0200 Subject: [PATCH 06/13] Stub Throwable.fillInStack in executor runtime --- .../test/java/com/codename1/tools/translator/CompilerHelper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java index c0415eaf12..8c90eec7ab 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java @@ -387,6 +387,7 @@ public static ExecutionResult compileAndRunForResult(String code) throws Excepti " fflush(stderr);\n" + " exit(1);\n" + "}\n" + + "void java_lang_Throwable_fillInStack__(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT me) { (void)threadStateData; (void)me; }\n" + "\n" + "void gcMarkObject(CODENAME_ONE_THREAD_STATE, JAVA_OBJECT obj, JAVA_BOOLEAN force) { (void)obj; (void)force; }\n" + "// Stub instanceofFunction. Note: signature in cn1_globals.h might differ (int vs pointers) in some versions.\n" + From 15a4c19f220fec715f6b0835e4d2869377c3f58d Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 5 Jan 2026 07:13:54 +0200 Subject: [PATCH 07/13] Patch translator static getter prototypes in integration tests --- .../translator/CleanTargetIntegrationTest.java | 16 ++++++++++++++++ .../tools/translator/CompilerHelper.java | 17 +---------------- .../translator/FileClassIntegrationTest.java | 1 + 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 26f779d12b..403458634a 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -249,6 +249,22 @@ static void patchCn1Globals(Path srcRoot) throws IOException { } } + static void patchStaticGetterPrototypes(Path srcRoot) throws IOException { + Files.walk(srcRoot) + .filter(p -> p.toString().endsWith(".h")) + .forEach(p -> { + try { + String original = new String(Files.readAllBytes(p), StandardCharsets.UTF_8); + String patched = original.replaceAll("(get_static_[A-Za-z0-9_]+)\\(\\);", "$1(CODENAME_ONE_THREAD_STATE);"); + if (!original.equals(patched)) { + Files.write(p, patched.getBytes(StandardCharsets.UTF_8)); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + }); + } + static void writeRuntimeStubs(Path srcRoot) throws IOException { Path objectHeader = srcRoot.resolve("java_lang_Object.h"); if (!Files.exists(objectHeader)) { diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java index 8c90eec7ab..fc33024562 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java @@ -206,7 +206,7 @@ public static ExecutionResult compileAndRunForResult(String code) throws Excepti java.nio.file.Path distDir = outputDir.resolve("dist"); java.nio.file.Path srcRoot = distDir.resolve("ExecutorApp-src"); CleanTargetIntegrationTest.patchCn1Globals(srcRoot); - patchStaticGetterPrototypes(srcRoot); + CleanTargetIntegrationTest.patchStaticGetterPrototypes(srcRoot); // Write basic stubs java.nio.file.Path ioFileHeader = srcRoot.resolve("java_io_File.h"); @@ -614,19 +614,4 @@ static void compileJavaAPI(java.nio.file.Path outputDir) throws IOException, Int compiler.run(null, null, null, args.toArray(new String[0])); } - private static void patchStaticGetterPrototypes(java.nio.file.Path srcRoot) throws IOException { - java.nio.file.Files.walk(srcRoot) - .filter(p -> p.toString().endsWith(".h")) - .forEach(p -> { - try { - String original = new String(java.nio.file.Files.readAllBytes(p), StandardCharsets.UTF_8); - String patched = original.replaceAll("(get_static_[A-Za-z0-9_]+)\\(\\);", "$1(CODENAME_ONE_THREAD_STATE);"); - if (!original.equals(patched)) { - java.nio.file.Files.write(p, patched.getBytes(StandardCharsets.UTF_8)); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - }); - } } diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java index d358ae4244..70cb7e4843 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java @@ -81,6 +81,7 @@ public void testFileClassMethods(CompilerHelper.CompilerConfig config) throws Ex Path srcRoot = distDir.resolve("FileTestApp-src"); CleanTargetIntegrationTest.patchCn1Globals(srcRoot); + CleanTargetIntegrationTest.patchStaticGetterPrototypes(srcRoot); // Ensure java_io_File.m is included (ByteCodeTranslator should copy it) assertTrue(Files.exists(srcRoot.resolve("java_io_File.m")), "java_io_File.m should exist"); From e59653149a0e719ef5d74cd46ac1e79e91a22520 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 5 Jan 2026 17:58:29 +0200 Subject: [PATCH 08/13] Relax literal range warnings for File integration build --- .../com/codename1/tools/translator/FileClassIntegrationTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java index 70cb7e4843..ae322f686b 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java @@ -87,6 +87,7 @@ public void testFileClassMethods(CompilerHelper.CompilerConfig config) throws Ex assertTrue(Files.exists(srcRoot.resolve("java_io_File.m")), "java_io_File.m should exist"); replaceLibraryWithExecutableTarget(cmakeLists, srcRoot.getFileName().toString()); + CleanTargetIntegrationTest.relaxLiteralRangeWarnings(cmakeLists); Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); From a61326ae827735ff0f3a5ad7b3b9192f9c1eebb3 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Mon, 5 Jan 2026 20:50:29 +0200 Subject: [PATCH 09/13] Make translator integration builds compiler-aware --- .../BytecodeInstructionIntegrationTest.java | 20 +++--- .../CleanTargetIntegrationTest.java | 63 ++++++++++++++++--- .../tools/translator/CompilerHelper.java | 11 ++-- .../translator/FileClassIntegrationTest.java | 10 +-- .../translator/LambdaIntegrationTest.java | 10 +-- .../tools/translator/LockIntegrationTest.java | 10 +-- .../ReadWriteLockIntegrationTest.java | 10 +-- .../StampedLockIntegrationTest.java | 10 +-- 8 files changed, 94 insertions(+), 50 deletions(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/BytecodeInstructionIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/BytecodeInstructionIntegrationTest.java index 4a55df8d05..608562fc7e 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/BytecodeInstructionIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/BytecodeInstructionIntegrationTest.java @@ -142,13 +142,13 @@ void translatesOptimizedBytecodeToLLVMExecutable(CompilerHelper.CompilerConfig c Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); - CleanTargetIntegrationTest.runCommand(Arrays.asList( + List cmakeCommand = new ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(CleanTargetIntegrationTest.cmakeCompilerArgs()); + CleanTargetIntegrationTest.runCommand(cmakeCommand, distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); @@ -293,13 +293,13 @@ void translatesInvokeAndLdcBytecodeToLLVMExecutable(CompilerHelper.CompilerConfi Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); - CleanTargetIntegrationTest.runCommand(Arrays.asList( + List cmakeCommand = new ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(CleanTargetIntegrationTest.cmakeCompilerArgs()); + CleanTargetIntegrationTest.runCommand(cmakeCommand, distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 403458634a..ce0664867d 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -7,6 +7,7 @@ import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; @@ -105,14 +106,13 @@ void generatesRunnableHelloWorldUsingCleanTarget(CompilerHelper.CompilerConfig c Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); - runCommand(Arrays.asList( + List cmakeCommand = new java.util.ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang", - "-DCMAKE_C_FLAGS=-Wno-error=literal-range -Wno-literal-range" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(cmakeCompilerArgs()); + runCommand(cmakeCommand, distDir); runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); @@ -192,13 +192,58 @@ static void replaceLibraryWithExecutableTarget(Path cmakeLists, String sourceDir static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { String content = new String(Files.readAllBytes(cmakeLists), StandardCharsets.UTF_8); - String flagLine = "set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} -Wno-error=literal-range -Wno-literal-range\")"; - if (!content.contains(flagLine)) { - content = flagLine + "\n" + content; + String marker = "CN1_LITERAL_RANGE_FLAGS"; + if (!content.contains(marker)) { + String flagBlock = + "set(" + marker + " \"-Wno-error=literal-range -Wno-literal-range\")\n" + + "if (CMAKE_C_COMPILER_ID MATCHES \"Clang\")\n" + + " set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${" + marker + "}\")\n" + + "endif\n" + + "if (CMAKE_OBJC_COMPILER_ID MATCHES \"Clang\")\n" + + " set(CMAKE_OBJC_FLAGS \"${CMAKE_OBJC_FLAGS} ${" + marker + "}\")\n" + + "endif\n"; + content = content + "\n" + flagBlock; Files.write(cmakeLists, content.getBytes(StandardCharsets.UTF_8)); } } + static List cmakeCompilerArgs() { + List args = new java.util.ArrayList<>(); + String cCompiler = findExecutable(Arrays.asList("clang", "cc", "gcc")); + if (cCompiler != null) { + args.add("-DCMAKE_C_COMPILER=" + cCompiler); + } + String objcCompiler = findExecutable(Arrays.asList("clang", "gcc", "cc")); + if (objcCompiler != null) { + args.add("-DCMAKE_OBJC_COMPILER=" + objcCompiler); + } + return args; + } + + private static String findExecutable(List candidates) { + for (String candidate : candidates) { + Path found = findOnPath(candidate); + if (found != null) { + return found.toString(); + } + } + return null; + } + + private static Path findOnPath(String executable) { + String path = System.getenv("PATH"); + if (path == null) { + return null; + } + for (String dir : path.split(File.pathSeparator)) { + Path candidate = Paths.get(dir, executable); + if (Files.isExecutable(candidate)) { + return candidate; + } + } + return null; + } + static String runCommand(List command, Path workingDir) throws Exception { ProcessBuilder builder = new ProcessBuilder(command); builder.directory(workingDir.toFile()); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java index fc33024562..5a7a2bfdd6 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CompilerHelper.java @@ -568,14 +568,13 @@ public static ExecutionResult compileAndRunForResult(String code) throws Excepti java.nio.file.Path buildDir = distDir.resolve("build"); java.nio.file.Files.createDirectories(buildDir); - CleanTargetIntegrationTest.runCommand(Arrays.asList( + List cmakeCommand = new ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang", - "-DCMAKE_C_FLAGS=-Wno-error=literal-range -Wno-literal-range" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(CleanTargetIntegrationTest.cmakeCompilerArgs()); + CleanTargetIntegrationTest.runCommand(cmakeCommand, distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java index ae322f686b..b84322d93e 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/FileClassIntegrationTest.java @@ -92,13 +92,13 @@ public void testFileClassMethods(CompilerHelper.CompilerConfig config) throws Ex Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); - CleanTargetIntegrationTest.runCommand(Arrays.asList( + List cmakeCommand = new ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(CleanTargetIntegrationTest.cmakeCompilerArgs()); + CleanTargetIntegrationTest.runCommand(cmakeCommand, distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/LambdaIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/LambdaIntegrationTest.java index f9f14e931f..114c15cc5e 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/LambdaIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/LambdaIntegrationTest.java @@ -128,13 +128,13 @@ void translatesLambdaBytecodeToLLVMExecutable(String targetVersion) throws Excep Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); - CleanTargetIntegrationTest.runCommand(Arrays.asList( + List cmakeCommand = new ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(CleanTargetIntegrationTest.cmakeCompilerArgs()); + CleanTargetIntegrationTest.runCommand(cmakeCommand, distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/LockIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/LockIntegrationTest.java index 45c50c6fd4..8c47bffd8c 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/LockIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/LockIntegrationTest.java @@ -95,13 +95,13 @@ void verifiesLockAndReentrantLockBehavior(CompilerHelper.CompilerConfig config) Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); - CleanTargetIntegrationTest.runCommand(Arrays.asList( + List cmakeCommand = new java.util.ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(CleanTargetIntegrationTest.cmakeCompilerArgs()); + CleanTargetIntegrationTest.runCommand(cmakeCommand, distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/ReadWriteLockIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/ReadWriteLockIntegrationTest.java index 054e5e1cfd..eb970138dd 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/ReadWriteLockIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/ReadWriteLockIntegrationTest.java @@ -99,13 +99,13 @@ void verifiesReadWriteLockBehavior(CompilerHelper.CompilerConfig config) throws Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); - CleanTargetIntegrationTest.runCommand(Arrays.asList( + List cmakeCommand = new java.util.ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(CleanTargetIntegrationTest.cmakeCompilerArgs()); + CleanTargetIntegrationTest.runCommand(cmakeCommand, distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/StampedLockIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/StampedLockIntegrationTest.java index 396743994d..efd7718b38 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/StampedLockIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/StampedLockIntegrationTest.java @@ -96,13 +96,13 @@ void verifiesStampedLockBehavior(CompilerHelper.CompilerConfig config) throws Ex Path buildDir = distDir.resolve("build"); Files.createDirectories(buildDir); - CleanTargetIntegrationTest.runCommand(Arrays.asList( + List cmakeCommand = new java.util.ArrayList<>(Arrays.asList( "cmake", "-S", distDir.toString(), - "-B", buildDir.toString(), - "-DCMAKE_C_COMPILER=clang", - "-DCMAKE_OBJC_COMPILER=clang" - ), distDir); + "-B", buildDir.toString() + )); + cmakeCommand.addAll(CleanTargetIntegrationTest.cmakeCompilerArgs()); + CleanTargetIntegrationTest.runCommand(cmakeCommand, distDir); CleanTargetIntegrationTest.runCommand(Arrays.asList("cmake", "--build", buildDir.toString()), distDir); From 60662cdfc84118d6f0f0793395d78ca0d6be5dd8 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Tue, 6 Jan 2026 03:59:04 +0200 Subject: [PATCH 10/13] Harden literal-range flag insertion in translator tests --- .../CleanTargetIntegrationTest.java | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index ce0664867d..57a7f1b289 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -191,20 +191,27 @@ static void replaceLibraryWithExecutableTarget(Path cmakeLists, String sourceDir } static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { - String content = new String(Files.readAllBytes(cmakeLists), StandardCharsets.UTF_8); - String marker = "CN1_LITERAL_RANGE_FLAGS"; - if (!content.contains(marker)) { - String flagBlock = - "set(" + marker + " \"-Wno-error=literal-range -Wno-literal-range\")\n" + - "if (CMAKE_C_COMPILER_ID MATCHES \"Clang\")\n" + - " set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${" + marker + "}\")\n" + - "endif\n" + - "if (CMAKE_OBJC_COMPILER_ID MATCHES \"Clang\")\n" + - " set(CMAKE_OBJC_FLAGS \"${CMAKE_OBJC_FLAGS} ${" + marker + "}\")\n" + - "endif\n"; - content = content + "\n" + flagBlock; - Files.write(cmakeLists, content.getBytes(StandardCharsets.UTF_8)); + final String marker = "CN1_LITERAL_RANGE_FLAGS"; + String content = Files.readString(cmakeLists, StandardCharsets.UTF_8); + if (content.contains(marker)) { + return; + } + + String newline = System.lineSeparator(); + StringBuilder amended = new StringBuilder(content); + if (!content.endsWith("\n") && !content.endsWith("\r\n")) { + amended.append(newline); } + + amended.append("set(").append(marker).append(" \"-Wno-error=literal-range -Wno-literal-range\")").append(newline) + .append("if (CMAKE_C_COMPILER_ID MATCHES \"Clang\")").append(newline) + .append(" set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${").append(marker).append("}\")").append(newline) + .append("endif").append(newline) + .append("if (CMAKE_OBJC_COMPILER_ID MATCHES \"Clang\")").append(newline) + .append(" set(CMAKE_OBJC_FLAGS \"${CMAKE_OBJC_FLAGS} ${").append(marker).append("}\")").append(newline) + .append("endif").append(newline); + + Files.writeString(cmakeLists, amended.toString(), StandardCharsets.UTF_8); } static List cmakeCompilerArgs() { From 7d51e3aa0302800cae0c7cd4c55519d6eb678a42 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Tue, 6 Jan 2026 04:19:14 +0200 Subject: [PATCH 11/13] Use Java 8 compatible file IO in CleanTargetIntegrationTest --- .../tools/translator/CleanTargetIntegrationTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 57a7f1b289..9b0ffba715 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -192,7 +192,7 @@ static void replaceLibraryWithExecutableTarget(Path cmakeLists, String sourceDir static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { final String marker = "CN1_LITERAL_RANGE_FLAGS"; - String content = Files.readString(cmakeLists, StandardCharsets.UTF_8); + String content = new String(Files.readAllBytes(cmakeLists), StandardCharsets.UTF_8); if (content.contains(marker)) { return; } @@ -211,7 +211,7 @@ static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { .append(" set(CMAKE_OBJC_FLAGS \"${CMAKE_OBJC_FLAGS} ${").append(marker).append("}\")").append(newline) .append("endif").append(newline); - Files.writeString(cmakeLists, amended.toString(), StandardCharsets.UTF_8); + Files.write(cmakeLists, amended.toString().getBytes(StandardCharsets.UTF_8)); } static List cmakeCompilerArgs() { From 77cb6126b8c2cc01628e0fa454080ab7536a1b19 Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Tue, 6 Jan 2026 07:09:07 +0200 Subject: [PATCH 12/13] Fix literal-range flag injection formatting --- .../codename1/tools/translator/CleanTargetIntegrationTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 9b0ffba715..1ec87f5e71 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -203,7 +203,8 @@ static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { amended.append(newline); } - amended.append("set(").append(marker).append(" \"-Wno-error=literal-range -Wno-literal-range\")").append(newline) + amended.append("# CN1 literal-range warning relaxation").append(newline) + .append("set(").append(marker).append(" \"-Wno-error=literal-range -Wno-literal-range\")").append(newline) .append("if (CMAKE_C_COMPILER_ID MATCHES \"Clang\")").append(newline) .append(" set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${").append(marker).append("}\")").append(newline) .append("endif").append(newline) From a968283701bd6a5d7a41d5811869ccf319f76eca Mon Sep 17 00:00:00 2001 From: Shai Almog <67850168+shai-almog@users.noreply.github.com> Date: Wed, 7 Jan 2026 21:05:02 +0200 Subject: [PATCH 13/13] Fix literal-range block spacing --- .../translator/CleanTargetIntegrationTest.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java index 1ec87f5e71..7eeb3835a1 100644 --- a/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java +++ b/vm/tests/src/test/java/com/codename1/tools/translator/CleanTargetIntegrationTest.java @@ -197,13 +197,10 @@ static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { return; } - String newline = System.lineSeparator(); - StringBuilder amended = new StringBuilder(content); - if (!content.endsWith("\n") && !content.endsWith("\r\n")) { - amended.append(newline); - } - - amended.append("# CN1 literal-range warning relaxation").append(newline) + String newline = "\n"; + StringBuilder block = new StringBuilder(); + block.append(newline) + .append("# CN1 literal-range warning relaxation").append(newline) .append("set(").append(marker).append(" \"-Wno-error=literal-range -Wno-literal-range\")").append(newline) .append("if (CMAKE_C_COMPILER_ID MATCHES \"Clang\")").append(newline) .append(" set(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${").append(marker).append("}\")").append(newline) @@ -212,6 +209,12 @@ static void relaxLiteralRangeWarnings(Path cmakeLists) throws IOException { .append(" set(CMAKE_OBJC_FLAGS \"${CMAKE_OBJC_FLAGS} ${").append(marker).append("}\")").append(newline) .append("endif").append(newline); + StringBuilder amended = new StringBuilder(content); + if (!content.endsWith("\n") && !content.endsWith("\r\n")) { + amended.append(newline); + } + amended.append(block); + Files.write(cmakeLists, amended.toString().getBytes(StandardCharsets.UTF_8)); }