1 /* vim: set ft=java: 
  2  *
  3  * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.  Oracle designates this
  9  * particular file as subject to the "Classpath" exception as provided
 10  * by Oracle in the LICENSE file that accompanied this code.
 11  *
 12  * This code is distributed in the hope that it will be useful, but WITHOUT
 13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 15  * version 2 for more details (a copy is included in the LICENSE file that
 16  * accompanied this code).
 17  *
 18  * You should have received a copy of the GNU General Public License version
 19  * 2 along with this work; if not, write to the Free Software Foundation,
 20  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 21  *
 22  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 23  * or visit www.oracle.com if you need additional information or have any
 24  * questions.
 25  */
 26 
 27 import static bldr.Bldr.*;
 28 import static bldr.Bldr.Capabilities.*;
 29 
 30 void main(String[] argv) {
 31    var pomComment = """
 32       Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
 33       DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 34 
 35       This code is free software; you can redistribute it and/or modify it
 36       under the terms of the GNU General Public License version 2 only, as
 37       published by the Free Software Foundation.  Oracle designates this
 38       particular file as subject to the "Classpath" exception as provided
 39       by Oracle in the LICENSE file that accompanied this code.
 40 
 41       This code is distributed in the hope that it will be useful, but WITHOUT
 42       ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 43       FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 44       version 2 for more details (a copy is included in the LICENSE file that
 45       accompanied this code).
 46 
 47       You should have received a copy of the GNU General Public License version
 48       2 along with this work; if not, write to the Free Software Foundation,
 49       Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 50 
 51       Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 52       or visit www.oracle.com if you need additional information or have any
 53       questions.                
 54       """;
 55 
 56   var hatDir = DirEntry.current();
 57   var hatCore = hatDir.existingDir("hat");
 58   var backends = hatDir.existingDir("backends");
 59   var examples = hatDir.existingDir("examples");
 60   var extractions = hatDir.existingDir("extractions");
 61   var buildDir = hatDir.existingBuildDir("build");
 62 
 63   var opencl = OpenCL.of();
 64   var opengl = OpenGL.of();
 65   var cuda = CUDA.of();
 66   var hip = HIP.of();
 67   var jextract = JExtract.of();
 68   var cmake = CMake.of();
 69 
 70   var capabilities = Capabilities.of(opencl, opengl, cuda, hip, jextract, cmake);
 71 
 72   if (cmake.available()) {
 73     cmake.probe(buildDir, capabilities);
 74   }
 75   capabilities.capabilities().forEach(fw -> println((fw.available() ? "we have " : "no ") + fw.name));
 76 
 77   hatDir.pom(pomComment, pom -> pom
 78       .comment("Auto generated by mkpoms")
 79       .pom("oracle.code", "hat-root", "1.0")
 80       .properties(properties -> properties
 81           .property("project.build.sourceEncoding", "UTF-8")
 82           .property("hat.root", "${env.PWD}")
 83           .property("hat.build", "${hat.root}/build")
 84           .property("hat.stage", "${hat.root}/stage")
 85           .property("hat.stage.repo", "${hat.stage}/repo")
 86           .property("hat.stage.jextract", "${hat.stage}/jextract")
 87           .property("mac.app.frameworks", "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks")
 88           .property("mac.lib.frameworks", "/System/Library/Frameworks")
 89       )
 90       .modules("hat", "extractions", "backends", "examples")
 91       .build(build -> build
 92           .plugins(plugins -> plugins
 93               .compilerPlugin(plugin -> plugin
 94                   .configuration(configuration -> configuration
 95                       .compilerArgs(
 96                           "--add-modules=jdk.incubator.code",
 97                           "--enable-preview",
 98                           "--add-exports=java.base/jdk.internal=ALL-UNNAMED",
 99                           "--add-exports=java.base/jdk.internal.vm.annotation=ALL-UNNAMED"
100                       )
101                       .source("24")
102                       .target("24")
103                       .showDeprecation("true")
104                       .failOnError("true")
105                       .showWarnings("true")
106                   )
107               )
108           )
109       )
110   );
111 
112   // Now hat/pom.xml
113   hatCore.pom(pomComment, pom -> pom
114       .comment("Auto generated by mkpoms")
115       .jar("oracle.code", "hat", "1.0")
116       .parent("oracle.code", "hat-root", "1.0")
117       .dependsOn("org.junit.jupiter", "junit-jupiter-engine", "5.10.0", "test")
118       .build(build -> build
119           .pluginManagement(pluginManagement -> pluginManagement
120               .plugins(plugins -> plugins
121                   .surefirePlugin(plugin -> plugin
122                       .configuration(configuration -> configuration
123                           .argLine("-enable-preview")
124                       )
125                   )
126               )
127           )
128           .plugins(plugins -> plugins
129               .antPlugin(plugin -> plugin
130                   .executions(executions -> executions
131                       .ant("1", "install", "run", ant -> ant
132                           .copy("target/${project.artifactId}-1.0.jar", "${hat.build}")
133                       )
134                   )
135               )
136           )
137       )
138   );
139 
140   // Note that we filter by capability here. So we only create poms (and include modules in parent) if capability is available
141   var extractionDirs = extractions
142       .subDirs(extraction -> !extraction.matches("^.*(target)$")).filter(dir -> capabilities.capabilityIsAvailable(dir.fileName())).toList();
143 
144   extractions.pom(pomComment, pom -> pom
145       .comment("Auto generated by mkpoms")
146       .pom("oracle.code", "hat-extractions", "1.0")
147       .parent("oracle.code", "hat-root", "1.0")
148       .modules(extractionDirs.stream().map(PathHolder::fileName).toList())
149       .build(build -> build
150           .plugins(plugins -> plugins
151               .antPlugin(plugin -> plugin
152                   .executions(executions -> executions
153                       .ant("createDir", "compile", "run", ant -> ant
154                           .mkdir("${hat.stage.jextract}")
155                           .echo("${hat.stage.jextract}/compile_flags.txt", "-F${mac.app.frameworks}")
156                       )
157                   )
158               )
159           )
160 
161       )
162   );
163 
164   extractionDirs.forEach(extraction -> extraction
165       .pom(pomComment, examplePom -> examplePom
166           .comment("Auto generated by mkpoms")
167           .pom("oracle.code", "hat-extraction-" + extraction.fileName(), "1.0")
168           .parent("oracle.code", "hat-extractions", "1.0")
169           .build(build -> build
170               .plugins(plugins -> plugins
171                   .execPlugin(plugin -> plugin
172                       .executions(execution -> execution
173                           .execIdPhaseConf("2", "compile", configuration -> configuration
174                               .executable("jextract")
175                               .workingDirectory("${hat.stage.jextract}")
176                               .arguments(arguments -> {
177                                 arguments
178                                     .argument("--output").argument("${hat.stage.jextract}")
179                                     .argument("-t").argument(extraction.fileName());
180                                 switch (extraction.fileName()) {
181                                   case "opencl" -> arguments
182                                       .argument("-l").argument("${mac.lib.frameworks}/OpenCL.framework/OpenCL")
183                                       .argument("${mac.app.frameworks}/OpenCL.framework/Headers/opencl.h");
184                                   case "opengl" -> arguments
185                                       .argument("-l").argument("${mac.lib.frameworks}/GLUT.framework/GLUT")
186                                       .argument("-l").argument("${mac.lib.frameworks}/OpenGL.framework/OpenGL")
187                                       .argument("${mac.app.frameworks}/GLUT.framework/Headers/glut.h");
188                                   default ->
189                                       throw new IllegalStateException("Unexpected value: " + extraction.fileName());
190                                 }
191                               })
192                           )
193                       )
194                   )
195                   .antPlugin(plugin -> plugin
196                       .executions(executions -> executions
197                           .ant("1", "install", "run", ant -> ant
198                                    .antjar("${hat.stage.jextract}", extraction.fileName(), "${hat.build}/jextracted-" + extraction.fileName() + "-1.0.jar")
199                                //.copy("target/jextracted" + extraction.fileName() + "-1.0.jar", "${hat.build}")
200                           )
201                       )
202                   )
203               )
204           )
205       )
206   );
207 
208   var exampleDirs = examples.subDirs(example -> !example.matches("^.*(experiments|target|nbody|.idea)$")).toList();
209 
210   // Here we create examples/pom.xml and nested inside we create each example/*/pom.xml
211   examples.pom(pomComment, examplesPom -> examplesPom
212       .comment("Auto generated by mkpoms")
213       .pom("oracle.code", "hat-examples", "1.0")
214       .parent("oracle.code", "hat-root", "1.0")
215       .dependsOn("oracle.code", "hat", "1.0")
216       .modules(exampleDirs.stream().map(PathHolder::fileName).toList())
217   );
218 
219   exampleDirs.forEach(example -> example
220       .pom(pomComment, examplePom -> examplePom
221           .comment("Auto generated by mkpoms")
222           .jar("oracle.code", "hat-example-" + example.fileName(), "1.0")
223           .parent("oracle.code", "hat-examples", "1.0")
224           .dependsOn("oracle.code", "hat", "1.0")
225           .build(build -> build
226               .plugins(plugins -> plugins
227                   .antPlugin(plugin -> plugin
228                       .executions(executions -> executions
229                           .ant("1", "install", "run", ant -> ant
230                               .copy("target/hat-example-" + example.fileName() + "-1.0.jar", "${hat.build}")
231                           )
232                       )
233                   )
234               )
235           )
236       )
237   );
238   var backendDirs = backends.subDirs(backend -> !backend.matches("^.*(jextracted|target|.idea)$")).toList();
239 
240   // Now backends/pom.xml and backends/*/pom.xml
241   backends.pom(pomComment, backendsPom -> backendsPom
242       .comment("Auto generated by mkpoms")
243       .pom("oracle.code", "hat-backends", "1.0")
244       .parent("oracle.code", "hat-root", "1.0")
245       .dependsOn("oracle.code", "hat", "1.0")
246       .modules("java", "ffi")
247   );
248 
249   {
250     var ffiBackend = backends.dir("ffi");
251 
252 
253     var ffiBackendDirs = ffiBackend.subDirs(backend -> !backend.matches("^.*(hip|spirv|shared|openclx|target|.idea)$")).toList();
254 
255     ffiBackend.pom(pomComment, backendsPom -> backendsPom
256         .comment("Auto generated by mkpoms")
257         .pom("oracle.code", "hat-backends-ffi", "1.0")
258         .parent("oracle.code", "hat-backends", "1.0")
259         .dependsOn("oracle.code", "hat", "1.0")
260         .modules(ffiBackendDirs.stream().map(PathHolder::fileName).toList())
261         .build(build -> build
262             .plugins(plugins -> plugins
263                 .execPlugin(plugin -> plugin
264                     .executions(executions -> executions
265                         .cmake("1", "compile", "-DHAT_TARGET=${hat.build}", "-B", "${hat.build}/cmake-build-debug")
266                         .cmake("2", "install", "--build", "${hat.build}/cmake-build-debug")
267                     )
268                 )
269             )
270         )
271     );
272 
273     ffiBackendDirs.forEach(backend -> backend
274         .pom(pomComment, backendPom -> backendPom
275             .comment("Auto generated by mkpoms")
276             .jar("oracle.code", "hat-backend-ffi-" + backend.fileName(), "1.0")
277             .parent("oracle.code", "hat-backends-ffi", "1.0")
278             .dependsOn("oracle.code", "hat", "1.0")
279             .build(build -> build
280                 .plugins(plugins -> plugins
281                     .execPlugin(plugin -> plugin
282                         .configuration(configuration -> configuration
283                             .skip("true")
284                         )
285                     )
286                     .antPlugin(plugin -> plugin
287                         .executions(executions -> executions
288                             .ant("1", "install", "run", ant -> ant
289                                 .copy("target/hat-backend-ffi-" + backend.fileName() + "-1.0.jar", "${hat.build}")
290                             )
291                         )
292                     )
293                 )
294             )
295         )
296     );
297   }
298   {
299     var javaBackend = backends.dir("java");
300     var javaBackendDirs = javaBackend.subDirs(backend -> !backend.matches("^.*(target|.idea)$")).toList();
301 
302     javaBackend.pom(pomComment, backendsPom -> backendsPom
303         .comment("Auto generated by mkpoms")
304         .pom("oracle.code", "hat-backends-java", "1.0")
305         .parent("oracle.code", "hat-backends", "1.0")
306         .dependsOn("oracle.code", "hat", "1.0")
307         .modules(javaBackendDirs.stream().map(PathHolder::fileName).toList())
308     );
309 
310     javaBackendDirs.forEach(backend -> backend
311         .pom(pomComment, backendPom -> backendPom
312             .comment("Auto generated by mkpoms")
313             .jar("oracle.code", "hat-backend-java-" + backend.fileName(), "1.0")
314             .parent("oracle.code", "hat-backends-java", "1.0")
315             .dependsOn("oracle.code", "hat", "1.0")
316             .build(build -> build
317                 .plugins(plugins -> plugins
318                     .antPlugin(plugin -> plugin
319                         .executions(executions -> executions
320                             .ant("1", "install", "run", ant -> ant
321                                 .copy("target/hat-backend-java-" + backend.fileName() + "-1.0.jar", "${hat.build}")
322                             )
323                         )
324                     )
325                 )
326             )
327         )
328     );
329   }
330 
331 
332   var backendJExtracted = backends.dir("jextracted");
333 
334 }