diff --git a/build-tools/automation/azure-pipelines.yaml b/build-tools/automation/azure-pipelines.yaml index c3886c7a0..d3b1d7941 100644 --- a/build-tools/automation/azure-pipelines.yaml +++ b/build-tools/automation/azure-pipelines.yaml @@ -18,7 +18,7 @@ pr: variables: RunningOnCI: true Build.Configuration: Release - DotNetCoreVersion: 3.1.300 + DotNetCoreVersion: 5.0.103 HostedMacImage: macOS-10.15 HostedWinVS2019: Hosted Windows 2019 with VS2019 NetCoreTargetFrameworkPathSuffix: -netcoreapp3.1 @@ -90,6 +90,8 @@ jobs: - template: templates\core-build.yaml - template: templates\core-tests.yaml + parameters: + runNativeDotnetTests: true - template: templates\fail-on-issue.yaml diff --git a/build-tools/automation/templates/core-tests.yaml b/build-tools/automation/templates/core-tests.yaml index b62a7615f..f62747fa3 100644 --- a/build-tools/automation/templates/core-tests.yaml +++ b/build-tools/automation/templates/core-tests.yaml @@ -69,7 +69,7 @@ steps: - task: DotNetCoreCLI@2 displayName: 'Tests: Java.Interop' - condition: eq('${{ parameters.runNativeTests }}', 'true') + condition: or(eq('${{ parameters.runNativeDotnetTests }}', 'true'), eq('${{ parameters.runNativeTests }}', 'true')) inputs: command: test arguments: bin/Test$(Build.Configuration)$(NetCoreTargetFrameworkPathSuffix)/Java.Interop-Tests.dll diff --git a/build-tools/scripts/NativeToolchain.targets b/build-tools/scripts/NativeToolchain.targets new file mode 100644 index 000000000..6d8ec76e9 --- /dev/null +++ b/build-tools/scripts/NativeToolchain.targets @@ -0,0 +1,18 @@ + + + + + <_Vcvarsall + Include="$(VSINSTALLROOT)\VC\Auxiliary\Build\vcvarsall.bat" + /> + + + <_Vcvarsall>%(_Vcvarsall.Identity) + call "$(_Vcvarsall)" + + + -G "NMake Makefiles" + -G "Unix Makefiles" + + + diff --git a/build-tools/scripts/RunCmake.proj b/build-tools/scripts/RunCmake.proj new file mode 100644 index 000000000..5ea67f6b5 --- /dev/null +++ b/build-tools/scripts/RunCmake.proj @@ -0,0 +1,73 @@ + + + + + + + + + + + + + <_Prepare>$(PrepareNativeToolchain) + <_Prepare Condition=" '$(_Prepare)' != '' And !$(_Prepare.Trim().EndsWith('&&')) ">$(_Prepare) && + <_SourceDir>$(CmakeSourceDir.Replace('%5c', '/')) + <_BuildDir>$(CmakeBuildDir.Replace('%5c', '/')) + <_ExtraArgs>$(CmakeExtraArgs.Replace('%5c', '/')) + + + + <_CmakeStatus>$(MSBuildLastTaskResult) + + + + + + + + + + + + + + diff --git a/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs b/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs index 57384f8d1..dcfd35289 100644 --- a/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs +++ b/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs @@ -70,6 +70,15 @@ public JreRuntime CreateJreVM () public class JreRuntime : JniRuntime { + static JreRuntime () + { + if (Environment.OSVersion.Platform == PlatformID.Win32NT) { + var baseDir = Path.GetDirectoryName (typeof (JreRuntime).Assembly.Location); + var newDir = Path.Combine (baseDir, Environment.Is64BitProcess ? "win-x64" : "win-x86"); + NativeMethods.AddDllDirectory (newDir); + } + } + static int CreateJavaVM (out IntPtr javavm, out IntPtr jnienv, ref JavaVMInitArgs args) { return NativeMethods.java_interop_jvm_create (out javavm, out jnienv, ref args); @@ -168,6 +177,9 @@ partial class NativeMethods { [DllImport (JavaInteropLib, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] internal static extern int java_interop_jvm_create (out IntPtr javavm, out IntPtr jnienv, ref JavaVMInitArgs args); + + [DllImport ("kernel32", CharSet=CharSet.Unicode)] + internal static extern int AddDllDirectory (string NewDirectory); } } diff --git a/src/java-interop/CMakeLists.txt b/src/java-interop/CMakeLists.txt new file mode 100644 index 000000000..a48c0b7b0 --- /dev/null +++ b/src/java-interop/CMakeLists.txt @@ -0,0 +1,61 @@ +set(CMAKE_OSX_ARCHITECTURES x86_64 arm64) + +project( + java-interop + DESCRIPTION "Java.Interop native support" + HOMEPAGE_URL "https://github.com/xamarin/java.interop/" + LANGUAGES CXX C +) + +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_VISIBILITY_PRESET hidden) + +option(ENABLE_MONO_INTEGRATION "Require Mono runtime" OFF) + +cmake_minimum_required(VERSION 3.10.2) + +set(JAVA_INTEROP_CORE_SOURCES + java-interop-dlfcn.cc + java-interop-jvm.cc + java-interop-logger.cc + java-interop-util.cc + java-interop.cc + ${JNI_C_PATH} +) +set(JAVA_INTEROP_MONO_SOURCES + java-interop-gc-bridge-mono.cc + java-interop-mono.cc +) + +add_compile_definitions("JAVA_INTEROP_DLL_EXPORT") +add_compile_definitions("JI_DLL_EXPORT") + +foreach(dir in ${JDK_INCLUDE_LIST}) + include_directories(${dir}) +endforeach() + +set(LINK_FLAGS "") + +if(ENABLE_MONO_INTEGRATION) + foreach(dir in ${MONO_INCLUDE_LIST}) + include_directories(${dir}) + endforeach() + list(APPEND LINK_FLAGS ${MONO_LINK_FLAGS}) + list(APPEND LINK_FLAGS "-Wl,-undefined -Wl,suppress -Wl,-flat_namespace") + set(JAVA_INTEROP_SOURCES ${JAVA_INTEROP_CORE_SOURCES} ${JAVA_INTEROP_MONO_SOURCES}) +else() + set(JAVA_INTEROP_SOURCES ${JAVA_INTEROP_CORE_SOURCES}) +endif() + +add_library( + java-interop + SHARED + ${JAVA_INTEROP_SOURCES} +) +target_link_libraries( + java-interop + ${LINK_FLAGS} +) diff --git a/src/java-interop/Directory.Build.targets b/src/java-interop/Directory.Build.targets new file mode 100644 index 000000000..bb5ac87fb --- /dev/null +++ b/src/java-interop/Directory.Build.targets @@ -0,0 +1,100 @@ + + + + + + <_JavaInteropLibName Condition=" $([MSBuild]::IsOSPlatform ('osx')) ">libjava-interop.dylib + <_JavaInteropLibName Condition=" $([MSBuild]::IsOSPlatform ('linux')) ">libjava-interop.so + <_JavaInteropLibName Condition=" $([MSBuild]::IsOSPlatform ('windows')) ">java-interop.dll + + + + <_JavaInteropNativeLib Include="CMakeLists.txt"> + x86_amd64 + win-x64\ + + <_JavaInteropNativeLib Include="CMakeLists.txt"> + x86 + win-x86\ + + + + + <_JavaInteropNativeLib Include="CMakeLists.txt" /> + + + + + PreserveNewest + %(Dir)$(_JavaInteropLibName) + + + + + + + + + + + + + + + + + + + + <_MonoDirs>"-DMONO_INCLUDE_LIST=@(MonoIncludePath, ';')" + <_MonoLib>"-DMONO_LINK_FLAGS=$(MonoLibs)" + <_EnableMono>-DENABLE_MONO_INTEGRATION=ON + + + <_JdkDirs>"-DJDK_INCLUDE_LIST=@(JdkIncludePath, ';')" + <_Jni_c>"-DJNI_C_PATH=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)jni.c" + <_ExtraArgs>$([MSBuild]::Escape('$(_JdkDirs) $(_Jni_c) $(_EnableMono) $(_MonoDirs) $(_MonoLib)')) + + + + + + + <_Cmake + Condition=" '$(PrepareNativeToolchain)' != '' " + Include="PrepareNativeToolchain=$(PrepareNativeToolchain) %(_JavaInteropNativeLib.Arch)" + /> + <_Cmake Include="CmakePath=$(CmakePath)" /> + <_Cmake Include="CmakeGenerator=$(CmakeGenerator)" /> + <_Cmake Include="CmakeSourceDir=$(MSBuildThisFileDirectory)" /> + <_Cmake Include="CmakeBuildDir=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)%(_JavaInteropNativeLib.Dir)" /> + <_Cmake Include="CmakeExtraArgs=$(_ExtraArgs)" /> + + + + + <_Libs Include="$(IntermediateOutputPath)%(_JavaInteropNativeLib.Dir)$(_JavaInteropLibName)*" /> + + + + + + + + + + diff --git a/src/java-interop/java-interop-dlfcn.cc b/src/java-interop/java-interop-dlfcn.cc index 8673c7b91..0ce625687 100644 --- a/src/java-interop/java-interop-dlfcn.cc +++ b/src/java-interop/java-interop-dlfcn.cc @@ -2,11 +2,8 @@ #include "java-interop-dlfcn.h" #include "java-interop-util.h" -#ifdef WINDOWS -#include -#include -#include -#include +#ifdef _WINDOWS +#include #else #include #include @@ -17,7 +14,7 @@ namespace microsoft::java_interop { static char * _get_last_dlerror () { -#ifdef WINDOWS +#ifdef _WINDOWS DWORD error = GetLastError (); if (error == ERROR_SUCCESS /* 0 */) { @@ -43,11 +40,11 @@ _get_last_dlerror () return message; -#else // ndef WINDOWS +#else // ndef _WINDOWS return java_interop_strdup (dlerror ()); -#endif // ndef WINDOWS +#endif // ndef _WINDOWS } static void @@ -86,7 +83,7 @@ java_interop_lib_load (const char *path, [[maybe_unused]] unsigned int flags, ch void *handle = nullptr; -#ifdef WINDOWS +#ifdef _WINDOWS wchar_t *wpath = utf8_to_utf16 (path); if (wpath == nullptr) { @@ -96,13 +93,13 @@ java_interop_lib_load (const char *path, [[maybe_unused]] unsigned int flags, ch HMODULE module = LoadLibraryExW ( /* lpLibFileName */ wpath, /* hFile */ nullptr, - /* dwFlags */ LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS + /* dwFlags */ LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 ); java_interop_free (wpath); handle = reinterpret_cast(module); -#else // ndef WINDOWS +#else // ndef _WINDOWS int mode = 0; if ((flags & JAVA_INTEROP_LIB_LOAD_GLOBALLY) == JAVA_INTEROP_LIB_LOAD_GLOBALLY) { @@ -119,7 +116,7 @@ java_interop_lib_load (const char *path, [[maybe_unused]] unsigned int flags, ch handle = dlopen (path, mode); -#endif // ndef WINDOWS +#endif // ndef _WINDOWS if (handle == nullptr) { _set_error_to_last_error (error); @@ -144,17 +141,17 @@ java_interop_lib_symbol (void *library, const char *symbol, char **error) void *address = nullptr; -#ifdef WINDOWS +#ifdef _WINDOWS HMODULE module = reinterpret_cast(library); FARPROC a = GetProcAddress (module, symbol); address = reinterpret_cast(a); -#else // ndef WINDOWS +#else // ndef _WINDOWS address = dlsym (library, symbol); -#endif // ndef WINDOWS +#endif // ndef _WINDOWS if (address == nullptr) { _set_error_to_last_error (error); @@ -174,18 +171,18 @@ java_interop_lib_close (void* library, char **error) int r = 0; -#ifdef WINDOWS +#ifdef _WINDOWS HMODULE h = reinterpret_cast(library); BOOL v = FreeLibrary (h); if (!v) { r = JAVA_INTEROP_LIB_CLOSE_FAILED; } -#else // ndef WINDOWS +#else // ndef _WINDOWS r = dlclose (library); if (r != 0) { r = JAVA_INTEROP_LIB_CLOSE_FAILED; } -#endif // ndef WINDOWS +#endif // ndef _WINDOWS if (r != 0) { _set_error_to_last_error (error); diff --git a/src/java-interop/java-interop-gc-bridge-mono.cc b/src/java-interop/java-interop-gc-bridge-mono.cc index b6e854f5e..7b92487c7 100644 --- a/src/java-interop/java-interop-gc-bridge-mono.cc +++ b/src/java-interop/java-interop-gc-bridge-mono.cc @@ -11,7 +11,7 @@ #include "java-interop-mono.h" #include "java-interop-util.h" -#ifdef WINDOWS +#ifdef _WINDOWS #include #endif @@ -141,7 +141,7 @@ java_interop_gc_bridge_destroy (JavaInteropGCBridge *bridge) return 0; } -#ifdef WINDOWS +#ifdef _WINDOWS static char* _ji_realpath_win_loop (wchar_t* wpath, DWORD len) { @@ -178,7 +178,7 @@ ji_realpath (const char *path) if (path == NULL) return NULL; -#ifndef WINDOWS +#ifndef _WINDOWS char *rp = realpath (path, NULL); if (rp == NULL) { return strdup (path); diff --git a/src/java-interop/java-interop-logger.cc b/src/java-interop/java-interop-logger.cc index 095f31486..14fc4fe65 100644 --- a/src/java-interop/java-interop-logger.cc +++ b/src/java-interop/java-interop-logger.cc @@ -1,15 +1,19 @@ #include #include +#ifndef _MSC_VER +#include +#endif // ndef _MSC_VER + #include "java-interop-logger.h" #define LOG_VA_ARGS(_kind_,_category_,_format_) \ do { \ - const char* kind = (_kind_); \ - LogCategories category = (_category_); \ + const char* _kind = (_kind_); \ + LogCategories _cat = (_category_); \ va_list args; \ - va_start (args, (_format_)); \ - log_vprint (kind, CATEGORY_NAME (category), (_format_), args); \ + va_start (args, _format_); \ + log_vprint (_kind, CATEGORY_NAME (_cat), (_format_), args); \ va_end (args); \ } while (0) @@ -29,7 +33,15 @@ static const char* log_names[] = { "*error*", }; -#if defined(__i386__) && defined(__GNUC__) +#if defined(_MSC_VER) +#pragma intrinsic(_BitScanForward) +static inline unsigned long ffs (unsigned long value) +{ + unsigned long index; + unsigned char isNonzero = _BitScanForward (&index, value); + return isNonzero ? (index + 1) : 0; +} +#elif defined(__i386__) && defined(__GNUC__) #define ffs(__value__) __builtin_ffs ((__value__)) #elif defined(__x86_64__) && defined(__GNUC__) #define ffs(__value__) __builtin_ffsll ((__value__)) diff --git a/src/java-interop/java-interop-util.cc b/src/java-interop/java-interop-util.cc index 1e79b8928..39b14a7a0 100644 --- a/src/java-interop/java-interop-util.cc +++ b/src/java-interop/java-interop-util.cc @@ -1,7 +1,7 @@ -#ifdef WINDOWS +#ifdef _WINDOWS #include #include -#include +#include char* utf16_to_utf8 (const wchar_t *widestr) @@ -30,4 +30,4 @@ utf8_to_utf16 (const char *mbstr) return widestr; } -#endif // def WINDOWS +#endif // def _WINDOWS diff --git a/src/java-interop/java-interop-util.h b/src/java-interop/java-interop-util.h index 64f8dc1a6..a76060d3f 100644 --- a/src/java-interop/java-interop-util.h +++ b/src/java-interop/java-interop-util.h @@ -3,13 +3,13 @@ #include -#ifdef WINDOWS +#ifdef _WINDOWS /* Those two conversion functions are only properly implemented on Windows * because that's the only place where they should be useful. */ char* utf16_to_utf8 (const wchar_t *widestr); wchar_t* utf8_to_utf16 (const char *mbstr); -#endif // def WINDOWS +#endif // def _WINDOWS #include "java-interop-logger.h" diff --git a/src/java-interop/java-interop.cc b/src/java-interop/java-interop.cc index 417d979a0..282333753 100644 --- a/src/java-interop/java-interop.cc +++ b/src/java-interop/java-interop.cc @@ -3,6 +3,11 @@ #include "java-interop.h" +#ifdef _WINDOWS +// Warning C4996: 'strdup': The POSIX name for this item is deprecated. +#define strdup _strdup +#endif // ndef _WINDOWS + char* java_interop_strdup (const char* value) { diff --git a/src/java-interop/java-interop.csproj b/src/java-interop/java-interop.csproj index 13ae624e8..4db957592 100644 --- a/src/java-interop/java-interop.csproj +++ b/src/java-interop/java-interop.csproj @@ -16,43 +16,6 @@ 3 - - - - - - - - - - - - <_MonoIncludePath>@(MonoIncludePath->'%(FullPath)') - <_JdkIncludePath>@(JdkIncludePath->'%(FullPath)') - - - - - $([MSBuild]::Unescape($(DefineSymbols.Replace(' ', ';')))) - $([MSBuild]::Unescape($(_MonoIncludePath)));$([MSBuild]::Unescape($(_JdkIncludePath))) - - - - - - - - - - - - - - - - - - diff --git a/src/java-interop/java-interop.targets b/src/java-interop/java-interop.targets deleted file mode 100644 index 0c4050540..000000000 --- a/src/java-interop/java-interop.targets +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - <_MacLib>$(OutputPath)/lib$(OutputName).dylib - <_UnixLib>$(OutputPath)/lib$(OutputName).so - - - - - PreserveNewest - - - - - - PreserveNewest - - - - - - $([MSBuild]::Unescape($(DefineSymbols.Replace(' ', ';')))) - $([MSBuild]::Unescape($(_MonoIncludePath)));$([MSBuild]::Unescape($(_JdkIncludePath))) - $(IntermediateOutputPath)/%(Filename).o - - - - - - - <_Cl Include="@(ClCompile)"> - gcc -std=c99 -fPIC - g++ -std=c++17 -fPIC - - <_Defines Include="%(ClCompile.PreprocessorDefinitions)" /> - <_Includes Include="%(ClCompile.AdditionalIncludeDirectories)" /> - - - <_Arch Condition=" Exists ('/Library/Frameworks/') ">-m64 - <_Def>@(_Defines->'-D%(Identity)', ' ') - <_Inc>@(_Includes->'-I "%(Identity)"', ' ') - - - - - - - <_Objs Include="%(ClCompile.Obj)" /> - - - <_LinkFlags>-fvisibility=hidden -Wl,-undefined -Wl,suppress -Wl,-flat_namespace - <_Libs>$(MonoLibs) - <_Files>@(_Objs->'%(Identity)', ' ') - - - - - - - - - - <_Objs Include="%(ClCompile.Obj)" /> - - - <_LinkFlags>-fvisibility=hidden -Wl,-undefined -Wl,suppress -Wl,-flat_namespace -fPIC - <_Libs>$(MonoLibs) - <_Files>@(_Objs->'%(Identity)', ' ') - - - - - - - - - diff --git a/tests/NativeTiming/Directory.Build.targets b/tests/NativeTiming/Directory.Build.targets index f1ff4fcf2..6d7cbfe4c 100644 --- a/tests/NativeTiming/Directory.Build.targets +++ b/tests/NativeTiming/Directory.Build.targets @@ -1,108 +1,77 @@ + + - <_NativeTimingLibName Condition=" '$(OS)' != 'Windows_NT' And Exists ('/Library/Frameworks/') ">libNativeTiming.dylib - <_NativeTimingLibName Condition=" '$(OS)' != 'Windows_NT' And !Exists ('/Library/Frameworks/') ">libNativeTiming.so - <_NativeTimingLibName Condition=" '$(OS)' == 'Windows_NT' ">NativeTiming.dll - <_NativeTimingOutputPath>$(OutputPath)$(_NativeTimingLibName) + <_NativeTimingLibName Condition=" $([MSBuild]::IsOSPlatform ('osx')) ">libNativeTiming.dylib + <_NativeTimingLibName Condition=" $([MSBuild]::IsOSPlatform ('linux')) ">libNativeTiming.so + <_NativeTimingLibName Condition=" $([MSBuild]::IsOSPlatform ('windows')) ">NativeTiming.dll + + <_NativeTimingLib Include="CMakeLists.txt"> + x86_amd64 + win-x64\ + + <_NativeTimingLib Include="CMakeLists.txt"> + x86 + win-x86\ + + + + + <_NativeTimingLib Include="CMakeLists.txt" /> + + - + PreserveNewest + %(Dir)$(_NativeTimingLibName) - - + + + - - - <_Vcvarsall - Condition=" '$(VSINSTALLROOT)' != '' And Exists('$(VSINSTALLROOT)') " - Include="$(VSINSTALLROOT)\VC\Auxiliary\Build\vcvarsall.bat" - /> - - - <_Vcvarsall>%(_Vcvarsall.Identity) - <_PrepareToolchain>call "$(_Vcvarsall)" x86_amd64 && - - - <_Make Condition=" '$(OS)' != 'Windows_NT' ">make - <_Make Condition=" '$(OS)' == 'Windows_NT' ">nmake - - + + + + - + <_JdkDirs>"-DJDK_INCLUDE_LIST=@(JdkIncludePath, ';')" - <_CmakeGenerator Condition=" '$(OS)' != 'Windows_NT' ">-G "Unix Makefiles" - <_CmakeGenerator Condition=" '$(OS)' == 'Windows_NT' ">-G "NMake Makefiles" - - - <_CmakeStatus>$(MSBuildLastTaskResult) - - - - - - - - - - - - - - - - - + <_Cmake + Condition=" '$(PrepareNativeToolchain)' != '' " + Include="PrepareNativeToolchain=$(PrepareNativeToolchain) %(_NativeTimingLib.Arch)" + /> + <_Cmake Include="CmakePath=$(CmakePath)" /> + <_Cmake Include="CmakeGenerator=$(CmakeGenerator)" /> + <_Cmake Include="CmakeSourceDir=$(MSBuildThisFileDirectory)" /> + <_Cmake Include="CmakeBuildDir=$(MSBuildThisFileDirectory)$(IntermediateOutputPath)%(_NativeTimingLib.Dir)" /> + <_Cmake Include="CmakeExtraArgs=$(_JdkDirs)" /> + + - <_Libs Include="$(IntermediateOutputPath)$(_NativeTimingLibName)*" /> + <_Libs Include="$(IntermediateOutputPath)%(_NativeTimingLib.Dir)$(_NativeTimingLibName)*" /> - +