[jnienv-gen] Generate a header file for the native functions (#809)

Update `jnienv-gen` so that in addition to generate `.c` and `.cs`
files, it also generates a `.h` file with declarations for the
functions 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).
This commit is contained in:
Marek Habersack 2021-02-26 02:39:27 +01:00 коммит произвёл GitHub
Родитель 69767c1abd
Коммит cd4c8f8053
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 100 добавлений и 49 удалений

Просмотреть файл

@ -16,16 +16,28 @@ namespace Xamarin.Java.Interop
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 @@ namespace Xamarin.Java.Interop
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 @@ namespace Xamarin.Java.Interop
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 <jni.h>");
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 <jni.h>");
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");
}
}