From 82d1675f9d4d9181f73bac9e44fd79021435f09a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 24 Feb 2021 21:33:07 +0100 Subject: [PATCH] [jnienv-gen] Generate a header file for the native functions In addition to generating a .c file, generate a .h one with declarations of all the functions defined in the .c file. The header will be used by the NET6 build of Xamarin.Android's native runtime. Additionally, make it possible to not export symbols by defining the `JI_NO_VISIBILITY` preprocessor macro. This will also be used by the NET6 build of Xamarin.Android native runtime (which will no longer need to make the symbols visible for `p/invoke` to work) --- build-tools/jnienv-gen/Generator.cs | 149 +++++++++++++++++++--------- 1 file changed, 100 insertions(+), 49 deletions(-) diff --git a/build-tools/jnienv-gen/Generator.cs b/build-tools/jnienv-gen/Generator.cs index 3fba5c0c2..41dca3d35 100644 --- a/build-tools/jnienv-gen/Generator.cs +++ b/build-tools/jnienv-gen/Generator.cs @@ -16,16 +16,28 @@ public static string FixupType (this string t) partial class Generator { static string jnienv_g_c; + static string jnienv_g_h; static string jnienv_g_cs; public static int Main (string [] args) { jnienv_g_c = "JniEnvironment.g.c"; + jnienv_g_h = "JniEnvironment.g.h"; jnienv_g_cs = "JniEnvironment.g.cs"; if (args.Length > 0) jnienv_g_cs = args [0]; - if (args.Length > 1) + if (args.Length > 1) { jnienv_g_c = args [1]; + if (jnienv_g_c != "-") { + jnienv_g_h = Path.Combine (Path.GetDirectoryName (jnienv_g_c), $"{Path.GetFileNameWithoutExtension(jnienv_g_c)}-api.h"); + } else { + jnienv_g_h = "-"; + } + } + if (args.Length > 2) { + jnienv_g_h = args [2]; + } + try { using (TextWriter w = new StringWriter ()) { w.NewLine = "\n"; @@ -36,15 +48,21 @@ public static int Main (string [] args) else File.WriteAllText (jnienv_g_cs, content); } - using (TextWriter w = new StringWriter ()) { - w.NewLine = "\n"; - GenerateNativeLibSource (w); - string content = w.ToString (); - if (jnienv_g_c == "-" || jnienv_g_cs == "-") - Console.WriteLine (content); - else - File.WriteAllText (jnienv_g_c, content); - } + using (TextWriter sw = new StringWriter ()) { + using (TextWriter hw = new StringWriter ()) { + sw.NewLine = "\n"; + GenerateNativeLibSource (sw, hw, jnienv_g_h); + string sourceContent = sw.ToString (); + string headerContent = hw.ToString (); + if (jnienv_g_c == "-" || jnienv_g_cs == "-") { + Console.WriteLine (headerContent); + Console.WriteLine (); + Console.WriteLine (sourceContent); + } else { + File.WriteAllText (jnienv_g_h, headerContent); + File.WriteAllText (jnienv_g_c, sourceContent); + } + }} return 0; } catch (Exception ex) { Console.WriteLine (ex); @@ -431,67 +449,100 @@ static void RaiseException (TextWriter o, JniFunction entry, HandleStyle style) o.WriteLine (); } - static void GenerateNativeLibSource (TextWriter o) + static void WriteNativeFileHeader (TextWriter o) { o.WriteLine ("/*"); o.WriteLine (" * Generated file; DO NOT EDIT!"); o.WriteLine (" *"); - o.WriteLine (" * To make changes, edit Java.Interop/tools/jnienv-gen and rerun"); + o.WriteLine (" * To make changes, edit Java.Interop/build-tools/jnienv-gen and rerun"); o.WriteLine (" */"); o.WriteLine (); - o.WriteLine ("#include "); - o.WriteLine (); - o.WriteLine ("typedef jmethodID jstaticmethodID;"); - o.WriteLine ("typedef jfieldID jstaticfieldID;"); - o.WriteLine ("typedef jobject jglobal;"); - o.WriteLine (); - o.WriteLine ("/* VS 2010 and later have stdint.h */"); - o.WriteLine ("#if defined(_MSC_VER)"); - o.WriteLine (); - o.WriteLine (" #define JI_API_EXPORT __declspec(dllexport)"); - o.WriteLine (" #define JI_API_IMPORT __declspec(dllimport)"); - o.WriteLine (); - o.WriteLine ("#else /* defined(_MSC_VER */"); - o.WriteLine (); - o.WriteLine ("\t#define JI_API_EXPORT __attribute__ ((visibility (\"default\")))"); - o.WriteLine (" #define JI_API_IMPORT"); - o.WriteLine (); - o.WriteLine ("#endif /* !defined(_MSC_VER) */"); - o.WriteLine (); - o.WriteLine ("#if defined(JI_DLL_EXPORT)"); - o.WriteLine (" #define JI_API JI_API_EXPORT"); - o.WriteLine ("#elif defined(JI_DLL_IMPORT)"); - o.WriteLine (" #define JI_API JI_API_IMPORT"); - o.WriteLine ("#else /* !defined(JI_DLL_IMPORT) && !defined(JI_API_IMPORT) */"); - o.WriteLine (" #define JI_API"); - o.WriteLine ("#endif /* JI_DLL_EXPORT... */"); + } + + static void GenerateNativeLibSource (TextWriter source, TextWriter header, string headerName) + { + WriteNativeFileHeader (source); + WriteNativeFileHeader (header); + + header.WriteLine ("#if !defined (__JAVA_INTEROP_NATIVE_H)"); + header.WriteLine ("#define __JAVA_INTEROP_NATIVE_H"); + header.WriteLine (); + header.WriteLine ("#include "); + header.WriteLine (); + header.WriteLine ("typedef jmethodID jstaticmethodID;"); + header.WriteLine ("typedef jfieldID jstaticfieldID;"); + header.WriteLine ("typedef jobject jglobal;"); + header.WriteLine (); + header.WriteLine ("#if !defined(JI_NO_VISIBILITY)"); + header.WriteLine ("\t/* VS 2010 and later have stdint.h */"); + header.WriteLine ("\t#if defined(_MSC_VER)"); + header.WriteLine (); + header.WriteLine ("\t\t#define JI_API_EXPORT __declspec(dllexport)"); + header.WriteLine ("\t\t#define JI_API_IMPORT __declspec(dllimport)"); + header.WriteLine (); + header.WriteLine ("\t#else /* defined(_MSC_VER */"); + header.WriteLine (); + header.WriteLine ("\t\t#define JI_API_EXPORT __attribute__ ((visibility (\"default\")))"); + header.WriteLine ("\t\t#define JI_API_IMPORT"); + header.WriteLine (); + header.WriteLine ("\t#endif /* !defined(_MSC_VER) */"); + header.WriteLine (); + header.WriteLine ("\t#if defined(JI_DLL_EXPORT)"); + header.WriteLine ("\t\t#define JI_API JI_API_EXPORT"); + header.WriteLine ("\t#elif defined(JI_DLL_IMPORT)"); + header.WriteLine ("\t\t#define JI_API JI_API_IMPORT"); + header.WriteLine ("\t#else /* !defined(JI_DLL_IMPORT) && !defined(JI_API_IMPORT) */"); + header.WriteLine ("\t\t#define JI_API"); + header.WriteLine ("\t#endif /* JI_DLL_EXPORT... */"); + header.WriteLine ("#else // JI_NO_VISIBILITY"); + header.WriteLine ("\t#define JI_API"); + header.WriteLine ("#endif // JI_NO_VISIBILITY"); + header.WriteLine (); + + if (headerName != "-") { + source.WriteLine ($"#include \"{Path.GetFileName(headerName)}\""); + } + foreach (JniFunction entry in JNIEnvEntries) { if (entry.IsPrivate || entry.CustomWrapper) continue; - o.WriteLine (); - o.WriteLine ("JI_API {0}", entry.ReturnType.JniType); - o.WriteLine ("{0} (JNIEnv *env{1}{2}{3})", + + header.WriteLine ( + "JI_API {0} {1} (JNIEnv *env{2}{3}{4});", + entry.ReturnType.JniType, + GetPinvokeName (entry.Name), + entry.Throws ? ", jthrowable *_thrown" : "", + entry.Parameters.Length != 0 ? ", " : "", + string.Join (", ", entry.Parameters.Select (p => string.Format ("{0} {1}", p.Type.JniType, p.Name))) + ); + + source.WriteLine (); + source.WriteLine ("JI_API {0}", entry.ReturnType.JniType); + source.WriteLine ("{0} (JNIEnv *env{1}{2}{3})", GetPinvokeName (entry.Name), entry.Throws ? ", jthrowable *_thrown" : "", entry.Parameters.Length != 0 ? ", " : "", string.Join (", ", entry.Parameters.Select (p => string.Format ("{0} {1}", p.Type.JniType, p.Name)))); - o.WriteLine ("{"); + source.WriteLine ("{"); bool isVoid = entry.ReturnType.JniType == "void"; if (entry.Throws) - o.WriteLine ("\t*_thrown = 0;"); - o.Write ("\t"); + source.WriteLine ("\t*_thrown = 0;"); + source.Write ("\t"); if (!isVoid) - o.Write ("{0} _r_ = ", entry.ReturnType.JniType); - o.WriteLine ("(*env)->{0} (env{1}{2});", + source.Write ("{0} _r_ = ", entry.ReturnType.JniType); + source.WriteLine ("(*env)->{0} (env{1}{2});", entry.Name, entry.Parameters.Length != 0 ? ", " : "", string.Join (", ", entry.Parameters.Select (p => p.Name))); if (entry.Throws) - o.WriteLine ("\t*_thrown = (*env)->ExceptionOccurred (env);"); + source.WriteLine ("\t*_thrown = (*env)->ExceptionOccurred (env);"); if (!isVoid) - o.WriteLine ("\treturn _r_;"); - o.WriteLine ("}"); + source.WriteLine ("\treturn _r_;"); + source.WriteLine ("}"); } + + header.WriteLine (); + header.WriteLine ("#endif // __JAVA_INTEROP_NATIVE_H"); } }