diff --git a/.gitmodules b/.gitmodules
index 60d4e416e..792f80b15 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -6,3 +6,7 @@
path = external/cecil
url = https://github.com/mono/cecil.git
branch = master
+[submodule "external/xamarin-android-tools"]
+ path = external/xamarin-android-tools
+ url = https://github.com/xamarin/xamarin-android-tools.git
+ branch = master
diff --git a/Configuration.props b/Configuration.props
index 4ba4b8b61..e7c9e4acb 100644
--- a/Configuration.props
+++ b/Configuration.props
@@ -16,8 +16,10 @@
$(MSBuildThisFileDirectory)external\cecil
$(MSBuildThisFileDirectory)bin\$(Configuration)\
+ $(MSBuildThisFileDirectory)external\xamarin-android-tools
$([System.IO.Path]::GetFullPath ('$(CecilSourceDirectory)'))
+ $([System.IO.Path]::GetFullPath ('$(XamarinAndroidToolsDirectory)'))
diff --git a/Java.Interop.sln b/Java.Interop.sln
index 22fc435d7..f924d2ddc 100644
--- a/Java.Interop.sln
+++ b/Java.Interop.sln
@@ -17,7 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{4C173212-3
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop", "src\Java.Interop\Java.Interop.csproj", "{94BD81F7-B06F-4295-9636-F8A3B6BDC762}"
EndProject
-Project("{9344BDBB-3E7F-41FC-A0DD-8665D75EE146}") = "java-interop", "src\java-interop\java-interop.csproj", "{BB0AB9F7-0979-41A7-B7A9-877260655F94}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "java-interop", "src\java-interop\java-interop.csproj", "{BB0AB9F7-0979-41A7-B7A9-877260655F94}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.Dynamic", "src\Java.Interop.Dynamic\Java.Interop.Dynamic.csproj", "{AD4468F8-8883-434B-9D4C-E1801BB3B52A}"
EndProject
@@ -97,7 +97,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Cecil.Mdb",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.GenericMarshaler", "src\Java.Interop.GenericMarshaler\Java.Interop.GenericMarshaler.csproj", "{D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.BootstrapTasks", "src\Java.Interop.BootstrapTasks\Java.Interop.BootstrapTasks.csproj", "{3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Java.Interop.BootstrapTasks", "build-tools\Java.Interop.BootstrapTasks\Java.Interop.BootstrapTasks.csproj", "{3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Android.Tools.AndroidSdk", "external\xamarin-android-tools\src\Xamarin.Android.Tools.AndroidSdk\Xamarin.Android.Tools.AndroidSdk.csproj", "{E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -349,6 +351,14 @@ Global
{3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU
{3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}.XAIntegrationRelease|Any CPU.ActiveCfg = Release|Any CPU
{3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A}.XAIntegrationRelease|Any CPU.Build.0 = Release|Any CPU
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.XAIntegrationDebug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.XAIntegrationDebug|Any CPU.Build.0 = Debug|Any CPU
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.XAIntegrationRelease|Any CPU.ActiveCfg = Release|Any CPU
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}.XAIntegrationRelease|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{0C001D50-4176-45AE-BDC8-BA626508B0CC} = {C8F58966-94BF-407F-914A-8654F8B8AE3B}
@@ -392,5 +402,6 @@ Global
{C0487169-8F81-497F-919E-EB42B1D0243F} = {C8F58966-94BF-407F-914A-8654F8B8AE3B}
{D1243BAB-23CA-4566-A2A3-3ADA2C2DC3AF} = {4C173212-371D-45D8-BA83-9226194F48DC}
{3E8E5C8C-59A6-4A9A-B55D-46AB14431B2A} = {172B608B-E6F3-41CC-9949-203A76BA247C}
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157} = {172B608B-E6F3-41CC-9949-203A76BA247C}
EndGlobalSection
EndGlobal
diff --git a/Makefile b/Makefile
index f8f278811..a45d39c62 100644
--- a/Makefile
+++ b/Makefile
@@ -20,6 +20,9 @@ PACKAGES = \
packages/NUnit.3.7.1/NUnit.3.7.1.nupkg \
packages/NUnit.Console.3.7.0/NUnit.Console.3.7.0.nupkg
+PREPARE_EXTERNAL_FILES = \
+ external/xamarin-android-tools/src/Xamarin.Android.Tools.AndroidSdk/Xamarin.Android.Tools.AndroidSdk.csproj
+
DEPENDENCIES = \
bin/Test$(CONFIGURATION)/libNativeTiming$(NATIVE_EXT)
@@ -55,16 +58,18 @@ run-all-tests: run-tests run-test-jnimarshal run-test-generator-core run-ptests
include build-tools/scripts/msbuild.mk
-prepare:: prepare-bootstrap prepare-external
+prepare:: prepare-bootstrap
-prepare-bootstrap: bin/Build$(CONFIGURATION)/Java.Interop.BootstrapTasks.dll
+prepare-bootstrap: prepare-external bin/Build$(CONFIGURATION)/Java.Interop.BootstrapTasks.dll
-bin/Build$(CONFIGURATION)/Java.Interop.BootstrapTasks.dll: src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj \
- $(wildcard src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/*.cs)
- $(MSBUILD) $(MSBUILD_FLAGS) src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj
+bin/Build$(CONFIGURATION)/Java.Interop.BootstrapTasks.dll: build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj \
+ external/xamarin-android-tools/src/Xamarin.Android.Tools.AndroidSdk/Xamarin.Android.Tools.AndroidSdk.csproj \
+ $(wildcard build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/*.cs)
+ $(MSBUILD) $(MSBUILD_FLAGS) "$<"
-prepare-external: $(PACKAGES) $(NUNIT_CONSOLE)
+prepare-external $(PREPARE_EXTERNAL_FILES): $(PACKAGES) $(NUNIT_CONSOLE)
git submodule update --init --recursive
+ (cd external/xamarin-android-tools && $(MAKE) prepare)
clean:
-$(MSBUILD) $(MSBUILD_FLAGS) /t:Clean
diff --git a/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj
similarity index 87%
rename from src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj
rename to build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj
index 83567f08d..dbc5d407a 100644
--- a/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj
+++ b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks.csproj
@@ -41,9 +41,14 @@
-
+
+
+ {E34BCFA0-CAA4-412C-AA1C-75DB8D67D157}
+ Xamarin.Android.Tools.AndroidSdk
+
+
\ No newline at end of file
diff --git a/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/DownloadUri.cs b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/DownloadUri.cs
similarity index 100%
rename from src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/DownloadUri.cs
rename to build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/DownloadUri.cs
diff --git a/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs
new file mode 100644
index 000000000..889b6ca55
--- /dev/null
+++ b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/JdkInfo.cs
@@ -0,0 +1,122 @@
+using Microsoft.Build.Framework;
+using Microsoft.Build.Utilities;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Xml.Linq;
+
+using Xamarin.Android.Tools;
+
+using XATInfo = Xamarin.Android.Tools.JdkInfo;
+
+namespace Java.Interop.BootstrapTasks
+{
+ public class JdkInfo : Task
+ {
+ const string JARSIGNER = "jarsigner.exe";
+ const string MDREG_KEY = @"SOFTWARE\Novell\Mono for Android";
+ const string MDREG_JAVA_SDK = "JavaSdkDirectory";
+
+ public string JdksRoot { get; set; }
+
+ public string MaximumJdkVersion { get; set; }
+
+ static Regex VersionExtractor = new Regex (@"(?[\d]+(\.\d+)+)", RegexOptions.Compiled);
+
+ [Required]
+ public ITaskItem PropertyFile { get; set; }
+
+ [Required]
+ public ITaskItem MakeFragmentFile { get; set; }
+
+ [Output]
+ public string JavaHomePath { get; set; }
+
+ public override bool Execute ()
+ {
+ var maxVersion = GetVersion (MaximumJdkVersion);
+
+ XATInfo jdk = XATInfo.GetKnownSystemJdkInfos (CreateLogger ())
+ .Where (j => maxVersion != null ? j.Version <= maxVersion : true)
+ .FirstOrDefault ();
+
+ if (jdk == null) {
+ Log.LogError ("Could not determine JAVA_HOME location. Please set JdksRoot or export the JAVA_HOME environment variable.");
+ return false;
+ }
+
+ JavaHomePath = jdk.HomePath;
+
+ Directory.CreateDirectory (Path.GetDirectoryName (PropertyFile.ItemSpec));
+ Directory.CreateDirectory (Path.GetDirectoryName (MakeFragmentFile.ItemSpec));
+
+ WritePropertyFile (jdk.JarPath, jdk.JavacPath, jdk.JdkJvmPath, jdk.IncludePath);
+ WriteMakeFragmentFile (jdk.JarPath, jdk.JavacPath, jdk.JdkJvmPath, jdk.IncludePath);
+
+ return !Log.HasLoggedErrors;
+ }
+
+ Version GetVersion (string value)
+ {
+ if (string.IsNullOrEmpty (value))
+ return null;
+ if (!value.Contains (".")) {
+ value += ".0";
+ }
+ Version v;
+ if (Version.TryParse (value, out v))
+ return v;
+ return null;
+ }
+
+ Action CreateLogger ()
+ {
+ Action logger = (level, value) => {
+ switch (level) {
+ case TraceLevel.Error:
+ Log.LogError ("{0}", value);
+ break;
+ case TraceLevel.Warning:
+ Log.LogWarning ("{0}", value);
+ break;
+ default:
+ Log.LogMessage (MessageImportance.Low, "{0}", value);
+ break;
+ }
+ };
+ return logger;
+ }
+
+ void WritePropertyFile (string jarPath, string javacPath, string jdkJvmPath, IEnumerable includes)
+ {
+ var msbuild = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003");
+ var project = new XElement (msbuild + "Project",
+ new XElement (msbuild + "Choose",
+ new XElement (msbuild + "When", new XAttribute ("Condition", " '$(JdkJvmPath)' == '' "),
+ new XElement (msbuild + "PropertyGroup",
+ new XElement (msbuild + "JdkJvmPath", jdkJvmPath)),
+ new XElement (msbuild + "ItemGroup",
+ includes.Select (i => new XElement (msbuild + "JdkIncludePath", new XAttribute ("Include", i)))))),
+ new XElement (msbuild + "PropertyGroup",
+ new XElement (msbuild + "JavaCPath", new XAttribute ("Condition", " '$(JavaCPath)' == '' "),
+ javacPath),
+ new XElement (msbuild + "JarPath", new XAttribute ("Condition", " '$(JarPath)' == '' "),
+ jarPath)));
+ project.Save (PropertyFile.ItemSpec);
+ }
+
+ void WriteMakeFragmentFile (string jarPath, string javacPath, string jdkJvmPath, IEnumerable includes)
+ {
+ using (var o = new StreamWriter (MakeFragmentFile.ItemSpec)) {
+ o.WriteLine ($"export JI_JAR_PATH := {jarPath}");
+ o.WriteLine ($"export JI_JAVAC_PATH := {javacPath}");
+ o.WriteLine ($"export JI_JDK_INCLUDE_PATHS := {string.Join (" ", includes)}");
+ o.WriteLine ($"export JI_JVM_PATH := {jdkJvmPath}");
+ }
+ }
+ }
+}
diff --git a/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs
similarity index 58%
rename from src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs
rename to build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs
index 585c20ec5..4e9d11a4f 100644
--- a/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs
+++ b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/OS.cs
@@ -6,17 +6,5 @@ class OS {
public static readonly bool IsWindows = Path.DirectorySeparatorChar == '\\';
public static readonly bool IsMacOS = !IsWindows && Directory.Exists ("/Applications");
public static readonly bool IsLinux = !IsWindows && !IsMacOS;
-
- public static readonly string NativeLibraryFormat;
-
- static OS ()
- {
- if (IsWindows)
- NativeLibraryFormat = "{0}.dll";
- if (IsMacOS)
- NativeLibraryFormat = "lib{0}.dylib";
- if (IsLinux)
- NativeLibraryFormat = "lib{0}.so";
- }
}
}
diff --git a/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/SetEnvironmentVariable.cs b/build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/SetEnvironmentVariable.cs
similarity index 100%
rename from src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/SetEnvironmentVariable.cs
rename to build-tools/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/SetEnvironmentVariable.cs
diff --git a/src/Java.Interop.BootstrapTasks/Properties/AssemblyInfo.cs b/build-tools/Java.Interop.BootstrapTasks/Properties/AssemblyInfo.cs
similarity index 100%
rename from src/Java.Interop.BootstrapTasks/Properties/AssemblyInfo.cs
rename to build-tools/Java.Interop.BootstrapTasks/Properties/AssemblyInfo.cs
diff --git a/build-tools/scripts/PrepareWindows.targets b/build-tools/scripts/PrepareWindows.targets
index 7cbba368f..29b13021a 100644
--- a/build-tools/scripts/PrepareWindows.targets
+++ b/build-tools/scripts/PrepareWindows.targets
@@ -12,7 +12,7 @@
-
+
[\d]+(\.\d+)+)", RegexOptions.Compiled);
-
- [Required]
- public ITaskItem PropertyFile { get; set; }
-
- [Required]
- public ITaskItem MakeFragmentFile { get; set; }
-
- [Output]
- public string JavaHomePath { get; set; }
-
- public override bool Execute ()
- {
- Log.LogMessage (MessageImportance.Low, $"Task {nameof (JdkInfo)}");
- Log.LogMessage (MessageImportance.Low, $" {nameof (JdksRoot)}: {JdksRoot}");
- Log.LogMessage (MessageImportance.Low, $" {nameof (MakeFragmentFile)}: {MakeFragmentFile}");
- Log.LogMessage (MessageImportance.Low, $" {nameof (MaximumJdkVersion)}: {MaximumJdkVersion}");
- Log.LogMessage (MessageImportance.Low, $" {nameof (PropertyFile)}: {PropertyFile}");
-
- var maxVersion = GetVersion (MaximumJdkVersion);
-
- string jarPath = null;
- string javacPath = null;
- string jdkJvmPath = null;
- string includePath = null;
-
- var java_home = GetJavaHomePathFromEnvironment ();
- if (!ValidateJdkPath (maxVersion, java_home, out jarPath, out javacPath, out jdkJvmPath, out includePath)) {
- java_home = null;
- }
-
- if (java_home == null &&
- (java_home = GetJavaHomePathFromLibexec ()) != null &&
- !ValidateJdkPath (maxVersion, java_home, out jarPath, out javacPath, out jdkJvmPath, out includePath)) {
- java_home = null;
- }
-
- if (java_home == null &&
- (java_home = GetJavaHomePathFromAlternatives ()) != null &&
- !ValidateJdkPath (maxVersion, java_home, out jarPath, out javacPath, out jdkJvmPath, out includePath)) {
- java_home = null;
- }
-
- if (java_home == null &&
- (java_home = GetJavaHomePathFromMachine (maxVersion)) != null &&
- !ValidateJdkPath (maxVersion, java_home, out jarPath, out javacPath, out jdkJvmPath, out includePath)) {
- java_home = null;
- }
-
- if (java_home == null) {
- Log.LogError ("Could not determine JAVA_HOME location. Please set JdksRoot or export the JAVA_HOME environment variable.");
- return false;
- }
-
- var includes = new List () {
- includePath,
- };
- includes.AddRange (Directory.GetDirectories (includePath));
-
- if (Log.HasLoggedErrors) {
- return false;
- }
-
- JavaHomePath = java_home;
-
- Directory.CreateDirectory (Path.GetDirectoryName (PropertyFile.ItemSpec));
- Directory.CreateDirectory (Path.GetDirectoryName (MakeFragmentFile.ItemSpec));
-
- WritePropertyFile (jarPath, javacPath, jdkJvmPath, includes);
- WriteMakeFragmentFile (jarPath, javacPath, jdkJvmPath, includes);
-
- Log.LogMessage (MessageImportance.Low, $" [Output] {nameof (JavaHomePath)}: {JavaHomePath}");
-
- return !Log.HasLoggedErrors;
- }
-
- Version GetVersion (string value)
- {
- if (string.IsNullOrEmpty (value))
- return null;
- if (!value.Contains (".")) {
- value += ".0";
- }
- Version v;
- if (Version.TryParse (value, out v))
- return v;
- return null;
- }
-
- Version GetVersionFromPath (string path)
- {
- var m = VersionExtractor.Match (path);
- if (!m.Success)
- return null;
- return GetVersion (m.Groups ["version"].Value);
- }
-
- void FileExists (string path)
- {
- if (!File.Exists (path)) {
- var name = Path.GetFileName (path);
- Log.LogError ($"Could not determine location of `{name}`; tried `{path}`.");
- }
- }
-
- void WritePropertyFile (string jarPath, string javacPath, string jdkJvmPath, IEnumerable includes)
- {
- var msbuild = XNamespace.Get ("http://schemas.microsoft.com/developer/msbuild/2003");
- var project = new XElement (msbuild + "Project",
- new XElement (msbuild + "Choose",
- new XElement (msbuild + "When", new XAttribute ("Condition", " '$(JdkJvmPath)' == '' "),
- new XElement (msbuild + "PropertyGroup",
- new XElement (msbuild + "JdkJvmPath", jdkJvmPath)),
- new XElement (msbuild + "ItemGroup",
- includes.Select (i => new XElement (msbuild + "JdkIncludePath", new XAttribute ("Include", i)))))),
- new XElement (msbuild + "PropertyGroup",
- new XElement (msbuild + "JavaCPath", new XAttribute ("Condition", " '$(JavaCPath)' == '' "),
- javacPath),
- new XElement (msbuild + "JarPath", new XAttribute ("Condition", " '$(JarPath)' == '' "),
- jarPath)));
- project.Save (PropertyFile.ItemSpec);
- }
-
- void WriteMakeFragmentFile (string jarPath, string javacPath, string jdkJvmPath, IEnumerable includes)
- {
- using (var o = new StreamWriter (MakeFragmentFile.ItemSpec)) {
- o.WriteLine ($"export JI_JAR_PATH := {jarPath}");
- o.WriteLine ($"export JI_JAVAC_PATH := {javacPath}");
- o.WriteLine ($"export JI_JDK_INCLUDE_PATHS := {string.Join (" ", includes)}");
- o.WriteLine ($"export JI_JVM_PATH := {jdkJvmPath}");
- }
- }
-
- bool ValidateJdkPath (Version maxVersion, string java_home)
- {
- return ValidateJdkPath (maxVersion, java_home,
- out _, out _, out _, out _);
- }
-
- bool ValidateJdkPath (Version maxVersion, string java_home,
- out string jarPath, out string javacPath, out string jdkJvmPath, out string includePath)
- {
- jarPath = javacPath = jdkJvmPath = includePath = null;
-
- if (string.IsNullOrEmpty (java_home) || !Directory.Exists (java_home))
- return false;
-
- var pathVersion = GetVersionFromPath (java_home);
- if (maxVersion != null && pathVersion != null && pathVersion > maxVersion) {
- Log.LogMessage (MessageImportance.Low,
- $" Skipping JAVA_HOME value of `{java_home}` as it exceeds MaximumJdkVersion={MaximumJdkVersion}.");
- return false;
- }
-
- jarPath = FindExecutablesInDirectory (Path.Combine (java_home, "bin"), "jar").FirstOrDefault ();
- javacPath = FindExecutablesInDirectory (Path.Combine (java_home, "bin"), "javac").FirstOrDefault ();
- var jdkJvmPaths = OS.IsMacOS
- ? FindLibrariesInDirectory (java_home, "jli")
- : FindLibrariesInDirectory (Path.Combine (java_home, "jre"), "jvm");
- jdkJvmPath = jdkJvmPaths.FirstOrDefault ();
- includePath = Path.Combine (java_home, "include");
-
- if (jarPath == null) {
- Log.LogMessage (MessageImportance.Low, $" Skipping JAVA_HOME value of `{java_home}` as `jar` could not be found.");
- return false;
- }
- if (javacPath == null) {
- Log.LogMessage (MessageImportance.Low, $" Skipping JAVA_HOME value of `{java_home}` as `javac` could not be found.");
- return false;
- }
- if (jdkJvmPath == null) {
- var jvm = OS.IsMacOS ? "libjli.dylib" : string.Format (OS.NativeLibraryFormat, "jvm");
- Log.LogMessage (MessageImportance.Low, $" Skipping JAVA_HOME value of `{java_home}` as `{jvm} could not be found.");
- return false;
- }
- if (!Directory.Exists (includePath)) {
- Log.LogMessage (MessageImportance.Low, $" Skipping JAVA_HOME value of `{java_home}` as the `include` directory could not be found.");
- return false;
- }
-
- return true;
- }
-
- string GetJavaHomePathFromEnvironment ()
- {
- var java_home = Environment.GetEnvironmentVariable ("JAVA_HOME");
- if (!string.IsNullOrEmpty (java_home))
- return java_home;
- return null;
- }
-
- // macOS
- string GetJavaHomePathFromLibexec ()
- {
- var java_home = Path.GetFullPath ("/usr/libexec/java_home");
- if (!File.Exists (java_home)) {
- return null;
- }
- string path = null;
- Exec (java_home, "", (o, e) => {
- if (string.IsNullOrEmpty (e.Data))
- return;
- Log.LogMessage (MessageImportance.Low, $" {e.Data}");
- path = e.Data;
- });
- return path;
- }
-
- // Linux
- string GetJavaHomePathFromAlternatives ()
- {
- var alternatives = Path.GetFullPath ("/etc/alternatives/java");
- if (!File.Exists (alternatives))
- return null;
- string targetJava = null;
- Exec ("readlink", $"\"{alternatives}\"", (o, e) => {
- if (string.IsNullOrEmpty (e.Data))
- return;
- Log.LogMessage (MessageImportance.Low, $" {e.Data}");
- targetJava = e.Data;
- });
- if (string.IsNullOrEmpty (targetJava))
- return null;
- return GetJavaHomePathFromJava (targetJava);
- }
-
- string GetJavaHomePathFromMachine (Version maxVersion)
- {
- var java_homes = GetJavaHomePathsFromDirectory (JdksRoot)
- .Concat (GetJavaHomePathsFromJava ())
- .Concat (GetJavaHomePathsFromWindowsRegistry ())
- .Where (d => Directory.Exists (d))
- .Distinct ()
- .ToList ();
-
- foreach (var p in java_homes) {
- Log.LogMessage (MessageImportance.Low, $" Possible JAVA_HOME location: {p}");
- }
-
- var versionComparer = new ComparisonComparer((x, y) => {
- int r = 0;
- if (x.Version != null && y.Version != null)
- r = x.Version.CompareTo (y.Version);
- return r;
- });
-
- java_homes = java_homes.Where (d => ValidateJdkPath (maxVersion, d))
- .Select (jh => new JdkComparisonInfo {
- Path = jh,
- Version = GetVersionFromPath (jh),
- })
- .Where (v => (maxVersion == null || v.Version == null) ? true : v.Version <= maxVersion)
- .OrderByDescending (v => v, versionComparer)
- .ThenByDescending (v => Directory.GetLastWriteTimeUtc (v.Path))
- .Select (v => v.Path)
- .ToList ();
-
- foreach (var p in java_homes) {
- Log.LogMessage (MessageImportance.Low, $" Filtered JAVA_HOME location: {p}");
- }
-
- return java_homes.FirstOrDefault ();
- }
-
- IEnumerable GetJavaHomePathsFromDirectory (string jdksRoot)
- {
- if (string.IsNullOrEmpty (jdksRoot))
- yield break;
- if (!Directory.Exists (jdksRoot))
- yield break;
- foreach (var d in Directory.EnumerateDirectories (jdksRoot)) {
- var h = d;
- if (OS.IsMacOS)
- h = Path.Combine (h, "Contents", "Home");
- yield return h;
- }
- }
-
- IEnumerable GetJavaHomePathsFromJava ()
- {
- var javas = Environment.GetEnvironmentVariable ("PATH").Split (Path.PathSeparator)
- .SelectMany (p => FindExecutablesInDirectory (p, "java"));
-
- foreach (var exe in javas) {
- var java_home = GetJavaHomePathFromJava (exe);
- if (string.IsNullOrEmpty (java_home))
- continue;
- yield return java_home;
- }
- }
-
- string GetJavaHomePathFromJava (string java)
- {
- const string JavaHome = "java.home = ";
- string java_home = null;
- Exec (java, "-XshowSettings:properties -version", (o, e) => {
- int i = e.Data?.IndexOf (JavaHome) ?? -1;
- if (i < 0)
- return;
- Log.LogMessage (MessageImportance.Low, $" {e.Data}");
- java_home = e.Data.Substring (JavaHome.Length + i);
- // `java -XshowSettings:properties -version 2>&1 | grep java.home` ends with `/jre` on macOS.
- // We need the parent dir so we can properly lookup the `include` directories
- if (java_home.EndsWith ("jre", StringComparison.OrdinalIgnoreCase)) {
- java_home = Path.GetDirectoryName (java_home);
- }
- });
- return java_home;
- }
-
- void Exec (string java, string arguments, DataReceivedEventHandler output)
- {
- Log.LogMessage (MessageImportance.Low, $" Tool {java} execution started with arguments: {arguments}");
- var psi = new ProcessStartInfo () {
- FileName = java,
- Arguments = arguments,
- UseShellExecute = false,
- RedirectStandardInput = false,
- RedirectStandardOutput = true,
- RedirectStandardError = true,
- CreateNoWindow = true,
- WindowStyle = ProcessWindowStyle.Hidden,
- };
- var p = new Process () {
- StartInfo = psi,
- };
- p.OutputDataReceived += output;
- p.ErrorDataReceived += output;
-
- using (p) {
- p.StartInfo = psi;
- p.Start ();
- p.BeginOutputReadLine ();
- p.BeginErrorReadLine ();
- p.WaitForExit ();
- }
- }
-
- IEnumerable GetJavaHomePathsFromWindowsRegistry ()
- {
- if (Path.DirectorySeparatorChar == '/')
- yield break;
-
- // check the user specified path
- var roots = new [] { RegistryEx.CurrentUser, RegistryEx.LocalMachine };
- const RegistryEx.Wow64 wow = RegistryEx.Wow64.Key32;
- var regKey = GetMDRegistryKey ();
-
- foreach (var root in roots) {
- if (CheckRegistryKeyForExecutable (root, regKey, MDREG_JAVA_SDK, wow, "bin", JARSIGNER))
- yield return RegistryEx.GetValueString (root, regKey, MDREG_JAVA_SDK, wow);
- }
-
- string subkey = @"SOFTWARE\JavaSoft\Java Development Kit";
-
- Log.LogMessage (MessageImportance.Low, "Looking for Java 6 SDK...");
-
- foreach (var wow64 in new [] { RegistryEx.Wow64.Key32, RegistryEx.Wow64.Key64 }) {
- string key_name = string.Format (@"{0}\{1}\{2}", "HKLM", subkey, "CurrentVersion");
- var currentVersion = RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey, "CurrentVersion", wow64);
-
- if (!string.IsNullOrEmpty (currentVersion)) {
- Log.LogMessage (MessageImportance.Low, $" Key {key_name} found.");
-
- // No matter what the CurrentVersion is, look for 1.6 or 1.7 or 1.8
- if (CheckRegistryKeyForExecutable (RegistryEx.LocalMachine, subkey + "\\" + "1.8", "JavaHome", wow64, "bin", JARSIGNER))
- yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.8", "JavaHome", wow64);
-
- if (CheckRegistryKeyForExecutable (RegistryEx.LocalMachine, subkey + "\\" + "1.7", "JavaHome", wow64, "bin", JARSIGNER))
- yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.7", "JavaHome", wow64);
-
- if (CheckRegistryKeyForExecutable (RegistryEx.LocalMachine, subkey + "\\" + "1.6", "JavaHome", wow64, "bin", JARSIGNER))
- yield return RegistryEx.GetValueString (RegistryEx.LocalMachine, subkey + "\\" + "1.6", "JavaHome", wow64);
- }
-
- Log.LogMessage (MessageImportance.Low, $" Key {key_name} not found.");
- }
- }
-
- string GetMDRegistryKey ()
- {
- var regKey = Environment.GetEnvironmentVariable ("XAMARIN_ANDROID_REGKEY");
- return string.IsNullOrWhiteSpace (regKey) ? MDREG_KEY : regKey;
- }
-
- private bool CheckRegistryKeyForExecutable (UIntPtr key, string subkey, string valueName, RegistryEx.Wow64 wow64, string subdir, string exe)
- {
- string key_name = string.Format (@"{0}\{1}\{2}", key == RegistryEx.CurrentUser ? "HKCU" : "HKLM", subkey, valueName);
-
- var value = RegistryEx.GetValueString (key, subkey, valueName, wow64);
- var path = string.IsNullOrEmpty (value) ? null : value;
-
- if (path == null) {
- Log.LogMessage (MessageImportance.Low, $" Key {key_name} not found.");
- return false;
- }
-
- if (!FindExecutablesInDirectory (Path.Combine (path, subdir), exe).Any ()) {
- Log.LogMessage (MessageImportance.Low, $" Key {key_name} found:\n Path does not contain {exe} in \\{subdir} ({path}).");
- return false;
- }
-
- Log.LogMessage (MessageImportance.Low, $" Key {key_name} found:\n Path contains {exe} in \\{subdir} ({path}).");
-
- return true;
- }
-
- IEnumerable FindExecutablesInDirectory (string dir, string executable)
- {
- foreach (var exe in Executables (executable)) {
- var p = Path.Combine (dir, exe);
- if (File.Exists (p))
- yield return p;
- }
- }
-
- IEnumerable Executables (string executable)
- {
- var pathExt = Environment.GetEnvironmentVariable ("PATHEXT");
- var pathExts = pathExt?.Split (new char [] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
-
- if (pathExts == null) {
- yield return executable;
- yield break;
- }
-
- foreach (var ext in pathExts)
- yield return Path.ChangeExtension (executable, ext);
- }
-
- IEnumerable FindLibrariesInDirectory (string dir, string libraryName)
- {
- var library = string.Format (OS.NativeLibraryFormat, libraryName);
- return Directory.EnumerateFiles (dir, library, SearchOption.AllDirectories);
- }
-
- class JdkComparisonInfo {
- public string Path;
- public Version Version;
- }
- }
-
- class ComparisonComparer : IComparer {
-
- Comparison comparison;
-
- public ComparisonComparer (Comparison comparison)
- {
- this.comparison = comparison;
- }
-
- public int Compare (T x, T y)
- {
- return comparison (x, y);
- }
- }
-}
diff --git a/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/RegistryEx.cs b/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/RegistryEx.cs
deleted file mode 100644
index 0973a7716..000000000
--- a/src/Java.Interop.BootstrapTasks/Java.Interop.BootstrapTasks/RegistryEx.cs
+++ /dev/null
@@ -1,126 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace Java.Interop.BootstrapTasks
-{
- internal static class RegistryEx
- {
- const string ADVAPI = "advapi32.dll";
-
- public static UIntPtr CurrentUser = (UIntPtr)0x80000001;
- public static UIntPtr LocalMachine = (UIntPtr)0x80000002;
-
- [DllImport (ADVAPI, CharSet = CharSet.Unicode, SetLastError = true)]
- static extern int RegOpenKeyEx (UIntPtr hKey, string subKey, uint reserved, uint sam, out UIntPtr phkResult);
-
- [DllImport (ADVAPI, CharSet = CharSet.Unicode, SetLastError = true)]
- static extern int RegQueryValueExW (UIntPtr hKey, string lpValueName, int lpReserved, out uint lpType,
- StringBuilder lpData, ref uint lpcbData);
-
- [DllImport (ADVAPI, CharSet = CharSet.Unicode, SetLastError = true)]
- static extern int RegSetValueExW (UIntPtr hKey, string lpValueName, int lpReserved,
- uint dwType, string data, uint cbData);
-
- [DllImport (ADVAPI, CharSet = CharSet.Unicode, SetLastError = true)]
- static extern int RegSetValueExW (UIntPtr hKey, string lpValueName, int lpReserved,
- uint dwType, IntPtr data, uint cbData);
-
- [DllImport (ADVAPI, CharSet = CharSet.Unicode, SetLastError = true)]
- static extern int RegCreateKeyEx (UIntPtr hKey, string subKey, uint reserved, string @class, uint options,
- uint samDesired, IntPtr lpSecurityAttributes, out UIntPtr phkResult, out Disposition lpdwDisposition);
-
- [DllImport ("advapi32.dll", SetLastError = true)]
- static extern int RegCloseKey (UIntPtr hKey);
-
- public static string GetValueString (UIntPtr key, string subkey, string valueName, Wow64 wow64)
- {
- UIntPtr regKeyHandle;
- uint sam = (uint)Rights.QueryValue + (uint)wow64;
- if (RegOpenKeyEx (key, subkey, 0, sam, out regKeyHandle) != 0)
- return null;
-
- try {
- uint type;
- var sb = new StringBuilder (2048);
- uint cbData = (uint)sb.Capacity;
- if (RegQueryValueExW (regKeyHandle, valueName, 0, out type, sb, ref cbData) == 0) {
- return sb.ToString ();
- }
- return null;
- } finally {
- RegCloseKey (regKeyHandle);
- }
- }
-
- public static void SetValueString (UIntPtr key, string subkey, string valueName, string value, Wow64 wow64)
- {
- UIntPtr regKeyHandle;
- uint sam = (uint)(Rights.CreateSubKey | Rights.SetValue) + (uint)wow64;
- uint options = (uint)Options.NonVolatile;
- Disposition disposition;
- if (RegCreateKeyEx (key, subkey, 0, null, options, sam, IntPtr.Zero, out regKeyHandle, out disposition) != 0) {
- throw new Exception ("Could not open or craete key");
- }
-
- try {
- uint type = (uint)ValueType.String;
- uint lenBytesPlusNull = ((uint)value.Length + 1) * 2;
- var result = RegSetValueExW (regKeyHandle, valueName, 0, type, value, lenBytesPlusNull);
- if (result != 0)
- throw new Exception (string.Format ("Error {0} setting registry key '{1}{2}@{3}'='{4}'",
- result, key, subkey, valueName, value));
- } finally {
- RegCloseKey (regKeyHandle);
- }
- }
-
- [Flags]
- enum Rights : uint
- {
- None = 0,
- QueryValue = 0x0001,
- SetValue = 0x0002,
- CreateSubKey = 0x0004,
- EnumerateSubKey = 0x0008,
- }
-
- enum Options
- {
- BackupRestore = 0x00000004,
- CreateLink = 0x00000002,
- NonVolatile = 0x00000000,
- Volatile = 0x00000001,
- }
-
- public enum Wow64 : uint
- {
- Key64 = 0x0100,
- Key32 = 0x0200,
- }
-
- enum ValueType : uint
- {
- None = 0, //REG_NONE
- String = 1, //REG_SZ
- UnexpandedString = 2, //REG_EXPAND_SZ
- Binary = 3, //REG_BINARY
- DWord = 4, //REG_DWORD
- DWordLittleEndian = 4, //REG_DWORD_LITTLE_ENDIAN
- DWordBigEndian = 5, //REG_DWORD_BIG_ENDIAN
- Link = 6, //REG_LINK
- MultiString = 7, //REG_MULTI_SZ
- ResourceList = 8, //REG_RESOURCE_LIST
- FullResourceDescriptor = 9, //REG_FULL_RESOURCE_DESCRIPTOR
- ResourceRequirementsList = 10, //REG_RESOURCE_REQUIREMENTS_LIST
- QWord = 11, //REG_QWORD
- QWordLittleEndian = 11, //REG_QWORD_LITTLE_ENDIAN
- }
-
- enum Disposition : uint
- {
- CreatedNewKey = 0x00000001,
- OpenedExistingKey = 0x00000002,
- }
- }
-}