Create new branch named "wip-jvlite2imodeapp"
[SquirrelJME.git] / emulators / emulator-base / build.gradle
blobf8756c384772a68cc8cdbb18a114b6bb345edc8b
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
7 plugins
9         // C++ needs to be first otherwise the build will break
10         id "cpp-library"
11         id "java-library"
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) {
24         library {
25                         targetMachines.add(machines.linux.x86_64)
26         }
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) {
33         library {
34                 targetMachines.add(machines.macOS.x86_64)
35         }
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.
42 dependencies
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
64 jar {
65         dependsOn (useDebugLib ? "assembleDebug" : "assembleRelease")
66         
67         java.nio.file.Path libPath = buildDir.toPath().resolve("lib")
68                 .resolve("main").resolve((useDebugLib ? "debug" : "release"))
69         project.ext.libPathBase = libPath
71         from libPath.toFile()
72         into "/"
75 java {
76         // Use a fixed version of the JVM
77         compileJava
78         {
79                 sourceCompatibility = JavaVersion.VERSION_1_8
80                 targetCompatibility = JavaVersion.VERSION_1_8
81                 
82                 // Use the default bootstrap classpath
83                 options.bootstrapClasspath = null
84         }
86         // Maximize debugging
87         compileJava.options.debug = true
88         compileJava.options.debugOptions.setDebugLevel("source,lines,vars")
90         // Copy settings
91         compileTestJava.options.debug = compileJava.options.debug
92         compileTestJava.options.debugOptions = compileJava.options.debugOptions
93         
94         javadoc.options.tags = [ "squirreljme.property",
95                 "squirreljme.env",
96                 "squirreljme.error",
97                 "squirreljme.syscallparam",
98                 "squirreljme.syscallreturn",
99                 "squirreljme.tsiparam",
100                 "squirreljme.configtype",
101                 "squirreljme.uiwidgetparam" ]
104 // Are we on Mac OS?
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
111         try {
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")
117                         
118                         if (Files.exists(tryPath) && Files.isExecutable(tryPath)) {
119                                 clangExe = tryPath
120                                 break
121                         }
122                 }
123                 
124                 // Nothing found? Then we could not detect at all
125                 if (clangExe == null) {
126                         return false
127                 }
128                 
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,
135                         Arrays.asList(
136                                 "int main(int argc, char** argv) { return 0; }"
137                         ),
138                         StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING,
139                         StandardOpenOption.WRITE)
140                 
141                 // Just assume we are using the default clang
142                 ProcessBuilder processBuilder = new ProcessBuilder()
143                 processBuilder.command(
144                         clangExe.toAbsolutePath().toString(),
145                         "-arch",
146                         arch,
147                         "-o",
148                         tempOutput.toAbsolutePath().toString(),
149                         "--",
150                         tempSource.toAbsolutePath().toString())
151                 processBuilder.redirectOutput(ProcessBuilder.Redirect.PIPE)
152                 processBuilder.redirectError(ProcessBuilder.Redirect.PIPE)
153                 
154                 // Run and check for success
155                 Process process = processBuilder.start()
156                 if (!process.waitFor(6, TimeUnit.SECONDS)) {
157                         return false
158                 }
159                 
160                 // Did this work or fail?
161                 int exitCode = process.exitValue()
162                 
163                 // Some debugging
164                 String stdOut = new String(process.getInputStream().bytes)
165                 String stdErr = new String(process.getErrorStream().bytes)
166                 
167                 logger.debug("Clang ExitCode: " + exitCode)
168                 if (stdOut.length() > 0) {
169                         logger.lifecycle("Clang StdOut: " + stdOut)
170                 }
171                 if (stdErr.length() > 0) {
172                         logger.error("Clang StdErr: " + stdErr)
173                 }
174                 
175                 // Did this work?
176                 if (0 == exitCode) {
177                         return true
178                 }
179         } catch (IOException e) {
180                 logger.error("Could not determine compiler support.", e)
181         } finally {
182                 try {
183                         if (tempSource != null)
184                                 Files.deleteIfExists(tempSource)
185                 } catch (IOException ignored) {
186                 }
188                 try {
189                         if (tempOutput != null)
190                                 Files.deleteIfExists(tempOutput)
191                 } catch (IOException ignored) {
192                 }
193         }
194         
195         // Failure here
196         return false
199 // Collects all of the arches available for Mac OS
200 List<String> getMacOsArchArguments(ToolChain toolChain) {
201         List<String> result = new ArrayList<>()
202         
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))
206                 
207                 if (checkMacOsArch(toolChain, arch)) {
208                         result.add("-arch")
209                         result.add(arch)
210                 }
211         }
212                 
213         return result
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")
221         if (!isRelease) {
222                 item.debuggable = true
223                 item.optimized = false
224         }
225         
226         // Additional compiler options for each compiler
227         item.compilerArgs.addAll toolChain.map { toolChain ->
228                 // Clang on Mac OS
229                 if (isOnMacOs && "clang".equalsIgnoreCase(toolChain.name)) {
230                         return getMacOsArchArguments(toolChain)
231                 }
232                 
233                 // Microsoft Visual C++
234                 if ("visualCpp".equalsIgnoreCase(toolChain.name)) {
235                         if (!isRelease) {
236                                 return [
237                                         // Disable optimization
238                                         "/Od",
239                                 
240                                         // Buffer security check
241                                         "/GS",
242                                         
243                                         // Run-time error checking
244                                         "/RTC",
245                                         
246                                         // Enable all warnings
247                                         "/Wall",
248                                         
249                                         // Our object files contain _full_ debug info
250                                         "/Z7",
251                                         
252                                         // End
253                                         ]
254                         }
255                 }
256                 
257                 return []
258         }
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")
265         if (!isRelease) {
266                 item.getDebuggable().set(true)
267         }
268         
269         // Additional compiler options for each compiler
270         item.linkerArgs.addAll toolChain.map { toolChain ->
271                 // Clang on Mac OS
272                 if (isOnMacOs && "clang".equalsIgnoreCase(toolChain.name)) {
273                         return getMacOsArchArguments(toolChain)
274                 }
275                 
276                 // Microsoft Visual C++
277                 if ("visualCpp".equalsIgnoreCase(toolChain.name)) {
278                         if (!isRelease) {
279                                 return [
280                                         // Full debug info
281                                         "/DEBUG:FULL",
282                                         
283                                         // Create map file
284                                         "/MAP"
285                                 
286                                         // End
287                                         ]
288                         }
289                 }
290                 
291                 return []
292         }