1 import java.nio.file.Files
2 import java.nio.file.Paths
3 import java.nio.file.StandardOpenOption
4 import java.util.concurrent.TimeUnit
5 import java.util.regex.Pattern
9 // C++ needs to be first otherwise the build will break
14 description = "This library provides the base support for testing and " +
15 "running SquirrelJME on a Java SE host, which is normally not " +
16 "capable of doing as such."
18 // If running on Termux on Android, we need to do some changes accordingly
19 // so that the C compiler is found and things link... We technically are not
20 // on x86_64 but it really does not matter anyway as long as it passes
21 // -m64 correctly when on Android.
22 if (project.hasProperty("squirreljmeTermuxCompiler") &&
23 project.squirreljmeTermuxCompiler) {
25 targetMachines.add(machines.linux.x86_64)
29 // Gradle does not support C++ compilation on M1 Macs currently, so this
30 // is a bit of a workaround
31 if (project.hasProperty("squirreljmeMacOsArmCpp") &&
32 project.squirreljmeMacOsArmCpp) {
34 targetMachines.add(machines.macOS.x86_64)
38 // Due to the combination of C++ and Java these dependencies have to be very
39 // specific in that they only refer to the Java or C++ portion. So
40 // "implementation" and "compile" cannot be used because the C++ library will
41 // try to use them during compilation.
44 // We need these two modules to obtain the SquirrelJME specific classes
45 compileClasspath project(":modules:cldc-compact")
46 compileClasspath project(":modules:common-vm")
47 compileClasspath project(":modules:io")
48 compileClasspath project(":modules:tac")
49 compileClasspath project(":modules:zip")
50 compileClasspath project(":modules:debug-jdwp")
52 // And for run-time to be able to be ran
53 runtimeClasspath project(":modules:cldc-compact")
54 runtimeClasspath project(":modules:common-vm")
55 runtimeClasspath project(":modules:io")
56 runtimeClasspath project(":modules:tac")
57 runtimeClasspath project(":modules:zip")
58 runtimeClasspath project(":modules:debug-jdwp")
61 // We need the native library in the JAR before we can properly use it
62 // But we can compile the Java code just fine without it
63 boolean useDebugLib = false
65 dependsOn (useDebugLib ? "assembleDebug" : "assembleRelease")
67 java.nio.file.Path libPath = buildDir.toPath().resolve("lib")
68 .resolve("main").resolve((useDebugLib ? "debug" : "release"))
69 project.ext.libPathBase = libPath
76 // Use a fixed version of the JVM
79 sourceCompatibility = JavaVersion.VERSION_1_8
80 targetCompatibility = JavaVersion.VERSION_1_8
82 // Use the default bootstrap classpath
83 options.bootstrapClasspath = null
87 compileJava.options.debug = true
88 compileJava.options.debugOptions.setDebugLevel("source,lines,vars")
91 compileTestJava.options.debug = compileJava.options.debug
92 compileTestJava.options.debugOptions = compileJava.options.debugOptions
94 javadoc.options.tags = [ "squirreljme.property",
97 "squirreljme.syscallparam",
98 "squirreljme.syscallreturn",
99 "squirreljme.tsiparam",
100 "squirreljme.configtype",
101 "squirreljme.uiwidgetparam" ]
105 def isOnMacOs = project.hasProperty("squirreljmeIsOnMacOs") &&
106 project.squirreljmeIsOnMacOs
108 // Method to check which arches are available for compile on Mac OS
109 boolean checkMacOsArch(ToolChain toolChain, String arch) {
110 java.nio.file.Path tempSource, tempOutput
112 // Try to find the clang executable
113 java.nio.file.Path clangExe = null
114 for (String pathLet in System.getenv("PATH")
115 .split(Pattern.quote(File.pathSeparator))) {
116 java.nio.file.Path tryPath = Paths.get(pathLet).resolve("clang")
118 if (Files.exists(tryPath) && Files.isExecutable(tryPath)) {
124 // Nothing found? Then we could not detect at all
125 if (clangExe == null) {
129 // Create temporary file to compile
130 tempSource = Files.createTempFile(
131 "squirreljme-test-arch", ".c")
132 tempOutput = Files.createTempFile(
133 "squirreljme-test-arch", ".out")
134 Files.write(tempSource,
136 "int main(int argc, char** argv) { return 0; }"
138 StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING,
139 StandardOpenOption.WRITE)
141 // Just assume we are using the default clang
142 ProcessBuilder processBuilder = new ProcessBuilder()
143 processBuilder.command(
144 clangExe.toAbsolutePath().toString(),
148 tempOutput.toAbsolutePath().toString(),
150 tempSource.toAbsolutePath().toString())
151 processBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE)
152 processBuilder.redirectError(ProcessBuilder.Redirect.PIPE)
154 // Run and check for success
155 Process process = processBuilder.start()
156 if (!process.waitFor(6, TimeUnit.SECONDS)) {
160 // Did this work or fail?
161 int exitCode = process.exitValue()
164 String stdOut = new String(process.getInputStream().bytes)
165 String stdErr = new String(process.getErrorStream().bytes)
167 logger.debug("Clang ExitCode: " + exitCode)
168 if (stdOut.length() > 0) {
169 logger.lifecycle("Clang StdOut: " + stdOut)
171 if (stdErr.length() > 0) {
172 logger.error("Clang StdErr: " + stdErr)
179 } catch (IOException e) {
180 logger.error("Could not determine compiler support.", e)
183 if (tempSource != null)
184 Files.deleteIfExists(tempSource)
185 } catch (IOException ignored) {
189 if (tempOutput != null)
190 Files.deleteIfExists(tempOutput)
191 } catch (IOException ignored) {
199 // Collects all of the arches available for Mac OS
200 List<String> getMacOsArchArguments(ToolChain toolChain) {
201 List<String> result = new ArrayList<>()
203 // Check all of these at once! If none found will default to nothing.
204 for (String arch in [ "ppc", "i686", "x86_64", "arm64" ]) {
205 logger.debug(String.format("Checking %s%n", arch))
207 if (checkMacOsArch(toolChain, arch)) {
216 // Improve debugging with native code compiles, these are only used by the
217 // build system tests so these do not impact users at all
218 tasks.withType(CppCompile).configureEach() {item ->
219 // Only set for non-debugging targets
220 boolean isRelease = item.name.toLowerCase().contains("release")
222 item.debuggable = true
223 item.optimized = false
226 // Additional compiler options for each compiler
227 item.compilerArgs.addAll toolChain.map { toolChain ->
229 if (isOnMacOs && "clang".equalsIgnoreCase(toolChain.name)) {
230 return getMacOsArchArguments(toolChain)
233 // Microsoft Visual C++
234 if ("visualCpp".equalsIgnoreCase(toolChain.name)) {
237 // Disable optimization
240 // Buffer security check
243 // Run-time error checking
246 // Enable all warnings
249 // Our object files contain _full_ debug info
261 // Ensure debugging information is used when linking
262 tasks.withType(LinkSharedLibrary).configureEach() { item ->
263 // Only set for non-debugging targets
264 boolean isRelease = item.name.toLowerCase().contains("release")
266 item.getDebuggable().set(true)
269 // Additional compiler options for each compiler
270 item.linkerArgs.addAll toolChain.map { toolChain ->
272 if (isOnMacOs && "clang".equalsIgnoreCase(toolChain.name)) {
273 return getMacOsArchArguments(toolChain)
276 // Microsoft Visual C++
277 if ("visualCpp".equalsIgnoreCase(toolChain.name)) {