diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 00000000..d74e0f88 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,42 @@ +# https://aka.ms/yaml + +name: $(BuildID) + +trigger: +- master + +variables: + Mono.Windows.Url: https://download.mono-project.com/archive/6.0.0/windows-installer/mono-6.0.0.319-gtksharp-2.12.45-win32-0.msi + SdkManager.Windows: 'C:\Program Files (x86)\Android\android-sdk\tools\bin\sdkmanager' + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + +jobs: + +- job: windows + pool: + name: Hosted VS2017 + demands: msbuild + steps: + - powershell: | + echo y | & "$(SdkManager.Windows)" ndk-bundle + displayName: install Android NDK + - powershell: | + Invoke-WebRequest $(Mono.Windows.Url) -OutFile mono.msi -Verbose + Start-Process msiexec -Wait -ArgumentList '/i mono.msi /quiet /l*v mono.log' + Get-Content mono.log + displayName: install mono + - powershell: | + .\build.ps1 -t Jenkins -v diagnostic + displayName: build and test + +- job: mac + pool: + name: Hosted macOS + demands: msbuild + steps: + - bash: | + source build/SetupCI.sh + displayName: setup ci + - bash: | + ./build.sh -t Travis -v diagnostic + displayName: build and test diff --git a/binder/Compilation.cs b/binder/Compilation.cs index d6c4b919..553d7399 100644 --- a/binder/Compilation.cs +++ b/binder/Compilation.cs @@ -687,15 +687,12 @@ bool CompileNDK(IEnumerable files) var libName = $"lib{name}.so"; var ndkPath = XamarinAndroid.AndroidSdk.AndroidNdkPath; - foreach (var abi in new[] { "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }) + foreach (var abi in new[] { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }) { string extra = string.Empty; AndroidTargetArch targetArch; switch (abi) { - case "armeabi": - targetArch = AndroidTargetArch.Arm; - break; case "armeabi-v7a": targetArch = AndroidTargetArch.Arm; extra = " -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16"; @@ -715,8 +712,17 @@ bool CompileNDK(IEnumerable files) throw new NotImplementedException(); } + bool isLLVM = false; var clangBin = NdkUtil.GetNdkClangBin(Path.Combine(ndkPath, "toolchains"), targetArch); - var systemInclude = NdkUtil.GetNdkPlatformIncludePath(ndkPath, targetArch, XamarinAndroid.ApiLevel); + if (string.IsNullOrEmpty(clangBin)) { + clangBin = NdkUtil.GetNdkClangBin(Path.Combine(ndkPath, "toolchains", "llvm"), targetArch); + isLLVM = true; + } + if (string.IsNullOrEmpty (clangBin)) + { + throw new Exception($"Unable to find NDK toolchain for {abi}!"); + } + var systemInclude = NdkUtil.GetNdkPlatformIncludePath(ndkPath, targetArch, XamarinAndroid.ApiLevel, isLLVM); var monoDroidPath = Path.Combine(XamarinAndroid.LibraryPath, abi); var abiDir = Path.Combine(Options.OutputDir, "android", "jni", abi); var outputPath = Path.Combine(abiDir, libName); @@ -731,9 +737,14 @@ bool CompileNDK(IEnumerable files) $"-I\"{monoPath}\"", $"-L\"{monoDroidPath}\" -lmonosgen-2.0 -lmono-android.release", string.Join(" ", files.ToList()), - "--std=c99", + "--std=c11", + "-fPIC", $"-shared -o {outputPath}", }; + if (isLLVM) + { + args.Add($"--target={NdkUtil.GetLlvmToolchainTarget(targetArch, XamarinAndroid.ApiLevel)}"); + } var invocation = string.Join(" ", args); var output = Invoke(clangBin, invocation); diff --git a/binder/Utils/NdkUtils.cs b/binder/Utils/NdkUtils.cs index faf5f77a..1fec7f59 100644 --- a/binder/Utils/NdkUtils.cs +++ b/binder/Utils/NdkUtils.cs @@ -48,9 +48,19 @@ public static string GetNdkTool(string androidNdkPath, AndroidTargetArch arch, s throw new Exception($"C compiler for target {arch} was not found. Tried paths: \"{string.Join("; ", toolPaths)}\""); } - public static string GetNdkPlatformIncludePath(string androidNdkPath, AndroidTargetArch arch, int level) + public static string GetNdkPlatformIncludePath(string androidNdkPath, AndroidTargetArch arch, int level, bool isLLVM) { - string path = Path.Combine(androidNdkPath, "platforms", "android-" + level, "arch-" + GetPlatformArch(arch)); + string path; + if (isLLVM) + { + var toolchainDir = Path.Combine(androidNdkPath, "toolchains", "llvm", "prebuilt"); + var machineDir = Directory.GetDirectories(Path.Combine(toolchainDir)).First(); + path = Path.Combine(machineDir, "sysroot"); + } + else + { + path = Path.Combine(androidNdkPath, "platforms", "android-" + level, "arch-" + GetPlatformArch(arch)); + } if (!Directory.Exists(path)) throw new InvalidOperationException(String.Format("Platform header files for target {0} and API Level {1} was not found. Expected path is \"{2}\"", arch, level, path)); return path; @@ -86,6 +96,10 @@ static string[] GetNdkToolchainDirectories(string toolchainsPath, AndroidTargetA { if (!Directory.Exists(toolchainsPath)) throw new Exception($"Missing Android NDK toolchains directory '{toolchainsPath}'. Please install the Android NDK."); + if (string.Compare(Path.GetFileName(toolchainsPath), "llvm", StringComparison.OrdinalIgnoreCase) == 0) + { + return new[] { toolchainsPath }; + } switch (arch) { case AndroidTargetArch.Arm: @@ -125,17 +139,39 @@ static string GetNdkToolchainPrefix(AndroidTargetArch arch) } } + public static string GetLlvmToolchainTarget (AndroidTargetArch arch, int apiLevel) + { + switch (arch) + { + case AndroidTargetArch.Arm: + return $"armv7a-linux-androideabi{apiLevel}"; + case AndroidTargetArch.Arm64: + return $"aarch64-linux-android{apiLevel}"; + case AndroidTargetArch.X86: + return $"i686-linux-android{apiLevel}"; + case AndroidTargetArch.X86_64: + return $"x86_64-linux-android{apiLevel}"; + default: + return string.Empty; + } + } + public static string GetNdkClangBin(string toolchainsPath, AndroidTargetArch arch) { - var toolChainDir = GetNdkToolchainDirectories(toolchainsPath, arch).First(); - var machineDir = Directory.GetDirectories(Path.Combine(toolChainDir, "prebuilt")).First(); + foreach (var toolChainDir in GetNdkToolchainDirectories(toolchainsPath, arch)) + { + var machineDir = Directory.GetDirectories(Path.Combine(toolChainDir, "prebuilt")).First(); - var executableSuffix = Platform.IsWindows ? ".exe" : string.Empty; - var gcc = Path.Combine(machineDir, "bin", GetNdkToolchainPrefix(arch) + "gcc" + executableSuffix); - if (File.Exists(gcc)) - return gcc; + var executableSuffix = Platform.IsWindows ? ".exe" : string.Empty; + var gcc = Path.Combine(machineDir, "bin", GetNdkToolchainPrefix(arch) + "gcc" + executableSuffix); + if (File.Exists(gcc)) + return gcc; - throw new Exception($"Unable to find NDK toolchain for {arch}!"); + var clang = Path.Combine(machineDir, "bin", "clang" + executableSuffix); + if (File.Exists(clang)) + return clang; + } + return null; } static bool GetNdkToolchainRelease(string androidNdkPath, out string version) diff --git a/build.cake b/build.cake index c5fdeff1..6329761d 100755 --- a/build.cake +++ b/build.cake @@ -34,7 +34,7 @@ Task("Build-Binder") .IsDependentOn("NuGet-Restore") .Does(() => { - MSBuild("./build/projects/Embeddinator-4000.csproj", settings => settings.SetConfiguration(configuration)); + MSBuild("./build/projects/Embeddinator-4000.csproj", MSBuildSettings()); }); Task("Generate-Project-Files") diff --git a/build.ps1 b/build.ps1 index 709f543b..b701aec0 100644 --- a/build.ps1 +++ b/build.ps1 @@ -89,7 +89,7 @@ if(!$PSScriptRoot){ $TOOLS_DIR = Join-Path $PSScriptRoot ".cake" $NUGET_EXE = Join-Path $PSScriptRoot ".cake/nuget.exe" $CAKE_EXE = Join-Path $TOOLS_DIR "Cake/Cake.exe" -$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" +$NUGET_URL = "https://dist.nuget.org/win-x86-commandline/v4.7.3/nuget.exe" $PACKAGES_CONFIG = Join-Path $TOOLS_DIR "packages.config" $PACKAGES_CONFIG_MD5 = Join-Path $TOOLS_DIR "packages.config.md5sum" diff --git a/build.sh b/build.sh index bd64be54..7b9878a1 100755 --- a/build.sh +++ b/build.sh @@ -67,7 +67,7 @@ fi # Download NuGet if it does not exist. if [ ! -f "$NUGET_EXE" ]; then echo "Downloading NuGet..." - curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/latest/nuget.exe + curl -Lsfo "$NUGET_EXE" https://dist.nuget.org/win-x86-commandline/v4.7.3/nuget.exe if [ $? -ne 0 ]; then echo "An error occured while downloading nuget.exe." exit 1 diff --git a/build/Tests.cake b/build/Tests.cake index f1ae60b0..8ae58559 100644 --- a/build/Tests.cake +++ b/build/Tests.cake @@ -11,8 +11,7 @@ Task("Build-Managed") .IsDependentOn("NuGet-Restore") .Does(() => { - MSBuild("./tests/managed/generic/managed-generic.csproj", settings => - settings.SetConfiguration(configuration)); + MSBuild("./tests/managed/generic/managed-generic.csproj", MSBuildSettings()); }); Task("Build-Android") @@ -20,8 +19,7 @@ Task("Build-Android") .IsDependentOn("NuGet-Restore") .Does(() => { - MSBuild("./tests/managed/android/managed-android.csproj", settings => - settings.SetConfiguration(configuration).SetPlatformTarget(PlatformTarget.MSIL)); + MSBuild("./tests/managed/android/managed-android.csproj", MSBuildSettings().SetPlatformTarget(PlatformTarget.MSIL)); }); Task("Build-FSharp-Android") @@ -29,8 +27,7 @@ Task("Build-FSharp-Android") .IsDependentOn("NuGet-Restore") .Does(() => { - MSBuild("./tests/managed/fsharp-android/fsharp-android.fsproj", settings => - settings.SetConfiguration(configuration).SetPlatformTarget(PlatformTarget.MSIL)); + MSBuild("./tests/managed/fsharp-android/fsharp-android.fsproj", MSBuildSettings().SetPlatformTarget(PlatformTarget.MSIL)); }); Task("Build-FSharp-Generic") @@ -38,8 +35,7 @@ Task("Build-FSharp-Generic") .IsDependentOn("NuGet-Restore") .Does(()=> { - MSBuild("./tests/managed/fsharp-generic/fsharp-generic.fsproj", settings => - settings.SetConfiguration(configuration).SetPlatformTarget(PlatformTarget.MSIL)); + MSBuild("./tests/managed/fsharp-generic/fsharp-generic.fsproj", MSBuildSettings().SetPlatformTarget(PlatformTarget.MSIL)); }); Task("Build-PCL") @@ -47,8 +43,7 @@ Task("Build-PCL") .IsDependentOn("NuGet-Restore") .Does(() => { - MSBuild("./tests/managed/pcl/managed-pcl.csproj", settings => - settings.SetConfiguration(configuration).SetPlatformTarget(PlatformTarget.MSIL)); + MSBuild("./tests/managed/pcl/managed-pcl.csproj", MSBuildSettings().SetPlatformTarget(PlatformTarget.MSIL)); }); Task("Build-NetStandard") @@ -58,7 +53,7 @@ Task("Build-NetStandard") { var project = "./tests/managed/netstandard/managed-netstandard.csproj"; DotNetCoreRestore(project); - MSBuild(project, settings => settings.SetConfiguration(configuration).SetPlatformTarget(PlatformTarget.MSIL)); + MSBuild(project, MSBuildSettings().SetPlatformTarget(PlatformTarget.MSIL)); }); Task("Build-CSharp-Tests") @@ -66,7 +61,7 @@ Task("Build-CSharp-Tests") .IsDependentOn("Build-Managed") .Does(() => { - MSBuild("./tests/MonoEmbeddinator4000.Tests/MonoEmbeddinator4000.Tests.csproj", settings => settings.SetConfiguration(configuration)); + MSBuild("./tests/MonoEmbeddinator4000.Tests/MonoEmbeddinator4000.Tests.csproj", MSBuildSettings()); }); Task("Run-CSharp-Tests") @@ -108,9 +103,7 @@ Task("Build-C-Tests") // Execute the build files. if (IsRunningOnWindows()) - MSBuild(mkDir + File("mk.sln"), settings => - settings.SetConfiguration(configuration) - .SetPlatformTarget(PlatformTarget.Win32)); + MSBuild(mkDir + File("mk.sln"), MSBuildSettings().SetPlatformTarget(PlatformTarget.Win32)); else { var envVars = new Dictionary (); diff --git a/build/Utils.cake b/build/Utils.cake index 2fd8b994..59dadca8 100644 --- a/build/Utils.cake +++ b/build/Utils.cake @@ -59,3 +59,41 @@ void Premake(string file, string args, string action) File("premake5.exe") : IsRunningOnMacOS() ? File("premake5-osx") : File("premake5-linux-64")); Exec(premakePath, $"--file={file} {args} {action}"); } + +MSBuildSettings MSBuildSettings() +{ + var settings = new MSBuildSettings { Configuration = configuration }; + + if (IsRunningOnWindows()) + { + // Find MSBuild for Visual Studio 2019 and newer + DirectoryPath vsLatest = VSWhereLatest(); + FilePath msBuildPath = vsLatest?.CombineWithFilePath("./MSBuild/Current/Bin/MSBuild.exe"); + + // Find MSBuild for Visual Studio 2017 + if (msBuildPath != null && !FileExists(msBuildPath)) + msBuildPath = vsLatest.CombineWithFilePath("./MSBuild/15.0/Bin/MSBuild.exe"); + + // Have we found MSBuild yet? + if (!FileExists(msBuildPath)) + { + throw new Exception($"Failed to find MSBuild: {msBuildPath}"); + } + + Information("Building using MSBuild at " + msBuildPath); + settings.ToolPath = msBuildPath; + + var java_home = Environment.GetEnvironmentVariable("JAVA_HOME_8_X64"); + if (!string.IsNullOrEmpty(java_home)) + { + Information("JAVA_HOME_8_X64 set: " + java_home); + settings = settings.WithProperty("JavaSdkDirectory", java_home); + } + } + else + { + settings.ToolPath = Context.Tools.Resolve("msbuild"); + } + + return settings; +} diff --git a/external/Xamarin.Android.Tools b/external/Xamarin.Android.Tools index 4c00c223..294f4471 160000 --- a/external/Xamarin.Android.Tools +++ b/external/Xamarin.Android.Tools @@ -1 +1 @@ -Subproject commit 4c00c223f278afaa7da159d49059a7b28c2b46f4 +Subproject commit 294f4471a76da6df798c8520a8f8da0e6e83d3a5 diff --git a/support/mono-support.h b/support/mono-support.h index a231ade8..a3482de4 100644 --- a/support/mono-support.h +++ b/support/mono-support.h @@ -89,7 +89,9 @@ typedef struct _GString GString; /* utils/mono-publib.h */ typedef int32_t mono_bool; +#ifndef _WIN32 typedef uint16_t mono_unichar2; +#endif /* metadata/image.h */ typedef struct _MonoAssembly MonoAssembly;