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 
 29 void main(String[] args) {
 30 
 31     /*
 32      *  ./
 33      *    +--build/                     All jars, native libs and executables
 34      *    |    +--cmake-build-debug/    All intermediate cmake artifacts
 35      *    |
 36      *    +--stage/
 37      *    |    +--repo/                 All downloaded maven assets
 38      *    |    |
 39      *    |    +--jextract/             All jextracted files
 40      *    |    |    +--opencl
 41      *    |    |    +--opengl
 42      *    |    |    +--cuda
 43      *    |
 44      *    +--hat                        * Note maven style layout
 45      *    |    +--src/main/java
 46      *    |    |    +--hat/
 47      *    |    |
 48      *    |    +--src/main/test
 49      *    |         +--hat/
 50      *    |
 51      *    +--backends
 52      *    |    +--java
 53      *    |    |    +--mt                    (*)
 54      *    |    |    +--seq                   (*)
 55      *    |    +--jextracted
 56      *    |    |    +--opencl                (*)
 57      *    |    +--ffi
 58      *    |    |    +--opencl                (*)
 59      *    |    |    +--ptx                   (*)
 60      *    |    |    +--mock                  (*)
 61      *    |    |    +--spirv                 (*)
 62      *    |    |    +--cuda                  (*)
 63      *    |    |    +--hip                   (*)
 64      *    |
 65      *    +--examples
 66      *    |    +--mandel                (*)
 67      *    |    +--squares               (*)
 68      *    |    +--heal                  (*)
 69      *    |    +--life                  (*)
 70      *    |    +--violajones            (*)
 71      *
 72      */
 73 
 74     var hatDir = DirEntry.current();
 75   var hatCoreDir = hatDir.existingDir("hat");
 76   var backends = hatDir.existingDir("backends");
 77   var examples = hatDir.existingDir("examples");
 78   var stageDir = hatDir.buildDir("stage").create();
 79   var jextractDir = stageDir.buildDir("jextract").create();
 80   var buildDir = BuildDir.of(hatDir.path("build")).create();
 81   var cmakeBuildDir = buildDir.cMakeBuildDir("cmake-build-debug");
 82 
 83   var extractedOpenCLJar = buildDir.jarFile("jextracted-opencl.jar");
 84   var extractedOpenGLJar = buildDir.jarFile("jextracted-opengl.jar");
 85 
 86   var opencl = Capabilities.OpenCL.of();
 87   var opengl = Capabilities.OpenGL.of();
 88   var cuda = Capabilities.CUDA.of();
 89   var hip = Capabilities.HIP.of();
 90   var jextract = Capabilities.JExtract.of();
 91   var cmake = Capabilities.CMake.of();
 92 
 93   Capabilities capabilities = Capabilities.of(opencl, opengl, cuda, hip, jextract, cmake);
 94 
 95   if (cmake.available()) {
 96     cmake.probe(buildDir, capabilities);
 97   }
 98   capabilities.capabilities().forEach(fw -> println((fw.available() ? "we have " : "no ") + fw.name));
 99   var verbose = false;
100 
101 
102   if (jextract.available()) {
103     if (opencl.available()) {
104       if (!extractedOpenCLJar.exists()) {
105         var openclSource = jextractDir.sourceDir("opencl");
106         if (!openclSource.exists()) {
107           jextract(jextract.executable, $ -> {
108             $
109               .verbose(verbose)
110               .output(jextractDir)
111               .target_package(openclSource.fileName());
112             switch (os) {
113               case OS.Mac mac -> {
114                 $
115                   .compile_flag("-F" + opencl.appLibFrameworks() + "/System/library/Frameworks")
116                   .library(mac.frameworkLibrary("OpenCL"))
117                   //.library(Path.of(opencl.lib()))
118                   .header(Path.of(opencl.includeDir()).resolve("Headers/opencl.h"));
119               }
120               case OS.Linux linux -> {
121               }
122               default -> throw new RuntimeException("Unsupported OS: " + os);
123             }
124           });
125         }
126         jar(jar -> {
127               jar
128                 .jar(extractedOpenCLJar)
129                 .javac(javac -> javac.source(24).source_path(openclSource));
130             }
131         );
132       }
133     } else {
134       println("This platform does not have OpenCL");
135     }
136 
137     if (opengl.available()) {
138       if (!extractedOpenGLJar.exists()) {
139         var openglSource = jextractDir.sourceDir("opengl");
140         if (!openglSource.exists()) {
141           jextract(jextract.executable, $ -> { $
142               .verbose(verbose)
143               .output(jextractDir)
144               .target_package(openglSource.fileName());
145             switch (os) {
146               case OS.Mac mac -> { $
147                   .compile_flag("-F" + opengl.appLibFrameworks() + "/System/library/Frameworks")
148                   //.library(opengl.lib("GLUT"),opengl.lib("OpenGL"))
149                   .library(mac.frameworkLibrary("GLUT"), mac.frameworkLibrary("OpenGL"))
150                   .header(mac.frameworkHeader("GLUT", "glut.h"));
151               }
152               case OS.Linux linux -> {
153               }
154               default -> throw new RuntimeException("Unsupported OS: " + os);
155             }
156           });
157         }
158         jar(jar -> jar
159           .jar(extractedOpenGLJar)
160           .javac(javac -> javac.source(24).source_path(openglSource))
161         );
162       }
163     } else {
164       println("This platform does not have OpenGL");
165     }
166 
167 
168     if (cuda.available()) {
169 
170     } else {
171       println("This platform does not have CUDA");
172     }
173   }
174   var hatJavacOpts = javacBuilder(javacBuilder -> {javacBuilder
175     .enable_preview()
176     .add_modules("jdk.incubator.code")
177     .add_exports(
178        "java.base",
179        List.of(
180           "jdk.internal",
181           "jdk.internal.vm.annotation"
182        ),
183        "ALL-UNNAMED"
184     )
185     .source(24);
186   });
187 
188   var hatJarOptions = jarBuilder(jarBuilder -> jarBuilder
189     .verbose(verbose)
190   );
191   var hatJarFile = buildDir.jarFile("hat-1.0.jar");
192   jar(jar -> jar
193     .copy(hatJarOptions)
194     .jar(hatJarFile)
195     .maven_style_root(hatCoreDir)
196     .javac(javac -> javac.copy(hatJavacOpts))
197   );
198 
199 
200   // Here we create all backend jars.
201   var ffiBackends = backends.existingDir("ffi");
202   ffiBackends
203     .subDirs(backend -> !backend.matches("^.*(spirv|hip|shared|target|.idea)$"))
204     .forEach(backend -> {
205       var jarFile = buildDir.jarFile("hat-backend-ffi-" + backend.fileName() + "-1.0.jar");
206       println(jarFile.fileName());
207       jar(jar -> jar.copy(hatJarOptions)
208         .jar(jarFile)
209         .maven_style_root(backend)
210         .javac(javac -> javac.copy(hatJavacOpts).class_path(hatJarFile))
211       );
212     });
213 
214   // Here we create all java backend jars.
215   var javaBackends = backends.existingDir("java");
216   javaBackends
217     .subDirs(backend -> !backend.matches("^.*(target|.idea)$"))
218     .forEach(backend -> {
219       var jarFile = buildDir.jarFile("hat-backend-java-" + backend.fileName() + "-1.0.jar");
220       println(jarFile.fileName());
221       jar(jar -> jar
222             .copy(hatJarOptions)
223             .jar(jarFile)
224             .dir_list(backend.dir("src/main/resources"))
225           //.maven_style_root(backend)
226       );
227     });
228 
229 
230   // here we create the example jars
231   examples
232     .subDirs(example -> !example.matches("^.*(experiments|nbody|target|.idea)$"))
233     .forEach(example -> {
234       var jarFile = buildDir.jarFile("hat-example-" + example.fileName() + "-1.0.jar");
235       println(jarFile.fileName());
236       jar(jar -> jar.copy(hatJarOptions)
237         .jar(jarFile)
238         .maven_style_root(example)
239         .javac(javac -> javac.copy(hatJavacOpts).class_path(hatJarFile))
240         .manifest(manifest -> manifest
241           .main_class(example.fileName() + ".Main")
242         )
243       );
244     });
245 
246   if (jextract.available() && opencl.available() && opengl.available()) {
247     var example = examples.dir("nbody");
248     var jarFile = buildDir.jarFile("hat-example-" + example.fileName() + "-1.0.jar");
249     println(jarFile.fileName());
250     jar(jar -> jar.copy(hatJarOptions)
251       .jar(jarFile)
252       .maven_style_root(example)
253       .javac(javac -> javac.copy(hatJavacOpts).class_path(hatJarFile, extractedOpenCLJar, extractedOpenGLJar))
254     );
255   }
256 
257   if (cmake.available()) {
258     if (!cmakeBuildDir.exists()) {
259       cmake($ -> $
260         .source_dir(ffiBackends)
261         .build_dir(cmakeBuildDir)
262         .copy_to(buildDir)
263       );
264     }
265     cmake($ -> $
266       .build(cmakeBuildDir)
267     );
268   } else {
269     println("No cmake available so we did not build ffi backend shared libs");
270   }
271 
272 
273 }
274