Skip to content

Commit cd4c8f8

Browse files
authored
[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).
1 parent 69767c1 commit cd4c8f8

File tree

1 file changed

+100
-49
lines changed

1 file changed

+100
-49
lines changed

build-tools/jnienv-gen/Generator.cs

+100-49
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,28 @@ public static string FixupType (this string t)
1616
partial class Generator
1717
{
1818
static string jnienv_g_c;
19+
static string jnienv_g_h;
1920
static string jnienv_g_cs;
2021

2122
public static int Main (string [] args)
2223
{
2324
jnienv_g_c = "JniEnvironment.g.c";
25+
jnienv_g_h = "JniEnvironment.g.h";
2426
jnienv_g_cs = "JniEnvironment.g.cs";
2527
if (args.Length > 0)
2628
jnienv_g_cs = args [0];
27-
if (args.Length > 1)
29+
if (args.Length > 1) {
2830
jnienv_g_c = args [1];
31+
if (jnienv_g_c != "-") {
32+
jnienv_g_h = Path.Combine (Path.GetDirectoryName (jnienv_g_c), $"{Path.GetFileNameWithoutExtension(jnienv_g_c)}-api.h");
33+
} else {
34+
jnienv_g_h = "-";
35+
}
36+
}
37+
if (args.Length > 2) {
38+
jnienv_g_h = args [2];
39+
}
40+
2941
try {
3042
using (TextWriter w = new StringWriter ()) {
3143
w.NewLine = "\n";
@@ -36,15 +48,21 @@ public static int Main (string [] args)
3648
else
3749
File.WriteAllText (jnienv_g_cs, content);
3850
}
39-
using (TextWriter w = new StringWriter ()) {
40-
w.NewLine = "\n";
41-
GenerateNativeLibSource (w);
42-
string content = w.ToString ();
43-
if (jnienv_g_c == "-" || jnienv_g_cs == "-")
44-
Console.WriteLine (content);
45-
else
46-
File.WriteAllText (jnienv_g_c, content);
47-
}
51+
using (TextWriter sw = new StringWriter ()) {
52+
using (TextWriter hw = new StringWriter ()) {
53+
sw.NewLine = "\n";
54+
GenerateNativeLibSource (sw, hw, jnienv_g_h);
55+
string sourceContent = sw.ToString ();
56+
string headerContent = hw.ToString ();
57+
if (jnienv_g_c == "-" || jnienv_g_cs == "-") {
58+
Console.WriteLine (headerContent);
59+
Console.WriteLine ();
60+
Console.WriteLine (sourceContent);
61+
} else {
62+
File.WriteAllText (jnienv_g_h, headerContent);
63+
File.WriteAllText (jnienv_g_c, sourceContent);
64+
}
65+
}}
4866
return 0;
4967
} catch (Exception ex) {
5068
Console.WriteLine (ex);
@@ -431,67 +449,100 @@ static void RaiseException (TextWriter o, JniFunction entry, HandleStyle style)
431449
o.WriteLine ();
432450
}
433451

434-
static void GenerateNativeLibSource (TextWriter o)
452+
static void WriteNativeFileHeader (TextWriter o)
435453
{
436454
o.WriteLine ("/*");
437455
o.WriteLine (" * Generated file; DO NOT EDIT!");
438456
o.WriteLine (" *");
439-
o.WriteLine (" * To make changes, edit Java.Interop/tools/jnienv-gen and rerun");
457+
o.WriteLine (" * To make changes, edit Java.Interop/build-tools/jnienv-gen and rerun");
440458
o.WriteLine (" */");
441459
o.WriteLine ();
442-
o.WriteLine ("#include <jni.h>");
443-
o.WriteLine ();
444-
o.WriteLine ("typedef jmethodID jstaticmethodID;");
445-
o.WriteLine ("typedef jfieldID jstaticfieldID;");
446-
o.WriteLine ("typedef jobject jglobal;");
447-
o.WriteLine ();
448-
o.WriteLine ("/* VS 2010 and later have stdint.h */");
449-
o.WriteLine ("#if defined(_MSC_VER)");
450-
o.WriteLine ();
451-
o.WriteLine (" #define JI_API_EXPORT __declspec(dllexport)");
452-
o.WriteLine (" #define JI_API_IMPORT __declspec(dllimport)");
453-
o.WriteLine ();
454-
o.WriteLine ("#else /* defined(_MSC_VER */");
455-
o.WriteLine ();
456-
o.WriteLine ("\t#define JI_API_EXPORT __attribute__ ((visibility (\"default\")))");
457-
o.WriteLine (" #define JI_API_IMPORT");
458-
o.WriteLine ();
459-
o.WriteLine ("#endif /* !defined(_MSC_VER) */");
460-
o.WriteLine ();
461-
o.WriteLine ("#if defined(JI_DLL_EXPORT)");
462-
o.WriteLine (" #define JI_API JI_API_EXPORT");
463-
o.WriteLine ("#elif defined(JI_DLL_IMPORT)");
464-
o.WriteLine (" #define JI_API JI_API_IMPORT");
465-
o.WriteLine ("#else /* !defined(JI_DLL_IMPORT) && !defined(JI_API_IMPORT) */");
466-
o.WriteLine (" #define JI_API");
467-
o.WriteLine ("#endif /* JI_DLL_EXPORT... */");
460+
}
461+
462+
static void GenerateNativeLibSource (TextWriter source, TextWriter header, string headerName)
463+
{
464+
WriteNativeFileHeader (source);
465+
WriteNativeFileHeader (header);
466+
467+
header.WriteLine ("#if !defined (__JAVA_INTEROP_NATIVE_H)");
468+
header.WriteLine ("#define __JAVA_INTEROP_NATIVE_H");
469+
header.WriteLine ();
470+
header.WriteLine ("#include <jni.h>");
471+
header.WriteLine ();
472+
header.WriteLine ("typedef jmethodID jstaticmethodID;");
473+
header.WriteLine ("typedef jfieldID jstaticfieldID;");
474+
header.WriteLine ("typedef jobject jglobal;");
475+
header.WriteLine ();
476+
header.WriteLine ("#if !defined(JI_NO_VISIBILITY)");
477+
header.WriteLine ("\t/* VS 2010 and later have stdint.h */");
478+
header.WriteLine ("\t#if defined(_MSC_VER)");
479+
header.WriteLine ();
480+
header.WriteLine ("\t\t#define JI_API_EXPORT __declspec(dllexport)");
481+
header.WriteLine ("\t\t#define JI_API_IMPORT __declspec(dllimport)");
482+
header.WriteLine ();
483+
header.WriteLine ("\t#else /* defined(_MSC_VER */");
484+
header.WriteLine ();
485+
header.WriteLine ("\t\t#define JI_API_EXPORT __attribute__ ((visibility (\"default\")))");
486+
header.WriteLine ("\t\t#define JI_API_IMPORT");
487+
header.WriteLine ();
488+
header.WriteLine ("\t#endif /* !defined(_MSC_VER) */");
489+
header.WriteLine ();
490+
header.WriteLine ("\t#if defined(JI_DLL_EXPORT)");
491+
header.WriteLine ("\t\t#define JI_API JI_API_EXPORT");
492+
header.WriteLine ("\t#elif defined(JI_DLL_IMPORT)");
493+
header.WriteLine ("\t\t#define JI_API JI_API_IMPORT");
494+
header.WriteLine ("\t#else /* !defined(JI_DLL_IMPORT) && !defined(JI_API_IMPORT) */");
495+
header.WriteLine ("\t\t#define JI_API");
496+
header.WriteLine ("\t#endif /* JI_DLL_EXPORT... */");
497+
header.WriteLine ("#else // JI_NO_VISIBILITY");
498+
header.WriteLine ("\t#define JI_API");
499+
header.WriteLine ("#endif // JI_NO_VISIBILITY");
500+
header.WriteLine ();
501+
502+
if (headerName != "-") {
503+
source.WriteLine ($"#include \"{Path.GetFileName(headerName)}\"");
504+
}
505+
468506
foreach (JniFunction entry in JNIEnvEntries) {
469507
if (entry.IsPrivate || entry.CustomWrapper)
470508
continue;
471-
o.WriteLine ();
472-
o.WriteLine ("JI_API {0}", entry.ReturnType.JniType);
473-
o.WriteLine ("{0} (JNIEnv *env{1}{2}{3})",
509+
510+
header.WriteLine (
511+
"JI_API {0} {1} (JNIEnv *env{2}{3}{4});",
512+
entry.ReturnType.JniType,
513+
GetPinvokeName (entry.Name),
514+
entry.Throws ? ", jthrowable *_thrown" : "",
515+
entry.Parameters.Length != 0 ? ", " : "",
516+
string.Join (", ", entry.Parameters.Select (p => string.Format ("{0} {1}", p.Type.JniType, p.Name)))
517+
);
518+
519+
source.WriteLine ();
520+
source.WriteLine ("JI_API {0}", entry.ReturnType.JniType);
521+
source.WriteLine ("{0} (JNIEnv *env{1}{2}{3})",
474522
GetPinvokeName (entry.Name),
475523
entry.Throws ? ", jthrowable *_thrown" : "",
476524
entry.Parameters.Length != 0 ? ", " : "",
477525
string.Join (", ", entry.Parameters.Select (p => string.Format ("{0} {1}", p.Type.JniType, p.Name))));
478-
o.WriteLine ("{");
526+
source.WriteLine ("{");
479527
bool isVoid = entry.ReturnType.JniType == "void";
480528
if (entry.Throws)
481-
o.WriteLine ("\t*_thrown = 0;");
482-
o.Write ("\t");
529+
source.WriteLine ("\t*_thrown = 0;");
530+
source.Write ("\t");
483531
if (!isVoid)
484-
o.Write ("{0} _r_ = ", entry.ReturnType.JniType);
485-
o.WriteLine ("(*env)->{0} (env{1}{2});",
532+
source.Write ("{0} _r_ = ", entry.ReturnType.JniType);
533+
source.WriteLine ("(*env)->{0} (env{1}{2});",
486534
entry.Name,
487535
entry.Parameters.Length != 0 ? ", " : "",
488536
string.Join (", ", entry.Parameters.Select (p => p.Name)));
489537
if (entry.Throws)
490-
o.WriteLine ("\t*_thrown = (*env)->ExceptionOccurred (env);");
538+
source.WriteLine ("\t*_thrown = (*env)->ExceptionOccurred (env);");
491539
if (!isVoid)
492-
o.WriteLine ("\treturn _r_;");
493-
o.WriteLine ("}");
540+
source.WriteLine ("\treturn _r_;");
541+
source.WriteLine ("}");
494542
}
543+
544+
header.WriteLine ();
545+
header.WriteLine ("#endif // __JAVA_INTEROP_NATIVE_H");
495546
}
496547
}
497548

0 commit comments

Comments
 (0)