diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ae62d692..99b895154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning][]. This document follows the conventions laid out in [Keep a CHANGELOG][]. ## [unreleased][] +- Added VS 2017 build with net40 and NetStandard 1.5 targets ### Added - Added `clr.GetClrType` (#432, #433) diff --git a/pythonnet.15.sln b/pythonnet.15.sln new file mode 100644 index 000000000..0358a736b --- /dev/null +++ b/pythonnet.15.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.10 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.Runtime.15", "src\runtime\Python.Runtime.15.csproj", "{4D2089E1-5B6A-4799-984B-178AE467902D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Python.EmbeddingTest.15", "src\embed_tests\Python.EmbeddingTest.15.csproj", "{4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug-Linux-x64|x64 = Debug-Linux-x64|x64 + Debug-Win-x64|x64 = Debug-Win-x64|x64 + Release-Linux-x64|x64 = Release-Linux-x64|x64 + Release-Win-x64|x64 = Release-Win-x64|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4D2089E1-5B6A-4799-984B-178AE467902D}.Debug-Linux-x64|x64.ActiveCfg = Debug-Linux-x64|x64 + {4D2089E1-5B6A-4799-984B-178AE467902D}.Debug-Linux-x64|x64.Build.0 = Debug-Linux-x64|x64 + {4D2089E1-5B6A-4799-984B-178AE467902D}.Debug-Win-x64|x64.ActiveCfg = Debug-Win-x64|x64 + {4D2089E1-5B6A-4799-984B-178AE467902D}.Debug-Win-x64|x64.Build.0 = Debug-Win-x64|x64 + {4D2089E1-5B6A-4799-984B-178AE467902D}.Release-Linux-x64|x64.ActiveCfg = Release-Win-x64|x64 + {4D2089E1-5B6A-4799-984B-178AE467902D}.Release-Linux-x64|x64.Build.0 = Release-Win-x64|x64 + {4D2089E1-5B6A-4799-984B-178AE467902D}.Release-Win-x64|x64.ActiveCfg = Release-Win-x64|x64 + {4D2089E1-5B6A-4799-984B-178AE467902D}.Release-Win-x64|x64.Build.0 = Release-Win-x64|x64 + {4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}.Debug-Linux-x64|x64.ActiveCfg = Debug|x64 + {4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}.Debug-Linux-x64|x64.Build.0 = Debug|x64 + {4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}.Debug-Win-x64|x64.ActiveCfg = Debug|x64 + {4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}.Debug-Win-x64|x64.Build.0 = Debug|x64 + {4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}.Release-Linux-x64|x64.ActiveCfg = Release|x64 + {4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}.Release-Linux-x64|x64.Build.0 = Release|x64 + {4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}.Release-Win-x64|x64.ActiveCfg = Release|x64 + {4CACAA81-CC6A-4381-85B8-3A4B57EFE3BD}.Release-Win-x64|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/src/embed_tests/Program.cs b/src/embed_tests/Program.cs new file mode 100644 index 000000000..349bf4522 --- /dev/null +++ b/src/embed_tests/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Reflection; +using NUnit.Common; +using NUnitLite; + +namespace Python.EmbeddingTest +{ + public class Program + { + public static int Main(string[] args) + { + ////var example = new TestExample(); + ////example.SetUp(); + ////example.TestReadme(); + ////example.Dispose(); + ////return 0; + return new AutoRun(typeof(Program).GetTypeInfo().Assembly) + .Execute(args, new ExtendedTextWrapper(Console.Out), Console.In); + } + } +} diff --git a/src/embed_tests/Properties/PublishProfiles/FolderProfile.pubxml b/src/embed_tests/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 000000000..6bdb8c414 --- /dev/null +++ b/src/embed_tests/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,14 @@ + + + + + FileSystem + Debug-Linux-x64 + netcoreapp1.0 + bin\publish\Debug-Linux-x64 + ubuntu.14.04-x64 + + \ No newline at end of file diff --git a/src/embed_tests/Properties/launchSettings.json b/src/embed_tests/Properties/launchSettings.json new file mode 100644 index 000000000..a8841cea2 --- /dev/null +++ b/src/embed_tests/Properties/launchSettings.json @@ -0,0 +1,7 @@ +{ + "profiles": { + "Python.EmbeddingTest.15": { + "commandName": "Project" + } + } +} \ No newline at end of file diff --git a/src/embed_tests/Python.EmbeddingTest.15.csproj b/src/embed_tests/Python.EmbeddingTest.15.csproj new file mode 100644 index 000000000..8d4321025 --- /dev/null +++ b/src/embed_tests/Python.EmbeddingTest.15.csproj @@ -0,0 +1,64 @@ + + + exe + netcoreapp1.0 + win7-x64;ubuntu.16.04-x64;ubuntu.14.04-x64 + Python.EmbeddingTest + Python.EmbeddingTest + Python.EmbeddingTest + 3.0.0 + Alpha + false + false + True + + 1.6.0 + + Full + + + x86 + + + x64 + + + + + + + + + + + + $(DefineConstants);XPLAT + + + + + 3.6.1 + + + + + + + + + + + + + 4.0.1 + + + + + + + + PreserveNewest + + + \ No newline at end of file diff --git a/src/embed_tests/pyimport.cs b/src/embed_tests/pyimport.cs index 3bb9a34d6..dbf71da24 100644 --- a/src/embed_tests/pyimport.cs +++ b/src/embed_tests/pyimport.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using NUnit.Framework; using Python.Runtime; @@ -30,7 +30,11 @@ public void SetUp() /* Append the tests directory to sys.path * using reflection to circumvent the private * modifiers placed on most Runtime methods. */ +#if XPLAT + const string s = "fixtures"; +#else const string s = "../fixtures"; +#endif string testPath = Path.Combine(TestContext.CurrentContext.TestDirectory, s); IntPtr str = Runtime.Runtime.PyString_FromString(testPath); diff --git a/src/runtime/Python.Runtime.15.csproj b/src/runtime/Python.Runtime.15.csproj new file mode 100644 index 000000000..f58a1360e --- /dev/null +++ b/src/runtime/Python.Runtime.15.csproj @@ -0,0 +1,99 @@ + + + + net40;netstandard1.5 + Python.Runtime + Python.Runtime + Python.Runtime + 3.0.0 + Alpha + false + false + True + + 1.6.0 + + + x64 + TRACE;DEBUG;X64;LINUX;UNIX;UCS4;PYTHON_WITH_PYMALLOC;MONO_LINUX + + + x64 + TRACE;DEBUG;X64;LINUX;UNIX;UCS4;PYTHON_WITH_PYMALLOC;MONO_LINUX + + + x64 + TRACE;DEBUG;X64;LINUX;UNIX;UCS4;PYTHON_WITH_PYMALLOC;MONO_LINUX + + + x64 + TRACE;DEBUG;X64;LINUX;UNIX;UCS4;PYTHON_WITH_PYMALLOC;MONO_LINUX + + + + x64 + TRACE;DEBUG;X64;UCS2 + + + x64 + TRACE;DEBUG;X64;UCS2 + + + x64 + TRACE;X64;UCS2 + + + x64 + TRACE;DEBUG;X64;UCS2; + + + + $(DefineConstants);XPLAT;REFLECTIONBRIDGE;PYTHON3;PYTHON35 + + + + + bin\Debug + + + + + 2.0.11 + + + 4.0.1 + + + 4.1.0 + + + 4.0.1 + + + 4.0.11 + + + 4.0.1 + + + 4.1.0 + + + 4.0.0 + + + 4.0.0-rc3-24212-01 + + + 4.0.0 + + + + + + + + + + + \ No newline at end of file diff --git a/src/runtime/Python.Runtime.csproj b/src/runtime/Python.Runtime.csproj index 82825a626..2e614d6d5 100644 --- a/src/runtime/Python.Runtime.csproj +++ b/src/runtime/Python.Runtime.csproj @@ -76,6 +76,7 @@ + Properties\SharedAssemblyInfo.cs @@ -158,6 +159,9 @@ clr.py + + + $(TargetPath) diff --git a/src/runtime/arrayobject.cs b/src/runtime/arrayobject.cs index a10688749..0c174135c 100644 --- a/src/runtime/arrayobject.cs +++ b/src/runtime/arrayobject.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; namespace Python.Runtime @@ -140,8 +140,8 @@ public static int mp_ass_subscript(IntPtr ob, IntPtr idx, IntPtr v) int rank = items.Rank; int index; object value; - - if (items.IsReadOnly) + + if (((IList)items).IsReadOnly) { Exceptions.RaiseTypeError("array is read-only"); return -1; diff --git a/src/runtime/assemblymanager.cs b/src/runtime/assemblymanager.cs index 06a4449a2..ad287eba8 100644 --- a/src/runtime/assemblymanager.cs +++ b/src/runtime/assemblymanager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; @@ -6,6 +6,9 @@ using System.IO; using System.Reflection; using System.Threading; +#if NETSTANDARD1_5 +using System.Runtime.Loader; +#endif namespace Python.Runtime { @@ -19,7 +22,9 @@ internal class AssemblyManager // therefore this should be a ConcurrentDictionary private static ConcurrentDictionary> namespaces; //private static Dictionary> generics; +#if !NETSTANDARD1_5 private static AssemblyLoadEventHandler lhandler; +#endif private static ResolveEventHandler rhandler; // updated only under GIL? @@ -48,9 +53,10 @@ internal static void Initialize() AppDomain domain = AppDomain.CurrentDomain; +#if !NETSTANDARD1_5 lhandler = new AssemblyLoadEventHandler(AssemblyLoadHandler); domain.AssemblyLoad += lhandler; - +#endif rhandler = new ResolveEventHandler(ResolveHandler); domain.AssemblyResolve += rhandler; @@ -76,11 +82,13 @@ internal static void Initialize() internal static void Shutdown() { AppDomain domain = AppDomain.CurrentDomain; +#if !NETSTANDARD1_5 domain.AssemblyLoad -= lhandler; +#endif domain.AssemblyResolve -= rhandler; } - +#if !NETSTANDARD1_5 /// /// Event handler for assembly load events. At the time the Python /// runtime loads, we scan the app domain to map the assemblies that @@ -94,7 +102,7 @@ private static void AssemblyLoadHandler(object ob, AssemblyLoadEventArgs args) assemblies.Add(assembly); ScanAssembly(assembly); } - +#endif /// /// Event handler for assembly resolve events. This is needed because @@ -196,7 +204,11 @@ public static Assembly LoadAssembly(string name) Assembly assembly = null; try { +#if NETSTANDARD1_5 + assembly = Assembly.Load(new AssemblyName(name)); +#else assembly = Assembly.Load(name); +#endif } catch (Exception) { @@ -220,7 +232,11 @@ public static Assembly LoadAssemblyPath(string name) { try { +#if NETSTANDARD1_5 + assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path); +#else assembly = Assembly.LoadFrom(path); +#endif } catch (Exception) { @@ -247,7 +263,11 @@ public static Assembly LoadAssemblyFullPath(string name) { try { +#if NETSTANDARD1_5 + assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(name); +#else assembly = Assembly.LoadFrom(name); +#endif } catch (Exception) { @@ -364,7 +384,11 @@ internal static void ScanAssembly(Assembly assembly) namespaces[ns].TryAdd(assembly, string.Empty); } +#if !NETSTANDARD1_5 if (ns != null && t.IsGenericTypeDefinition) +#else + if (ns != null && t.GetTypeInfo().IsGenericTypeDefinition) +#endif { GenericUtil.Register(t); } diff --git a/src/runtime/classbase.cs b/src/runtime/classbase.cs index 4dd3b5364..edbb32061 100644 --- a/src/runtime/classbase.cs +++ b/src/runtime/classbase.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections; using System.Runtime.InteropServices; +using ReflectionBridge.Extensions; namespace Python.Runtime { @@ -25,7 +26,7 @@ internal ClassBase(Type tp) internal virtual bool CanSubclass() { - return !type.IsEnum; + return !type.IsEnum(); } /// diff --git a/src/runtime/classderived.cs b/src/runtime/classderived.cs index 16d3b99db..37c99934f 100644 --- a/src/runtime/classderived.cs +++ b/src/runtime/classderived.cs @@ -5,6 +5,7 @@ using System.Reflection.Emit; using System.Runtime.InteropServices; using System.Threading.Tasks; +using ReflectionBridge.Extensions; namespace Python.Runtime { @@ -123,7 +124,11 @@ internal static Type CreateDerivedType(string name, if (null == assemblyName) { +#if NETSTANDARD1_5 + assemblyName = Assembly.GetEntryAssembly().FullName; +#else assemblyName = Assembly.GetExecutingAssembly().FullName; +#endif } ModuleBuilder moduleBuilder = GetModuleBuilder(assemblyName, moduleName); @@ -133,7 +138,7 @@ internal static Type CreateDerivedType(string name, // if the base type is an interface then use System.Object as the base class // and add the base type to the list of interfaces this new class will implement. - if (baseType.IsInterface) + if (baseType.IsInterface()) { interfaces.Add(baseType); baseClass = typeof(object); @@ -181,7 +186,11 @@ internal static Type CreateDerivedType(string name, } // override any virtual methods not already overridden by the properties above +#if NETSTANDARD1_5 + MethodInfo[] methods = baseType.GetTypeInfo().GetMethods(); +#else MethodInfo[] methods = baseType.GetMethods(); +#endif var virtualMethods = new HashSet(); foreach (MethodInfo method in methods) { @@ -249,16 +258,25 @@ internal static Type CreateDerivedType(string name, il.Emit(OpCodes.Call, baseClass.GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance)); il.Emit(OpCodes.Ret); +#if NETSTANDARD1_5 + TypeInfo type = typeBuilder.CreateTypeInfo(); + // scan the assembly so the newly added class can be imported + Assembly assembly = type.Assembly; +#else Type type = typeBuilder.CreateType(); - // scan the assembly so the newly added class can be imported Assembly assembly = Assembly.GetAssembly(type); +#endif AssemblyManager.ScanAssembly(assembly); // FIXME: assemblyBuilder not used AssemblyBuilder assemblyBuilder = assemblyBuilders[assemblyName]; +#if NETSTANDARD1_5 + return type.AsType(); +#else return type; +#endif } /// @@ -309,7 +327,7 @@ private static void AddConstructor(ConstructorInfo ctor, Type baseType, TypeBuil il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); - if (parameterTypes[i].IsValueType) + if (parameterTypes[i].IsValueType()) { il.Emit(OpCodes.Box, parameterTypes[i]); } @@ -387,7 +405,7 @@ private static void AddVirtualMethod(MethodInfo method, Type baseType, TypeBuild il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); - if (parameterTypes[i].IsValueType) + if (parameterTypes[i].IsValueType()) { il.Emit(OpCodes.Box, parameterTypes[i]); } @@ -474,7 +492,7 @@ private static void AddPythonMethod(string methodName, PyObject func, TypeBuilde il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldc_I4, i); il.Emit(OpCodes.Ldarg, i + 1); - if (argTypes[i].IsValueType) + if (argTypes[i].IsValueType()) { il.Emit(OpCodes.Box, argTypes[i]); } @@ -591,8 +609,13 @@ private static ModuleBuilder GetModuleBuilder(string assemblyName, string module } else { +#if NETSTANDARD1_5 + assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(assemblyName), + AssemblyBuilderAccess.Run); +#else assemblyBuilder = domain.DefineDynamicAssembly(new AssemblyName(assemblyName), AssemblyBuilderAccess.Run); +#endif assemblyBuilders[assemblyName] = assemblyBuilder; } @@ -677,12 +700,18 @@ public static T InvokeMethod(IPythonDerivedType obj, string methodName, strin { throw new NotImplementedException("Python object does not have a '" + methodName + "' method"); } - +#if NETSTANDARD1_5 + return (T)obj.GetType() + .GetTypeInfo() + .GetMethod(origMethodName, BindingFlags.InvokeMethod) + .Invoke(obj, args); +#else return (T)obj.GetType().InvokeMember(origMethodName, BindingFlags.InvokeMethod, null, obj, args); +#endif } public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, string origMethodName, @@ -740,11 +769,18 @@ public static void InvokeMethodVoid(IPythonDerivedType obj, string methodName, s throw new NotImplementedException($"Python object does not have a '{methodName}' method"); } +#if NETSTANDARD1_5 + obj.GetType() + .GetTypeInfo() + .GetMethod(origMethodName, BindingFlags.InvokeMethod) + .Invoke(obj, args); +#else obj.GetType().InvokeMember(origMethodName, BindingFlags.InvokeMethod, null, obj, args); +#endif } public static T InvokeGetProperty(IPythonDerivedType obj, string propertyName) @@ -802,11 +838,17 @@ public static void InvokeSetProperty(IPythonDerivedType obj, string propertyN public static void InvokeCtor(IPythonDerivedType obj, string origCtorName, object[] args) { // call the base constructor +#if NETSTANDARD1_5 + obj.GetType() + .GetMethod(origCtorName, BindingFlags.InvokeMethod) + .Invoke(obj, args); +#else obj.GetType().InvokeMember(origCtorName, BindingFlags.InvokeMethod, null, obj, args); +#endif CLRObject self = null; IntPtr gs = Runtime.PyGILState_Ensure(); diff --git a/src/runtime/classmanager.cs b/src/runtime/classmanager.cs index 6a9d40ebd..58e4037dd 100644 --- a/src/runtime/classmanager.cs +++ b/src/runtime/classmanager.cs @@ -1,9 +1,10 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using System.Security; +using ReflectionBridge.Extensions; namespace Python.Runtime { @@ -73,7 +74,11 @@ private static ClassBase CreateClass(Type type) // lets us check once (vs. on every lookup) in case we need to // wrap Exception-derived types in old-style classes +#if NETSTANDARD1_5 + if (type.GetTypeInfo().ContainsGenericParameters) +#else if (type.ContainsGenericParameters) +#endif { impl = new GenericType(type); } @@ -88,7 +93,7 @@ private static ClassBase CreateClass(Type type) impl = new ArrayObject(type); } - else if (type.IsInterface) + else if (type.IsInterface()) { impl = new InterfaceObject(type); } @@ -236,7 +241,7 @@ private static ClassInfo GetClassInfo(Type type) } } - if (type.IsInterface) + if (type.IsInterface()) { // Interface inheritance seems to be a different animal: // more contractual, less structural. Thus, a Type that @@ -358,12 +363,21 @@ private static ClassInfo GetClassInfo(Type type) continue; case MemberTypes.NestedType: +#if NETSTANDARD1_5 + tp = ((TypeInfo) mi).AsType(); + if (!(tp.IsNestedPublic() || tp.GetTypeInfo().IsNestedFamily || + tp.GetTypeInfo().IsNestedFamORAssem)) + { + continue; + } +#else tp = (Type)mi; if (!(tp.IsNestedPublic || tp.IsNestedFamily || tp.IsNestedFamORAssem)) { continue; } +#endif // Note the given instance might be uninitialized ob = GetClass(tp); ci.members[mi.Name] = ob; diff --git a/src/runtime/classobject.cs b/src/runtime/classobject.cs index 46257c73f..a0d383cde 100644 --- a/src/runtime/classobject.cs +++ b/src/runtime/classobject.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Reflection; +using ReflectionBridge.Extensions; namespace Python.Runtime { @@ -65,7 +66,7 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) // Primitive types do not have constructors, but they look like // they do from Python. If the ClassObject represents one of the // convertible primitive types, just convert the arg directly. - if (type.IsPrimitive || type == typeof(string)) + if (type.IsPrimitive() || type == typeof(string)) { if (Runtime.PyTuple_Size(args) != 1) { @@ -84,13 +85,13 @@ public static IntPtr tp_new(IntPtr tp, IntPtr args, IntPtr kw) return CLRObject.GetInstHandle(result, tp); } - if (type.IsAbstract) + if (type.IsAbstract()) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate abstract class"); return IntPtr.Zero; } - if (type.IsEnum) + if (type.IsEnum()) { Exceptions.SetError(Exceptions.TypeError, "cannot instantiate enumeration"); return IntPtr.Zero; diff --git a/src/runtime/codegenerator.cs b/src/runtime/codegenerator.cs index dc466bafb..b0f5784ce 100644 --- a/src/runtime/codegenerator.cs +++ b/src/runtime/codegenerator.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; using System.Reflection.Emit; using System.Threading; @@ -21,7 +21,11 @@ internal CodeGenerator() var aname = new AssemblyName { Name = "__CodeGenerator_Assembly" }; var aa = AssemblyBuilderAccess.Run; +#if NETSTANDARD1_5 + aBuilder = AssemblyBuilder.DefineDynamicAssembly(aname, aa); +#else aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa); +#endif mBuilder = aBuilder.DefineDynamicModule("__CodeGenerator_Module"); } diff --git a/src/runtime/constructorbinder.cs b/src/runtime/constructorbinder.cs index 1fc541920..59b849950 100644 --- a/src/runtime/constructorbinder.cs +++ b/src/runtime/constructorbinder.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Reflection; +using ReflectionBridge.Extensions; namespace Python.Runtime { @@ -51,8 +52,8 @@ internal object InvokeRaw(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info) { object result; - if (_containingType.IsValueType && !_containingType.IsPrimitive && - !_containingType.IsEnum && _containingType != typeof(decimal) && + if (_containingType.IsValueType() && !_containingType.IsPrimitive() && + !_containingType.IsEnum() && _containingType != typeof(decimal) && Runtime.PyTuple_Size(args) == 0) { // If you are trying to construct an instance of a struct by diff --git a/src/runtime/converter.cs b/src/runtime/converter.cs index 5179c849b..5b8fbbf92 100644 --- a/src/runtime/converter.cs +++ b/src/runtime/converter.cs @@ -1,17 +1,20 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Runtime.InteropServices; using System.Security; +using ReflectionBridge.Extensions; namespace Python.Runtime { /// /// Performs data conversions between managed types and Python types. /// +#if !NETSTANDARD1_5 [SuppressUnmanagedCodeSecurity] +#endif internal class Converter { private Converter() @@ -134,7 +137,7 @@ internal static IntPtr ToPython(object value, Type type) return result; } - if (value is IList && value.GetType().IsGenericType) + if (value is IList && value.GetType().IsGenericType()) { using (var resultlist = new PyList()) { @@ -312,7 +315,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return false; } - if (value == Runtime.PyNone && !obType.IsValueType) + if (value == Runtime.PyNone && !obType.IsValueType()) { result = null; return true; @@ -334,7 +337,7 @@ internal static bool ToManagedValue(IntPtr value, Type obType, return ToArray(value, obType, out result, setError); } - if (obType.IsEnum) + if (obType.IsEnum()) { return ToEnum(value, obType, out result, setError); } diff --git a/src/runtime/debughelper.cs b/src/runtime/debughelper.cs index 2a91a74b4..83bacc378 100644 --- a/src/runtime/debughelper.cs +++ b/src/runtime/debughelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using System.Reflection; using System.Runtime.InteropServices; @@ -105,8 +105,13 @@ internal static void DumpInst(IntPtr ob) [Conditional("DEBUG")] internal static void debug(string msg) { +#if NETSTANDARD1_5 + StackTrace st = new StackTrace(new Exception(msg), true); + StackFrame sf = st.GetFrames()[0]; +#else var st = new StackTrace(1, true); StackFrame sf = st.GetFrame(0); +#endif MethodBase mb = sf.GetMethod(); Type mt = mb.DeclaringType; string caller = mt.Name + "." + sf.GetMethod().Name; @@ -116,10 +121,10 @@ internal static void debug(string msg) Console.WriteLine(" {0}", msg); } - /// + /// /// Helper function to inspect/compare managed to native conversions. - /// Especially useful when debugging CustomMarshaler. - /// + /// Especially useful when debugging CustomMarshaler. + /// /// [Conditional("DEBUG")] public static void PrintHexBytes(byte[] bytes) diff --git a/src/runtime/delegatemanager.cs b/src/runtime/delegatemanager.cs index df5eec427..2d3c142fd 100644 --- a/src/runtime/delegatemanager.cs +++ b/src/runtime/delegatemanager.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; +using ReflectionBridge.Extensions; namespace Python.Runtime { @@ -118,7 +119,7 @@ private Type GetDispatcher(Type dtype) il.Emit(OpCodes.Ldloc_0); il.Emit(OpCodes.Ldarg_S, (byte)(c + 1)); - if (t.IsValueType) + if (t.IsValueType()) { il.Emit(OpCodes.Box, t); } @@ -135,14 +136,18 @@ private Type GetDispatcher(Type dtype) { il.Emit(OpCodes.Pop); } - else if (method.ReturnType.IsValueType) + else if (method.ReturnType.IsValueType()) { il.Emit(OpCodes.Unbox_Any, method.ReturnType); } il.Emit(OpCodes.Ret); +#if NETSTANDARD1_5 + Type disp = tb.CreateTypeInfo().AsType(); +#else Type disp = tb.CreateType(); +#endif cache[dtype] = disp; return disp; } @@ -157,7 +162,11 @@ internal Delegate GetDelegate(Type dtype, IntPtr callable) Type dispatcher = GetDispatcher(dtype); object[] args = { callable, dtype }; object o = Activator.CreateInstance(dispatcher, args); +#if NETSTANDARD1_5 + return DelegateShim.CreateDelegate(dtype, o, "Invoke"); +#else return Delegate.CreateDelegate(dtype, o, "Invoke"); +#endif } } diff --git a/src/runtime/delegateobject.cs b/src/runtime/delegateobject.cs index e1103cbc7..608aed25c 100644 --- a/src/runtime/delegateobject.cs +++ b/src/runtime/delegateobject.cs @@ -1,5 +1,7 @@ -using System; - +using System; +#if NETSTANDARD1_5 +using System.Reflection; +#endif namespace Python.Runtime { /// diff --git a/src/runtime/eventobject.cs b/src/runtime/eventobject.cs index 5f18c4609..033cc82b3 100644 --- a/src/runtime/eventobject.cs +++ b/src/runtime/eventobject.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Reflection; @@ -47,7 +47,11 @@ internal bool AddEventHandler(IntPtr target, IntPtr handler) { reg = new Hashtable(); } +#if NETSTANDARD1_5 + object key = obj ?? info.DeclaringType; +#else object key = obj ?? info.ReflectedType; +#endif var list = reg[key] as ArrayList; if (list == null) { @@ -60,7 +64,11 @@ internal bool AddEventHandler(IntPtr target, IntPtr handler) // so we have to get the underlying add method explicitly. object[] args = { d }; MethodInfo mi = info.GetAddMethod(true); +#if NETSTANDARD1_5 + mi.Invoke(obj, args); +#else mi.Invoke(obj, BindingFlags.Default, null, args, null); +#endif return true; } @@ -85,7 +93,11 @@ internal bool RemoveEventHandler(IntPtr target, IntPtr handler) return false; } +#if NETSTANDARD1_5 + object key = obj ?? info.DeclaringType; +#else object key = obj ?? info.ReflectedType; +#endif var list = reg[key] as ArrayList; if (list == null) @@ -107,7 +119,11 @@ internal bool RemoveEventHandler(IntPtr target, IntPtr handler) args[0] = item.del; try { +#if NETSTANDARD1_5 + mi.Invoke(obj, args); +#else mi.Invoke(obj, BindingFlags.Default, null, args, null); +#endif } catch { diff --git a/src/runtime/genericutil.cs b/src/runtime/genericutil.cs index 9772d082f..510da0287 100644 --- a/src/runtime/genericutil.cs +++ b/src/runtime/genericutil.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Collections.Generic; +using ReflectionBridge.Extensions; namespace Python.Runtime { diff --git a/src/runtime/importhook.cs b/src/runtime/importhook.cs index bc9ac5eee..291b0ad4c 100644 --- a/src/runtime/importhook.cs +++ b/src/runtime/importhook.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Runtime.InteropServices; namespace Python.Runtime @@ -75,7 +75,10 @@ internal static void Shutdown() if (Runtime.Py_IsInitialized() != 0) { Runtime.XDecref(py_clr_module); + // TODO: Very strange behavior under CoreCLR. System.ExecutionEngineException (Crash) +#if !NETSTANDARD1_5 Runtime.XDecref(root.pyHandle); +#endif Runtime.XDecref(py_import); } } diff --git a/src/runtime/interfaceobject.cs b/src/runtime/interfaceobject.cs index ce1bc9eb0..374ce0cc2 100644 --- a/src/runtime/interfaceobject.cs +++ b/src/runtime/interfaceobject.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; using System.Runtime.InteropServices; @@ -16,7 +16,12 @@ internal class InterfaceObject : ClassBase internal InterfaceObject(Type tp) : base(tp) { +#if NETSTANDARD1_5 + CoClassAttribute coclass = (CoClassAttribute) + tp.GetTypeInfo().GetCustomAttribute(cc_attr); +#else var coclass = (CoClassAttribute)Attribute.GetCustomAttribute(tp, cc_attr); +#endif if (coclass != null) { ctor = coclass.CoClass.GetConstructor(Type.EmptyTypes); diff --git a/src/runtime/interop.cs b/src/runtime/interop.cs index 4ae4b61e0..afc9d018a 100644 --- a/src/runtime/interop.cs +++ b/src/runtime/interop.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Specialized; using System.Runtime.InteropServices; @@ -342,7 +342,11 @@ static Interop() // Here we build a mapping of PyTypeObject slot names to the // appropriate prototype (delegate) type to use for the slot. +#if NETSTANDARD1_5 + Type[] items = typeof(Interop).GetTypeInfo().GetNestedTypes(); +#else Type[] items = typeof(Interop).GetNestedTypes(); +#endif Hashtable p = new Hashtable(); for (int i = 0; i < items.Length; i++) @@ -453,14 +457,22 @@ internal static IntPtr GetThunk(MethodInfo method, string funcType = null) { Type dt; if (funcType != null) +#if NETSTANDARD1_5 + dt = typeof(Interop).GetTypeInfo().GetNestedType(funcType) as Type; +#else dt = typeof(Interop).GetNestedType(funcType) as Type; +#endif else dt = GetPrototype(method.Name); if (dt != null) { IntPtr tmp = Marshal.AllocHGlobal(IntPtr.Size); +#if NETSTANDARD1_5 + Delegate d = DelegateShim.CreateDelegate(dt, method); +#else Delegate d = Delegate.CreateDelegate(dt, method); +#endif Thunk cb = new Thunk(d); Marshal.StructureToPtr(cb, tmp, false); IntPtr fp = Marshal.ReadIntPtr(tmp, 0); diff --git a/src/runtime/metatype.cs b/src/runtime/metatype.cs index 982f4a632..504a5720b 100644 --- a/src/runtime/metatype.cs +++ b/src/runtime/metatype.cs @@ -1,4 +1,7 @@ using System; +#if NETSTANDARD1_5 +using System.Reflection; +#endif using System.Runtime.InteropServices; namespace Python.Runtime diff --git a/src/runtime/methodbinder.cs b/src/runtime/methodbinder.cs index f0c58f34f..fd6fec98b 100644 --- a/src/runtime/methodbinder.cs +++ b/src/runtime/methodbinder.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Reflection; @@ -327,7 +327,11 @@ internal Binding Bind(IntPtr inst, IntPtr args, IntPtr kw, MethodBase info, Meth } } else if (pynargs > clrnargs && clrnargs > 0 && - Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute))) +#if NETSTANDARD1_5 + pi[clrnargs - 1].IsDefined(typeof(ParamArrayAttribute))) +#else + Attribute.IsDefined(pi[clrnargs - 1], typeof(ParamArrayAttribute))) +#endif { // This is a `foo(params object[] bar)` style method match = true; @@ -518,7 +522,11 @@ internal virtual IntPtr Invoke(IntPtr inst, IntPtr args, IntPtr kw, MethodBase i try { +#if NETSTANDARD1_5 + result = binding.info.Invoke(binding.inst, binding.args); +#else result = binding.info.Invoke(binding.inst, BindingFlags.Default, null, binding.args, null); +#endif } catch (Exception e) { diff --git a/src/runtime/methodwrapper.cs b/src/runtime/methodwrapper.cs index 2f3ce3ef2..e41c25cd1 100644 --- a/src/runtime/methodwrapper.cs +++ b/src/runtime/methodwrapper.cs @@ -1,4 +1,7 @@ -using System; +using System; +#if NETSTANDARD1_5 +using System.Reflection; +#endif namespace Python.Runtime { diff --git a/src/runtime/moduleobject.cs b/src/runtime/moduleobject.cs index e683026f9..9aeed54a6 100644 --- a/src/runtime/moduleobject.cs +++ b/src/runtime/moduleobject.cs @@ -1,8 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using ReflectionBridge.Extensions; namespace Python.Runtime { @@ -108,7 +110,7 @@ public ManagedType GetAttribute(string name, bool guess) type = AssemblyManager.LookupType(qname); if (type != null) { - if (!type.IsPublic) + if (!type.IsPublic()) { return null; } @@ -134,7 +136,7 @@ public ManagedType GetAttribute(string name, bool guess) type = AssemblyManager.LookupType(qname); if (type != null) { - if (!type.IsPublic) + if (!type.IsPublic()) { return null; } @@ -214,8 +216,8 @@ internal void InitializeModuleMembers() MethodInfo[] methods = type.GetMethods(flags); foreach (MethodInfo method in methods) { - object[] attrs = method.GetCustomAttributes(funcmarker, false); - object[] forbid = method.GetCustomAttributes(ftmarker, false); + object[] attrs = method.GetCustomAttributes(funcmarker, false).ToArray(); + object[] forbid = method.GetCustomAttributes(ftmarker, false).ToArray(); bool allow_threads = forbid.Length == 0; if (attrs.Length > 0) { @@ -230,7 +232,7 @@ internal void InitializeModuleMembers() PropertyInfo[] properties = type.GetProperties(); foreach (PropertyInfo property in properties) { - object[] attrs = property.GetCustomAttributes(propmarker, false); + object[] attrs = property.GetCustomAttributes(propmarker, false).ToArray(); if (attrs.Length > 0) { string name = property.Name; @@ -238,7 +240,7 @@ internal void InitializeModuleMembers() StoreAttribute(name, p); } } - type = type.BaseType; + type = type.BaseType(); } } diff --git a/src/runtime/nativecall.cs b/src/runtime/nativecall.cs index 9d1b0f41c..9cd428179 100644 --- a/src/runtime/nativecall.cs +++ b/src/runtime/nativecall.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; using System.Reflection.Emit; using System.Runtime.InteropServices; @@ -39,8 +39,11 @@ static NativeCall() var aname = new AssemblyName { Name = "e__NativeCall_Assembly" }; var aa = AssemblyBuilderAccess.Run; - +#if NETSTANDARD1_5 + aBuilder = AssemblyBuilder.DefineDynamicAssembly(aname, aa); +#else aBuilder = Thread.GetDomain().DefineDynamicAssembly(aname, aa); +#endif mBuilder = aBuilder.DefineDynamicModule("e__NativeCall_Module"); var ta = TypeAttributes.Public; @@ -57,7 +60,11 @@ static NativeCall() GenerateThunk(tBuilder, method); } +#if NETSTANDARD1_5 + Type theType = tBuilder.CreateTypeInfo().AsType(); +#else Type theType = tBuilder.CreateType(); +#endif Impl = (INativeCall)Activator.CreateInstance(theType); } @@ -106,12 +113,19 @@ private static void GenerateThunk(TypeBuilder tb, MethodInfo method) il.Emit(OpCodes.Ldarg_1); +#if NETSTANDARD1_5 + il.EmitCalli(OpCodes.Calli, + CallingConventions.ExplicitThis, + method.ReturnType, + nargs, null + ); +#else il.EmitCalli(OpCodes.Calli, CallingConvention.Cdecl, method.ReturnType, nargs ); - +#endif il.Emit(OpCodes.Ret); tb.DefineMethodOverride(mb, method); diff --git a/src/runtime/polyfill/DelegateShim.cs b/src/runtime/polyfill/DelegateShim.cs new file mode 100644 index 000000000..0fcbcbd52 --- /dev/null +++ b/src/runtime/polyfill/DelegateShim.cs @@ -0,0 +1,32 @@ +#if NETSTANDARD1_5 +namespace Python.Runtime +{ + using System; + using System.Linq; + using System.Reflection; + + public static class DelegateShim + { + public static Delegate CreateDelegate(Type dtype, object obj, string methodName) + { + if (obj == null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var methods = obj.GetType().GetTypeInfo().GetMember(methodName, BindingFlags.Default); + if (!methods.Any()) + { + throw new InvalidOperationException("Method does not exist"); + } + + return CreateDelegate(dtype, (MethodInfo)methods[0]); + } + + internal static Delegate CreateDelegate(Type dtype, MethodInfo method) + { + return method.CreateDelegate(dtype); + } + } +} +#endif \ No newline at end of file diff --git a/src/runtime/polyfill/ICustomMarshaler.cs b/src/runtime/polyfill/ICustomMarshaler.cs new file mode 100644 index 000000000..0b295a6de --- /dev/null +++ b/src/runtime/polyfill/ICustomMarshaler.cs @@ -0,0 +1,34 @@ +// This is copy from https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Runtime/InteropServices/ICustomMarshaler.cs + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================================= +** +** +** +** Purpose: This the base interface that must be implemented by all custom +** marshalers. +** +** +=============================================================================*/ + +#if NETSTANDARD1_5 +using System; +namespace System.Runtime.InteropServices +{ + public interface ICustomMarshaler + { + Object MarshalNativeToManaged(IntPtr pNativeData); + + IntPtr MarshalManagedToNative(Object ManagedObj); + + void CleanUpNativeData(IntPtr pNativeData); + + void CleanUpManagedData(Object ManagedObj); + + int GetNativeDataSize(); + } +} +#endif \ No newline at end of file diff --git a/src/runtime/polyfill/ReflectionBridge/LICENSE.txt b/src/runtime/polyfill/ReflectionBridge/LICENSE.txt new file mode 100644 index 000000000..9bb94287b --- /dev/null +++ b/src/runtime/polyfill/ReflectionBridge/LICENSE.txt @@ -0,0 +1,22 @@ + +MIT License + +Copyright (c) 2016 to 2099 Stef Heyenrath + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/runtime/polyfill/ReflectionBridge/ReflectionBridgeExtensions.cs b/src/runtime/polyfill/ReflectionBridge/ReflectionBridgeExtensions.cs new file mode 100644 index 000000000..c421408ac --- /dev/null +++ b/src/runtime/polyfill/ReflectionBridge/ReflectionBridgeExtensions.cs @@ -0,0 +1,231 @@ +using System; +using System.Reflection; + +#if REFLECTIONBRIDGE +using System.Collections.Generic; +using System.Linq; +#endif + +namespace ReflectionBridge.Extensions +{ + public static class ReflectionBridgeExtensions + { + public static Assembly GetAssembly(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().Assembly; +#else + return type.Assembly; +#endif + } + + public static bool IsSealed(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsSealed; +#else + return type.IsSealed; +#endif + } + + public static bool IsAbstract(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsAbstract; +#else + return type.IsAbstract; +#endif + } + + public static bool IsEnum(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsEnum; +#else + return type.IsEnum; +#endif + } + + public static bool IsClass(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsClass; +#else + return type.IsClass; +#endif + } + + public static bool IsPrimitive(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsPrimitive; +#else + return type.IsPrimitive; +#endif + } + + public static bool IsPublic(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsPublic; +#else + return type.IsPublic; +#endif + } + + public static bool IsNestedPublic(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsNestedPublic; +#else + return type.IsNestedPublic; +#endif + } + + public static bool IsFromLocalAssembly(this Type type) + { +#if SILVERLIGHT + string assemblyName = type.GetAssembly().FullName; +#else + string assemblyName = type.GetAssembly().GetName().Name; +#endif + + try + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + Assembly.Load(new AssemblyName { Name = assemblyName }); +#else + Assembly.Load(assemblyName); +#endif + return true; + } + catch + { + return false; + } + } + + public static bool IsGenericType(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsGenericType; +#else + return type.IsGenericType; +#endif + } + + public static bool IsInterface(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsInterface; +#else + return type.IsInterface; +#endif + } + + public static Type BaseType(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().BaseType; +#else + return type.BaseType; +#endif + } + + public static bool IsValueType(this Type type) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + return type.GetTypeInfo().IsValueType; +#else + return type.IsValueType; +#endif + } + + public static T GetPropertyValue(this Type type, string propertyName, object target) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + PropertyInfo property = type.GetTypeInfo().GetDeclaredProperty(propertyName); + return (T)property.GetValue(target); +#else + return (T)type.InvokeMember(propertyName, BindingFlags.GetProperty, null, target, null); +#endif + } + + public static void SetPropertyValue(this Type type, string propertyName, object target, object value) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + PropertyInfo property = type.GetTypeInfo().GetDeclaredProperty(propertyName); + property.SetValue(target, value); +#else + type.InvokeMember(propertyName, BindingFlags.SetProperty, null, target, new object[] { value }); +#endif + } + + public static void SetFieldValue(this Type type, string fieldName, object target, object value) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + FieldInfo field = type.GetTypeInfo().GetDeclaredField(fieldName); + if (field != null) + { + field.SetValue(target, value); + } + else + { + type.SetPropertyValue(fieldName, target, value); + } +#else + type.InvokeMember(fieldName, BindingFlags.SetField | BindingFlags.SetProperty, null, target, new object[] { value }); +#endif + } + + public static void InvokeMethod(this Type type, string methodName, object target, T value) + { +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + MethodInfo method = type.GetTypeInfo().GetDeclaredMethod(methodName); + method.Invoke(target, new object[] { value }); +#else + type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, target, new object[] { value }); +#endif + } + +#if REFLECTIONBRIDGE && (!(NET40 || NET35 || NET20 || SILVERLIGHT)) + public static IEnumerable GetMethods(this Type someType) + { + var t = someType; + while (t != null) + { + var ti = t.GetTypeInfo(); + foreach (var m in ti.DeclaredMethods) + yield return m; + t = ti.BaseType; + } + } + + public static Type[] GetGenericArguments(this Type type) + { + return type.GetTypeInfo().GenericTypeArguments; + } + + /* + public static bool IsAssignableFrom(this Type type, Type otherType) + { + return type.GetTypeInfo().IsAssignableFrom(otherType.GetTypeInfo()); + }*/ + + public static bool IsSubclassOf(this Type type, Type c) + { + return type.GetTypeInfo().IsSubclassOf(c); + } + + public static Attribute[] GetCustomAttributes(this Type type) + { + return type.GetTypeInfo().GetCustomAttributes().ToArray(); + } + + public static Attribute[] GetCustomAttributes(this Type type, Type attributeType, bool inherit) + { + return type.GetTypeInfo().GetCustomAttributes(attributeType, inherit).Cast().ToArray(); + } +#endif + } +} \ No newline at end of file diff --git a/src/runtime/propertyobject.cs b/src/runtime/propertyobject.cs index f2c97f163..5c76964a7 100644 --- a/src/runtime/propertyobject.cs +++ b/src/runtime/propertyobject.cs @@ -1,7 +1,8 @@ -using System; +using System; using System.Reflection; +#if !NETSTANDARD1_5 using System.Security.Permissions; - +#endif namespace Python.Runtime { /// @@ -12,8 +13,9 @@ internal class PropertyObject : ExtensionType private PropertyInfo info; private MethodInfo getter; private MethodInfo setter; - +#if !NETSTANDARD1_5 [StrongNameIdentityPermission(SecurityAction.Assert)] +#endif public PropertyObject(PropertyInfo md) { getter = md.GetGetMethod(true); diff --git a/src/runtime/pythonengine.cs b/src/runtime/pythonengine.cs index 556da698f..a6caf0c93 100644 --- a/src/runtime/pythonengine.cs +++ b/src/runtime/pythonengine.cs @@ -193,8 +193,16 @@ public static void Initialize(IEnumerable args, bool setSysArgv = true) IntPtr builtins = Runtime.PyEval_GetBuiltins(); Runtime.PyDict_SetItemString(module_globals, "__builtins__", builtins); +#if NETSTANDARD1_5 + Assembly assembly = typeof(Runtime).GetTypeInfo().Assembly; +#else Assembly assembly = Assembly.GetExecutingAssembly(); +#endif +#if XPLAT + using (Stream stream = assembly.GetManifestResourceStream("Python.Runtime.resources.clr.py")) +#else using (Stream stream = assembly.GetManifestResourceStream("clr.py")) +#endif using (var reader = new StreamReader(stream)) { // add the contents of clr.py to the module diff --git a/src/runtime/runtime.cs b/src/runtime/runtime.cs index 8f730a855..b471fa2c1 100644 --- a/src/runtime/runtime.cs +++ b/src/runtime/runtime.cs @@ -2,10 +2,13 @@ using System.Runtime.InteropServices; using System.Security; using System.Text; +using ReflectionBridge.Extensions; namespace Python.Runtime { +#if !NETSTANDARD1_5 [SuppressUnmanagedCodeSecurity] +#endif internal static class NativeMethods { #if MONO_LINUX || MONO_OSX @@ -21,7 +24,11 @@ internal static class NativeMethods public static IntPtr LoadLibrary(string fileName) { +#if NETSTANDARD1_5 + return dlopen(fileName, RTLD_NOW); +#else return dlopen(fileName, RTLD_NOW | RTLD_SHARED); +#endif } public static void FreeLibrary(IntPtr handle) @@ -300,9 +307,13 @@ internal static void Initialize() IntPtr dllLocal = IntPtr.Zero; if (_PythonDll != "__Internal") { +#if !NETSTANDARD1_5 dllLocal = NativeMethods.LoadLibrary(_PythonDll); +#endif } +#if !NETSTANDARD1_5 _PyObject_NextNotImplemented = NativeMethods.GetProcAddress(dllLocal, "_PyObject_NextNotImplemented"); +#endif #if !(MONO_LINUX || MONO_OSX) if (dllLocal != IntPtr.Zero) { @@ -318,7 +329,11 @@ internal static void Initialize() // Need to add the runtime directory to sys.path so that we // can find built-in assemblies like System.Data, et. al. +#if NETSTANDARD1_5 + string rtdir = typeof(string).GetAssembly().Location; +#else string rtdir = RuntimeEnvironment.GetRuntimeDirectory(); +#endif IntPtr path = PySys_GetObject("path"); IntPtr item = PyString_FromString(rtdir); PyList_Append(path, item); @@ -623,11 +638,35 @@ internal static unsafe long Refcount(IntPtr op) internal static extern IntPtr PyGILState_GetThisThreadState(); #if PYTHON3 +#if NETSTANDARD1_5 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + private static extern int Py_Main( + int argc, + IntPtr argv + ); + + public static int Py_Main( + int argc, + string[] argv + ) + { + var marshaler = StrArrayMarshaler.GetInstance(string.Empty); + var unmanagedDataPtr = marshaler.MarshalManagedToNative(argv); + + int result = Py_Main(argc, unmanagedDataPtr); + if (unmanagedDataPtr != IntPtr.Zero) + { + marshaler.CleanUpNativeData(unmanagedDataPtr); + } + return result; + } +#else [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] public static extern int Py_Main( int argc, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv ); +#endif #elif PYTHON2 [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] public static extern int Py_Main(int argc, string[] argv); @@ -1183,12 +1222,38 @@ internal static IntPtr PyBytes_AS_STRING(IntPtr ob) return ob + BytesOffset.ob_sval; } +#if NETSTANDARD1_5 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, + EntryPoint = "PyUnicode_FromStringAndSize")] + private static extern IntPtr PyString_FromStringAndSize( + IntPtr value, + int size + ); + + internal static IntPtr PyString_FromStringAndSize( + string value, + int size + ) + { + var marshaler = Utf8Marshaler.GetInstance(string.Empty); + var unmanagedDataPtr = marshaler.MarshalManagedToNative(value); + + IntPtr result = PyString_FromStringAndSize(unmanagedDataPtr, size); + + if (unmanagedDataPtr != IntPtr.Zero) + { + marshaler.CleanUpNativeData(unmanagedDataPtr); + } + return result; + } +#else [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = "PyUnicode_FromStringAndSize")] internal static extern IntPtr PyString_FromStringAndSize( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string value, int size ); +#endif [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr PyUnicode_FromStringAndSize(IntPtr value, int size); @@ -1215,12 +1280,40 @@ internal static bool PyUnicode_Check(IntPtr ob) [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); +#if NETSTANDARD1_5 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr PyUnicode_FromKindAndData( + int kind, + IntPtr s, + int size + ); + + internal static IntPtr PyUnicode_FromKindAndData( + int kind, + string s, + int size + ) + { + var marshaler = UcsMarshaler.GetInstance(string.Empty); + var unmanagedDataPtr = marshaler.MarshalManagedToNative(s); + + IntPtr result = PyUnicode_FromKindAndData(kind, unmanagedDataPtr, size); + + if (unmanagedDataPtr != IntPtr.Zero) + { + marshaler.CleanUpNativeData(unmanagedDataPtr); + } + + return result; + } +#else [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern IntPtr PyUnicode_FromKindAndData( int kind, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s, int size ); +#endif internal static IntPtr PyUnicode_FromUnicode(string s, int size) { @@ -1244,12 +1337,38 @@ internal static IntPtr PyUnicode_FromUnicode(string s, int size) EntryPoint = PyUnicodeEntryPoint + "FromEncodedObject")] internal static extern IntPtr PyUnicode_FromEncodedObject(IntPtr ob, IntPtr enc, IntPtr err); +#if NETSTANDARD1_5 + [DllImport(_PythonDll, EntryPoint = PyUnicodeEntryPoint + "FromUnicode", + CallingConvention = CallingConvention.Cdecl)] + private static extern IntPtr PyUnicode_FromUnicode( + IntPtr s, + int size + ); + + internal static IntPtr PyUnicode_FromUnicode( + string s, + int size + ) + { + var marshaler = UcsMarshaler.GetInstance(string.Empty); + var unmanagedDataPtr = marshaler.MarshalManagedToNative(s); + + IntPtr result = PyUnicode_FromUnicode(unmanagedDataPtr, size); + if (unmanagedDataPtr != IntPtr.Zero) + { + marshaler.CleanUpNativeData(unmanagedDataPtr); + } + + return result; + } +#else [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = PyUnicodeEntryPoint + "FromUnicode")] internal static extern IntPtr PyUnicode_FromUnicode( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UcsMarshaler))] string s, int size ); +#endif [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl, EntryPoint = PyUnicodeEntryPoint + "GetSize")] @@ -1438,6 +1557,10 @@ internal static bool PyTuple_Check(IntPtr ob) // Python iterator API //==================================================================== +#if PYTHON2 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + internal static extern bool PyIter_Check(IntPtr pointer); +#elif PYTHON3 internal static bool PyIter_Check(IntPtr pointer) { var ob_type = Marshal.ReadIntPtr(pointer, ObjectOffset.ob_type); @@ -1491,12 +1614,37 @@ internal static bool PyIter_Check(IntPtr pointer) internal static extern IntPtr PyImport_GetModuleDict(); #if PYTHON3 +#if NETSTANDARD1_5 + [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] + private static extern void PySys_SetArgvEx( + int argc, + IntPtr argv, + int updatepath + ); + + internal static void PySys_SetArgvEx( + int argc, + string[] argv, + int updatepath + ) + { + var marshaler = StrArrayMarshaler.GetInstance(string.Empty); + var unmanagedDataPtr = marshaler.MarshalManagedToNative(argv); + + PySys_SetArgvEx(argc, unmanagedDataPtr, updatepath); + if (unmanagedDataPtr != IntPtr.Zero) + { + marshaler.CleanUpNativeData(unmanagedDataPtr); + } + } +#else [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern void PySys_SetArgvEx( int argc, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StrArrayMarshaler))] string[] argv, int updatepath ); +#endif #elif PYTHON2 [DllImport(_PythonDll, CallingConvention = CallingConvention.Cdecl)] internal static extern void PySys_SetArgvEx( diff --git a/src/runtime/typemanager.cs b/src/runtime/typemanager.cs index 6570ee083..64d4419b8 100644 --- a/src/runtime/typemanager.cs +++ b/src/runtime/typemanager.cs @@ -1,8 +1,10 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using ReflectionBridge.Extensions; namespace Python.Runtime { @@ -132,9 +134,9 @@ internal static IntPtr CreateType(ManagedType impl, Type clrType) { base_ = Exceptions.Exception; } - else if (clrType.BaseType != null) + else if (clrType.BaseType() != null) { - ClassBase bc = ClassManager.GetClass(clrType.BaseType); + ClassBase bc = ClassManager.GetClass(clrType.BaseType()); base_ = bc.pyHandle; } @@ -487,7 +489,7 @@ internal static void InitializeSlots(IntPtr type, Type impl) seen[name] = 1; } - impl = impl.BaseType; + impl = impl.BaseType(); } } @@ -512,7 +514,7 @@ private static void InitMethods(IntPtr pytype, Type type) { if (!addedMethods.Contains(method.Name)) { - object[] attrs = method.GetCustomAttributes(marker, false); + object[] attrs = method.GetCustomAttributes(marker, false).ToArray(); if (attrs.Length > 0) { string method_name = method.Name; @@ -524,7 +526,7 @@ private static void InitMethods(IntPtr pytype, Type type) } } } - type = type.BaseType; + type = type.BaseType(); } } diff --git a/src/runtime/typemethod.cs b/src/runtime/typemethod.cs index 4da92613c..757945d7f 100644 --- a/src/runtime/typemethod.cs +++ b/src/runtime/typemethod.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection; namespace Python.Runtime @@ -33,7 +33,11 @@ public override IntPtr Invoke(IntPtr ob, IntPtr args, IntPtr kw) { inst = GetManagedObject(ob); } +#if NETSTANDARD1_5 + return (IntPtr)mi.Invoke(inst, arglist); +#else return (IntPtr)mi.Invoke(inst, BindingFlags.Default, null, arglist, null); +#endif } catch (Exception e) {