diff --git a/example-apps/swirlds-platform-base-example/src/main/cpp/com_swirlds_platform_base_example_jni_HelloWorld.h b/example-apps/swirlds-platform-base-example/src/main/cpp/com_swirlds_platform_base_example_jni_HelloWorld.h new file mode 100644 index 000000000000..ccb1e5c455ea --- /dev/null +++ b/example-apps/swirlds-platform-base-example/src/main/cpp/com_swirlds_platform_base_example_jni_HelloWorld.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_swirlds_platform_base_example_jni_HelloWorld */ + +#ifndef _Included_com_swirlds_platform_base_example_jni_HelloWorld +#define _Included_com_swirlds_platform_base_example_jni_HelloWorld +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_swirlds_platform_base_example_jni_HelloWorld + * Method: printHelloWorld + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_swirlds_platform_base_example_jni_HelloWorld_printHelloWorld + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/example-apps/swirlds-platform-base-example/src/main/cpp/hello.cpp b/example-apps/swirlds-platform-base-example/src/main/cpp/hello.cpp new file mode 100644 index 000000000000..5313e3d83920 --- /dev/null +++ b/example-apps/swirlds-platform-base-example/src/main/cpp/hello.cpp @@ -0,0 +1,9 @@ + +#include +#include +#include "com_swirlds_platform_base_example_jni_HelloWorld.h" // This is the generated header file + +// Implementation of the native method +JNIEXPORT void JNICALL Java_com_swirlds_platform_base_example_jni_HelloWorld_printHelloWorld(JNIEnv *, jobject) { + std::cout << "Hello, World from C++!" << std::endl; +} \ No newline at end of file diff --git a/example-apps/swirlds-platform-base-example/src/main/java/module-info.java b/example-apps/swirlds-platform-base-example/src/main/java/module-info.java index b24be409d3ed..0384b9746dac 100644 --- a/example-apps/swirlds-platform-base-example/src/main/java/module-info.java +++ b/example-apps/swirlds-platform-base-example/src/main/java/module-info.java @@ -18,6 +18,7 @@ requires com.swirlds.metrics.api; requires com.fasterxml.jackson.databind; requires com.google.common; + requires com.hedera.nativesupport; requires jdk.httpserver; requires jdk.management; requires org.apache.logging.log4j; diff --git a/platform-sdk/hedera-nativesupport/build.gradle.kts b/platform-sdk/hedera-nativesupport/build.gradle.kts new file mode 100644 index 000000000000..3c02776cf456 --- /dev/null +++ b/platform-sdk/hedera-nativesupport/build.gradle.kts @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +plugins { + id("com.hedera.gradle.platform") + id("com.hedera.gradle.platform-publish") +} + +testModuleInfo { requires("org.junit.jupiter.api") } diff --git a/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/Architecture.java b/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/Architecture.java new file mode 100644 index 000000000000..cca667e92118 --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/Architecture.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.nativesupport; + +/** + * Defines the supported architectures. + */ +public enum Architecture { + /** + * AMD64 + */ + AMD64, + /** + * ARM64 + */ + ARM64, + /** + * I386 + */ + I386; + + /** + * Attempts to determine the current architecture based on the system property "os.arch". + * + * @return the current architecture. + * @throws IllegalStateException if the current architecture is not supported. + */ + public static Architecture current() { + final String osArch = System.getProperty("os.arch").toLowerCase(); + if (osArch.contains("amd64") || osArch.contains("x86_64")) { + return AMD64; + } else if (osArch.contains("arm64") || osArch.contains("aarch64")) { + return ARM64; + } else if (osArch.contains("i386")) { + return I386; + } else { + throw new IllegalStateException("Unsupported architecture: " + osArch); + } + } +} diff --git a/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/LibraryLoader.java b/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/LibraryLoader.java new file mode 100644 index 000000000000..b51ff9669f5a --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/LibraryLoader.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2023-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.nativesupport; + +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; + +/** + * Utility class that helps to extract a library contained in the JAR file into a temporary directory. + */ +public final class LibraryLoader { + + /** + * The root resources folder where the software is located. + */ + private static final String SOFTWARE_FOLDER_NAME = "software"; + + /** + * The path delimiter used in the JAR file. + */ + private static final String RESOURCE_PATH_DELIMITER = File.separator; + + /** + * The {@link ResourceLoader} used to load the Helm executable. + */ + private static final ResourceLoader RESOURCE_LOADER = new ResourceLoader(LibraryLoader.class); + + private static final Map DEFAULT_LIB_EXTENSIONS = + Map.of(OperatingSystem.WINDOWS, "dll", OperatingSystem.LINUX, "so", OperatingSystem.DARWIN, "dylib"); + + /** + * Private constructor to prevent instantiation of this utility class. + */ + private LibraryLoader() { + // Empty private constructor to prevent instantiation of this utility class. + } + + /** + * Unpacks a library in the JAR file into a temporary directory. + * + * @param libraryName the library to load. + * @return the path to the library to load. + * @implNote This method expects the executable to be present at the following location in the JAR file: + * {@code /software///libraryName}. + */ + public static Path install(@NonNull final String libraryName) { + return install(libraryName, DEFAULT_LIB_EXTENSIONS); + } + + /** + * Unpacks a library in the JAR file into a temporary directory. + * + * @param libraryName the library to load. + * @param libExtensions defaults extensions for each os to use to load the library + * @return the path to the library to load. + * @implNote This method expects the executable to be present at the following location in the JAR file: + * {@code /software///libraryName}. + */ + public static Path install( + @NonNull final String libraryName, @NonNull final Map libExtensions) { + Objects.requireNonNull(libraryName, "libraryName must not be null"); + Objects.requireNonNull(libExtensions, "libExtensions must not be null"); + try { + final OperatingSystem os = OperatingSystem.current(); + final Architecture arch = Architecture.current(); + + String libExtension = libExtensions.get(os); + if (!libExtensions.isEmpty()) { + libExtension = "." + libExtension; + } + return RESOURCE_LOADER.load(SOFTWARE_FOLDER_NAME + + RESOURCE_PATH_DELIMITER + + os.name().toLowerCase(Locale.US) + + RESOURCE_PATH_DELIMITER + + arch.name().toLowerCase(Locale.US) + + RESOURCE_PATH_DELIMITER + + libraryName + + libExtension); + } catch (IOException | SecurityException | IllegalStateException e) { + throw new IllegalStateException("Could not install requested library " + libraryName, e); + } + } +} diff --git a/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/OperatingSystem.java b/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/OperatingSystem.java new file mode 100644 index 000000000000..5dd248e7acc2 --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/OperatingSystem.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.nativesupport; + +/** + * Defines the supported Operative systems + */ +public enum OperatingSystem { + /** + * WINDOWS + */ + WINDOWS, + /** + * LINUX + */ + LINUX, + /** + * DARWIN + */ + DARWIN; + + /** + * Attempts to determine the current operating system based on the system property "os.name". + * + * @return the current operating system. + * @throws IllegalStateException if the current operating system is not supported. + */ + public static OperatingSystem current() { + final String osName = System.getProperty("os.name").toLowerCase(); + if (osName.contains("win")) { + return WINDOWS; + } else if (osName.contains("nix") || osName.contains("nux")) { + return LINUX; + } else if (osName.contains("mac")) { + return DARWIN; + } else { + throw new IllegalStateException("Unsupported operating system: " + osName); + } + } +} diff --git a/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/ResourceLoader.java b/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/ResourceLoader.java new file mode 100644 index 000000000000..26abf28a4d49 --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/main/java/com/hedera/nativesupport/ResourceLoader.java @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2023-2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.nativesupport; + +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.FileSystemNotFoundException; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.ProviderNotFoundException; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * The {@code ResourceLoader} class is responsible for loading resources from the classpath, + * even if they are compressed or located within jar files. It provides functionalities to + * safely acquire and copy these resources to a temporary directory while handling permissions + * and resource management across different platforms. + *

+ * This class uses a combination of class loaders to resolve the resources. It initiates with + * the class loader of the requesting class and falls back to system and platform class loaders + * sequentially. + *

+ * The primary operations include locating a resource on the classpath, copying it to a + * temporary directory, and setting appropriate file permissions to ensure the resource is + * accessible. The loader also handles Posix compliance checks to adapt file permission setting + * accordingly. + *

+ * Example usage: + *

+ * {@code
+ * ResourceLoader loader = new ResourceLoader(Caller.class);
+ * Path resourcePath = loader.load("config/settings.xml");
+ * // Use the resource from the temporary directory
+ * }
+ * 
+ */ +public class ResourceLoader { + + /** + * The class which is requesting the resources. + */ + private final Class requester; + + /** + * The list of class loaders to use to resolve the resources in order. + */ + private final List resolvers; + + /** + * Constructs a new {@link ResourceLoader} for the specified class which is requesting the resources. + * + * @param requester the class which is requesting the resources. + * @throws NullPointerException if the requester is {@code null}. + */ + public ResourceLoader(@NonNull final Class requester) { + Objects.requireNonNull(requester, "requester must not be null"); + this.requester = requester; + + this.resolvers = new ArrayList<>(); + this.resolvers.add(this.requester.getClassLoader()); + this.resolvers.add(ClassLoader.getSystemClassLoader()); + this.resolvers.add(ClassLoader.getPlatformClassLoader()); + } + + /** + * Locates the resource on the classpath at the given path and copies the file to a temporary directory. + * Additionally, the file permissions are set to be world readable, writable, and executable. + * + * @param path the relative or absolute path to the resource to load. + * @return the path to the resource in the temporary directory. + * @throws IOException if the resource cannot be loaded or an I/O error occurs. + */ + @SuppressWarnings("ResultOfMethodCallIgnored") + public Path load(@NonNull final String path) throws IOException { + Objects.requireNonNull(path, "path must not be null"); + + final InputStream resourceStream = acquireResourceStream(path); + final String fileName = Path.of(path).getFileName().toString(); + final Path tempDirectory = createTempDirectory(); + final Path tempFile = tempDirectory.resolve(fileName); + + Files.copy(resourceStream, tempFile); + if (isPosixCompliant()) { + Files.setPosixFilePermissions(tempFile, PosixFilePermissions.fromString("rwxrwxrwx")); + } else { + final File f = tempFile.toFile(); + f.setExecutable(true, false); + f.setReadable(true, false); + f.setWritable(true, false); + } + + return tempFile; + } + + /** + * Acquires the resource stream for the specified path. + * + * @param path the path to the resource to acquire. + * @return an {@link InputStream} for the specified resource. + * @throws IOException if the resource cannot be acquired or an I/O error occurs. + * @throws NullPointerException if the path is {@code null}. + */ + private InputStream acquireResourceStream(@NonNull final String path) throws IOException { + Objects.requireNonNull(path, "path must not be null"); + + for (final ClassLoader resolver : resolvers) { + final InputStream stream = resolver.getResourceAsStream(path); + if (stream != null) { + return stream; + } + } + + throw new IOException("Unable to acquire resource stream for path: " + path); + } + + /** + * Creates a temporary directory for the requester. + * + * @return the path to the temporary directory. + * @throws IOException if the temporary directory cannot be created or an I/O error occurs. + */ + @SuppressWarnings("ResultOfMethodCallIgnored") + private Path createTempDirectory() throws IOException { + final Path tempDirectory = Files.createTempDirectory(requester.getSimpleName()); + tempDirectory.toFile().mkdir(); + tempDirectory.toFile().deleteOnExit(); + return tempDirectory; + } + + /** + * Is the system we're running on Posix compliant? + * + * @return True if posix compliant. + */ + protected boolean isPosixCompliant() { + try { + return FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); + } catch (FileSystemNotFoundException | ProviderNotFoundException | SecurityException e) { + return false; + } + } +} diff --git a/platform-sdk/hedera-nativesupport/src/main/java/module-info.java b/platform-sdk/hedera-nativesupport/src/main/java/module-info.java new file mode 100644 index 000000000000..a5d6d4ba0015 --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/main/java/module-info.java @@ -0,0 +1,9 @@ +/** + * Provides a set of generic functions loading native libraries in different system architectures when packaged + * in a jar using a predefined organization, so they can be accessed with JNI. + */ +module com.hedera.nativesupport { + exports com.hedera.nativesupport; + + requires static transitive com.github.spotbugs.annotations; +} diff --git a/platform-sdk/hedera-nativesupport/src/test/cpp/com_hedera_nativesupport_jni_Greeter.h b/platform-sdk/hedera-nativesupport/src/test/cpp/com_hedera_nativesupport_jni_Greeter.h new file mode 100644 index 000000000000..953642e7296b --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/test/cpp/com_hedera_nativesupport_jni_Greeter.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_hedera_nativesupport_jni_Greeter */ + +#ifndef _Included_com_hedera_nativesupport_jni_Greeter +#define _Included_com_hedera_nativesupport_jni_Greeter +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_hedera_nativesupport_jni_Greeter + * Method: getGreeting + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_com_hedera_nativesupport_jni_Greeter_getGreeting + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform-sdk/hedera-nativesupport/src/test/cpp/cppGreeter.cpp b/platform-sdk/hedera-nativesupport/src/test/cpp/cppGreeter.cpp new file mode 100644 index 000000000000..05ceeaaf9f4c --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/test/cpp/cppGreeter.cpp @@ -0,0 +1,10 @@ + +#include +#include +#include "com_hedera_nativesupport_jni_Greeter.h" // This is the generated header file + +// Implementation of the native method +JNIEXPORT jstring JNICALL Java_com_hedera_nativesupport_jni_Greeter_getGreeting(JNIEnv *env, jobject) { + std::string helloStr = "Hello, World from C++!"; + return env->NewStringUTF(helloStr.c_str()); +} \ No newline at end of file diff --git a/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/ArchitectureTest.java b/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/ArchitectureTest.java new file mode 100644 index 000000000000..3da436e4329f --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/ArchitectureTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.nativesupport; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; + +class ArchitectureTest { + + @Test + void testCurrent() { + assertNotNull(Architecture.current()); + } +} diff --git a/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/LibraryLoaderTest.java b/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/LibraryLoaderTest.java new file mode 100644 index 000000000000..bec36653a4e3 --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/LibraryLoaderTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.nativesupport; + +import static org.junit.jupiter.api.Assertions.*; + +import com.hedera.nativesupport.jni.Greeter; +import java.nio.file.Path; +import java.util.Map; +import org.junit.jupiter.api.Test; + +class LibraryLoaderTest { + + @Test + void testInstallDoesNotThrowException() { + assertDoesNotThrow(() -> LibraryLoader.install("greeter")); + } + + @Test + void testLoadDoesNotThrowException() { + Path p = LibraryLoader.install("greeter"); + // Load native library hello.dll (Windows) or greeter.so (Linux) greeter.dylib (Mac) + assertDoesNotThrow(() -> System.load(p.toString())); + } + + @Test + void testInvoke() { + Path p = LibraryLoader.install("greeter"); + // Load native library hello.dll (Windows) or greeter.so (Linux) greeter.dylib (Mac) + System.load(p.toString()); + + assertDoesNotThrow(() -> new Greeter().getGreeting()); + } + + @Test + void testResult() { + Path p = LibraryLoader.install("greeter"); + // Load native library hello.dll (Windows) or greeter.so (Linux) greeter.dylib (Mac) + System.load(p.toString()); + + assertEquals("Hello, World from C++!", new Greeter().getGreeting()); + } + + @Test + void testInvalidLib() { + assertThrows(IllegalStateException.class, () -> LibraryLoader.install("bye")); + } + + @Test + void testInvalidExtensionLib() { + assertThrows( + IllegalStateException.class, () -> LibraryLoader.install("hello", Map.of(OperatingSystem.DARWIN, "X"))); + } + + @Test + void testNoExtensionLib() { + assertThrows(IllegalStateException.class, () -> LibraryLoader.install("hello", Map.of())); + } +} diff --git a/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/OperatingSystemTest.java b/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/OperatingSystemTest.java new file mode 100644 index 000000000000..5e3bfea33dc5 --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/OperatingSystemTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.nativesupport; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.junit.jupiter.api.Test; + +class OperatingSystemTest { + + @Test + void testCurrent() { + assertNotNull(OperatingSystem.current()); + } +} diff --git a/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/jni/Greeter.java b/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/jni/Greeter.java new file mode 100644 index 000000000000..d3c211e6dc1d --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/test/java/com/hedera/nativesupport/jni/Greeter.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hedera.nativesupport.jni; + +public class Greeter { + + // Declare a native method + public native String getGreeting(); +} diff --git a/platform-sdk/hedera-nativesupport/src/test/readme.md b/platform-sdk/hedera-nativesupport/src/test/readme.md new file mode 100644 index 000000000000..bc2f2053e3da --- /dev/null +++ b/platform-sdk/hedera-nativesupport/src/test/readme.md @@ -0,0 +1,22 @@ +Go to the dir containing the java file Greeter.java and execute + +`javac -h . Greeter.java` +It will generate a `.h` file. Move it to `src/main/cpp` and set the current directory there. +If in darwin execute: +`g++ -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -shared -o greeter.dylib cppGreeter.cpp` + +for cross compiling, you will need to download the Adoption-JDK corresponding to the os/arch version crosscompiling to: +and unzip the `jdk.../include/` dir into `$DOWNLOAD_DIR` + +* For Linux +1. Install +`brew tap messense/macos-cross-toolchains` +`brew install x86_64-unknown-linux-gnu` +2. Execute +`x86_64-unknown-linux-gnu-g++ -I"$DOWNLOAD_DIR/include/" -I"$DOWNLOAD_DIR/include/linux/" -shared -o greeter.so cppGreeter.cpp -fPIC` + +* For Windows +1. Install +`brew install mingw-w64` +2. Execute +`x86_64-w64-mingw32-g++ -I"$$DOWNLOAD_DIR/include/" -I"$DOWNLOAD_DIR/include/win32/" -shared -o greeter.dll cppGreeter.cpp` \ No newline at end of file diff --git a/platform-sdk/hedera-nativesupport/src/test/resources/software/darwin/arm64/greeter.dylib b/platform-sdk/hedera-nativesupport/src/test/resources/software/darwin/arm64/greeter.dylib new file mode 100755 index 000000000000..6ba06635a07e Binary files /dev/null and b/platform-sdk/hedera-nativesupport/src/test/resources/software/darwin/arm64/greeter.dylib differ diff --git a/platform-sdk/hedera-nativesupport/src/test/resources/software/darwin/arm64/hello.dylib b/platform-sdk/hedera-nativesupport/src/test/resources/software/darwin/arm64/hello.dylib new file mode 100755 index 000000000000..aadc23052b74 Binary files /dev/null and b/platform-sdk/hedera-nativesupport/src/test/resources/software/darwin/arm64/hello.dylib differ diff --git a/platform-sdk/hedera-nativesupport/src/test/resources/software/linux/amd64/greeter.so b/platform-sdk/hedera-nativesupport/src/test/resources/software/linux/amd64/greeter.so new file mode 100755 index 000000000000..401b201f57d0 Binary files /dev/null and b/platform-sdk/hedera-nativesupport/src/test/resources/software/linux/amd64/greeter.so differ diff --git a/platform-sdk/hedera-nativesupport/src/test/resources/software/windows/amd64/greeter.dll b/platform-sdk/hedera-nativesupport/src/test/resources/software/windows/amd64/greeter.dll new file mode 100755 index 000000000000..fcccae299d5c Binary files /dev/null and b/platform-sdk/hedera-nativesupport/src/test/resources/software/windows/amd64/greeter.dll differ diff --git a/settings.gradle.kts b/settings.gradle.kts index d7e77f3b3829..2d995b9ac1f4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -120,6 +120,8 @@ include(":swirlds-cli", "platform-sdk/swirlds-cli") include(":swirlds-benchmarks", "platform-sdk/swirlds-benchmarks") +include(":hedera-nativesupport", "platform-sdk/hedera-nativesupport") + include(":swirlds-platform-test", "platform-sdk/swirlds-unit-tests/core/swirlds-platform-test") // Platform demo/test applications