BRL.Reflection: Pointer support
BlitzMax Forums/BlitzMax Module Tweaks/BRL.Reflection: Pointer support
| ||
snip |
| ||
UPDATED: September 3 2016 - version 1.28 !!! Contains a potentially breaking change to how function return types are handled. !!! !!! Specificly TMethod and TFunction requires calling TypeId().ReturnType() instead of just TypeId() !!! !!! Or one can call TMethod.ReturnType() and TFunction.ReturnType() directly !!! !! Only mainline module that uses this is BRL.MaxLUA, so line 77 in maxlua.bmx would need to me modified to use this modified reflection !! If this change is unacceptable, see post #82 for a copy of reflection.bmx with original semantics. (untested) !! Win32 and Linux targets use assembly for more arguments (30), MacOS still uses old way (8). see history in source below for more info. Download precompiled: brl.reflection.mod_grb_v1.28.7z Or use the sources below... mod/brl.mod/reflection.mod/reflection.bmx mod/brl.mod/reflection.mod/reflection.cpp mod/brl.mod/reflection.mod/callmethod.win32.x86.s mod/brl.mod/reflection.mod/callmethod.linux.x86.s mod/brl.mod/reflection.mod/callmethod.macos.x86.s |
| ||
snip |
| ||
Would it be possible to create something like EnumFunctions() for functions which don't belong to a type? I can create a TFunction manually for a function I already know about, proving that functions work the same wherever they are: Function a(s$) Print s End Function f:tfunction=New tfunction.init("a",IntTypeId.functiontype([StringTypeId]),"",IntTypeId,a) f.invoke(["hi"]) but I don't know enough about how the debugger works internally to be able to find arbitrary functions. How I imagine it working is something like: f:TFunction = TFunction.ForFunction(a) |
| ||
It is possible. But only in Debug mode, as no meta-data is stored for functions in Release mode :/ The meta-data is related to the Debug Scope, so its in its own table. Decoding it shouldnt pose a problem though, its getting access to it. Any ideas? |
| ||
This code doesn't seem to work any more. When I call TTypeID.ForName("class name") for any class, I usually get an EXCEPTION_ACCESS_VIOLATION, and the debugger points to line 1139:_functions.AddLast New TFunction.Init(id, tt, meta, Self, Byte Ptr(Int Ptr(Self._class + p[3])[0]) ) Before finding this thread I'd been using the code I stuck together at the end of this http://www.blitzmax.com/Community/posts.php?topic=84420#956203 thread, which crashes in the same way on the equivalent line. I suppose some internal change to blitz broke it; can anyone spread any light on what changed or how to fix it? |
| ||
The original BRL.Reflection hasnt changed though, so im guessing the meta-data hasnt changed either. I just tried some tests with 1.39 and i cant get it to crash on any of my tests. Can you give me an example? Btw, you say it "usually" crashes. Does this mean it works some of the time? If so it might not be the reflection code, but some other memory related error. |
| ||
Another thing I just found out: You forgot to add _functions=New TList to the Method "Init" of TTypeID. Adding this prevents your program to crash sometimes, if you tried to look up an unexistent function, because ObjectTypeID does not have a list "_functions". So the (slightly) modified Method "Init" could look like this: Method Init:TTypeId( name$,size,class=0,supor:TTypeId=Null ) _name=name _size=size _class=class _super=supor _fields=New TList _methods=New TList _functions=New TList _nameMap.Insert _name.ToLower(),Self If class _classMap.Insert New TClass.SetClass( class ),Self Return Self End Method Just wanted to mention. :) EDIT: Corrected typing mistake... |
| ||
Just one thing I just noticed: The modification seems not to work with BMax version 1.42. If I have a Function inside a type and when I try to do _anything_ with reflection it crashes in the line spacerat already mentioned. Can anyone confirm this? Thanks in advance |
| ||
bump top post has been updated with new BRL.Reflection. |
| ||
bug fix update. new version 1.10, see top post. fixed a stupid bug in FindConstant and made ForName able to parse function types with spaces between elements. allso added a new convenience method TField.FieldPtr() for a direct pointer to the field of and instance. On a side note, I really wonder why globals within a type arent emitted like the rest of the elements.. even constants are emitted, just not exposed via the default reflection implementation. It would be handy to have type globals as well i think :) |
| ||
version 1.11: refixed method overrides, allso did the same for functions (sorting by name and removing duplicates) cant believe i missed this one for so long :p |
| ||
I wrote a little dependency injection module for blitzmax using reflection. It is working great with your modifications. You can find it on GitHub: here |
| ||
Hallo. Here's a list of issues I found whilst applying these changes for bmx-ng : * TypeTagForId() doesn't work properly for pointers. * _Push and _Assign can crash for Pointer/Function types if value is null. |
| ||
Thanks brucey, they fail in vanilla bmx too.. Some wrong assumptions on my part ;) Pointer types now use _elementType to properly store its base. And _Push/_Assign check for Null and sets 0 for pointers and NullFunctionError for function pointers. EDIT: Left some bad code in last update, fixed now. |
| ||
Any ideas why the "updated revisions" (>1.05 or so) do no longer work with LUA objects)? I expose objects to lua, so eg. a lua script could call "list.Count()". With the current revision, this is no longer possible (it is not exposed). When accessing an object my lua engine does something in the likes of: Local obj:Object = lua_unboxobject(getLuaState(), 1) Local typeId:TTypeId = TTypeId.ForObject(obj) Local ident:String = lua_tostring(getLuaState(), 2) print "ident: "+ident +" typeId: "+typeId.name() so for aboves example this outputs "ident: Count typeId: TList" - when running on an ancient version of the code (1.05 or so - at least it contains some of the changes you did, but I did not have pointer / functionpointers...). Ok so when I updated the code, it now outputs "ident: Count typeId: String". Of course invokation of "Count()" is then no longer possible (as it sees it as a property then). I assume it has to do with the changes done in the helper functions (ForTag etc.) and that it is coming from an external source (lua_unboxobject). lua_unboxobject() could be found in "maxlua.mod/lua_object.c". I also tried to replace some changed functions with other ones, but up to now without success. Edit: Samplecode: Strict Type TMyObject Field myList:TList = CreateList() Method GetList:TList() Local list:TList = CreateList() list.AddLast("1") Return list End Method End Type Global myObject:TMyObject = New TMyObject LuaRegisterObject(myobject,"myobject") Global source:string = "function Run()~n print(~qmylist:~q .. myobject.myList.Count() .. ~q GetList:~q .. myobject.GetList().Count())~nend~n" Global luaClass:TLuaClass = TLuaClass.Create(source) Local luaInstance:TLuaObject = TLuaObject.Create(luaClass, Null) luaInstance.Invoke("Run",Null) This returns "mylist:0 GetList:1" when using old reflection code (which could be found HERE). When using the extended reflection in it's current incarnation, it exits with an lua error: "[string "function Run()..."]:2: attempt to call field 'Count' (a nil value)". To check it on your own you will have to adjust either brl.mod/reflection.mod - or adjust brl.mod/maxlua.mod to use your custom reflectionXYZ.mod. Does someone have "inbetween" releases of the code, so I could check at which point of development it stopped working (for me) ? bye Ron |
| ||
It also fails when calling some "extended objects" Super.Init()-calls (which call their Super.Init() and so on) ... I got errors in "TagForType()" with some null-properties. Am not able to produce a small code snippet for now - but it seems to be something aside of the LUA connection. bye Ron |
| ||
Yeah, sorry about that. I made the TypeId of functions, methods and function pointers be the same (before, its TypeId was only its return type). Essentially allowing for Function TypeIds, this in turn now requires to call ReturnType() to get at the return type. There was a bug in my BRL.Reflection version too which didnt account for this when calling methods, added a fixed version above now. For MaxLUA and any other code that uses a TMethod or TFunction and calling TypeId() on it to deduce its return type now has to use TypeId().ReturnType() or TMethod.ReturnType() instead... I know its a breaking change :( On line 77 in bmxlua.bmx change: Select meth.TypeId()to Select meth.TypeId().ReturnType()or Select meth.ReturnType()And it should work again. EDIT: If this change really bothers some people or messes up a lot of code, let me know. I could change TMethod.TypeId() and TFunction.TypeId() to return ONLY the return type directly and add an aditional .FunctionType() and/or .MethodType() to get at the full type (even though this would brake from the convention of .TypeId() returning the full type of any member) |
| ||
Your new code - and some small adjustments, let my lua-connection does its duty again. Thanks. Regarding "ReturnType()" and inconsistency: I understand your thoughts on this. I think the reason for a "TypeID" returning the call-result's type is, something similar to "consistency". You do not need to know what special instance a "TMember"-extending object is, you just need to call memberOrExtendedMember.TypeID() to get the desired result. The "member.TypeId().ReturnType()" is indeed a worthy replacement - if you know the existence of ReturnType() :-). @functionType/methodType I do not know what is more important: "backwards compatibility" (keeping other modules unchanged) or consistency? I just searched mods/brl.mod for "TypeID(" and only maxlua.bmx seems to use it for now. What about "TypeID()" returning the member typeID (TFunction, TConstant...) and "ValueTypeID()" returning the typeID for whatever is returned (for functions this is the result type, for constants the TypeID(). Keeping it backwards compatible would lead to "MemberTypeID()" returning TConstant, TField, TFunction, .. and "TypeID()" returning the return value "type". Hmpf, somehow I cannot come up with something really helpful now, maybe others will come to help regarding that issue. bye Ron |
| ||
Edit: maybe you want to incorporate Brucey's fix regarding Null-Arrays: https://github.com/maxmods/brl.mod/commit/fbbdbc8d222d115a11d0f2eb7ebe5556c29347f4 Else I would wait some days and modify the maxmods-reflection.mod to reflect your current changes (and then adjust maxlua.mod if needed). bye Ron |
| ||
Thanks for letting me know about that one Derron :) Updated top post, and i changed it a little so one doesnt need mingw to recompile. |
| ||
Doesn't your adjustment (regarding Brucey's bbRefArrayNull) remove the possibility to check if the returned value is a NullArray? In Brucey's code the "bbRefArrayNull" is always the same (the pointer to a special object is returned ?) in yours there is a fresh object created everytime. Or did I miss something - what is the difference between your approach and Brucey's ? I just want to avoid that we miss something Brucey added by intention... bye Ron |
| ||
Needed to add this to reflection.cppBBArray * bbRefArrayNull() { return &bbEmptyArray; } and to reflection.bmx: in externs: Function bbRefArrayNull:Object() and replace If value Local c=typeId._class Local t=bbRefGetObjectClass( value ) While t And t<>c t=bbRefGetSuperClass( t ) Wend If Not t Throw "ERROR" EndIf bbRefAssignObject p,value with If value Local c=typeId._class Local t=bbRefGetObjectClass( value ) While t And t<>c t=bbRefGetSuperClass( t ) Wend If Not t Throw "ERROR" Else If typeId.Name().Endswith("]") Then value = bbRefArrayNull() EndIf EndIf bbRefAssignObject p,value (as done by Brucey). Without that change I get segfaults in a sample code of my framework. Function TypeTagForId$( id:TTypeId ) If id.ExtendsType( ArrayTypeId ) Return "[]"+TypeTagForId( id.ElementType() ) EndIf [...] Debugger says, "id" is null. The problem is a nulled array which I use. So instead of "field obj:myobjects[5]" I have "field obj:myobjects[]" ("uninitialized"). So this means your "extends(ArrayTypeId)" does not trigger in that case (dunno why) and the result is a null-access (segfault). bye Ron |
| ||
Some further questions: --- in _CallMethod you convert pointers from Byte Ptr, in _CallFunction from Int If retTypeId.ExtendsType(PointerTypeId) Or retTypeId.ExtendsType(FunctionTypeId) Then Local f:Byte Ptr(p0,p1,p2,p3,p4,p5,p6,p7)=p Return String.FromInt( Int f( q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7] ) ) '=== VS === If retTypeId.ExtendsType(PointerTypeId) Or retTypeId.ExtendsType(FunctionTypeId) Then Local f:Int(p0, p1, p2, p3, p4, p5, p6, p7) = funcp Return String.FromInt( f( q[0],q[1],q[2],q[3],q[4],q[5],q[6],q[7] ) ) Is this _intention_ or is this something you forgot to unify? --- In "Function TypeTagForId$( id:TTypeId )" you take care of "PointerTypeId" and "FunctionTypeId" twice (once "simple" and another time by checking if it extends from it). --- Within TMethod you have "Method FunctionPtr..." - which is not utilized. The "else"-case of this method differs to the "else" part of the Invoke() method. Is this by intention? - by further checks, it seems as if you just do unneeded code there (as in "Init()" the _fptr is already set to BytePtr(index). Think we could shape some code off here. So Method Invoke:Object( obj:Object,args:Object[] ) If _index<65536 Return _CallMethod( bbRefMethodPtr( obj,_index ),_typeId.ReturnType(),obj,args,_typeId._argTypes ) EndIf Return _CallMethod( Byte Ptr(_index),_typeId,obj,args,_typeId._argTypes ) End Method becomes Method Invoke:Object( obj:Object,args:Object[] ) Return _CallMethod( FunctionPtr(obj), _typeId.ReturnType(), obj, args, _typeId._argTypes ) End Method If aboves int/byte ptr difference was unintented, you could unify "_callMethod" and "_callFunction" and shorten it even more (only difference then is the pushing of the instance in a method call). Edit: This is the current version of your code including my adjustments: https://raw.githubusercontent.com/GWRon/brl.mod-vanilla/ae348595e4e8778e7a8d8a53639e72c48c5e6a39/reflection.mod/reflection.bmx Changes (yours + mine) could be followed there: https://github.com/GWRon/brl.mod-vanilla/commits/feat_extendedReflection2/reflection.mod/reflection.bmx With mine being: https://github.com/GWRon/brl.mod-vanilla/commit/ae348595e4e8778e7a8d8a53639e72c48c5e6a39 bye Ron |
| ||
Sorry for being so slow to answer, i forget to check my email often enough and dont frequenctly check the module sub forum. In Brucey's code the "bbRefArrayNull" is always the same (the pointer to a special object is returned ?) in yours there is a fresh object created everytime. It should be the same really, and with my extremely limited tests it was. Without that change I get segfaults in a sample code of my framework. Hmm.. there might be a reason Brucey chose to test the name of the type after all. Its just that it should not be needed if everything is as it should...SuperStrict Local nullobject:Object Local nullarray:Object[] Local nullstring:String Local t1:TTypeId = TTypeId.ForObject(nullobject) Local t2:TTypeId = TTypeId.ForObject(nullarray) Local t3:TTypeId = TTypeId.ForObject(nullstring) If t1 Then Print "t1: " + t1.Name() If t2 Then Print "t2: " + t2.Name() If t3 Then Print "t3: " + t3.Name()Notice that t1 in the above example is Null, which is in line with the original. Is there a need for a Null type akin to the Null[] perhaps? Or is the Null[] type not needed either? Its been a while since i coded this so the reasoning behind it escapes me :/ About _CallMethod and _CallFunction differences: Forgetfullness :p About TypeTagForId: More forgetfullness, specificly that ExtendsType() checks for equality directly. About TMethod.FunctionPtr() not being used: Perhaps premature optimization by limiting the amount of method calls. I intended it to be a user level method really. Could you test your framework with bbArrayNull() and using ExtendsType(ArrayTypeId) instead of the name check? The purist in me doesnt like it one bit ;) And double check that it really does get different Null arrays, as it shouldnt do that. Id really like to keep it able to compile without mingw for those who still dont use it, though maybe at this point there is no need? But all in all i accept your changes :) If you agree i can include them in the copy here.. But id like to double check the null array stuff first. |
| ||
Hmm, I somehow cannot replicate the segfault now ... neither without your nullArray nor Brucey's variant. regarding MinGW: brl.reflection does contain the .cpp-file already, so MinGW is used regardless of the adjustment Brucey's fix uses. So it seems, as we could mix both additions to something new: ElseIf typeId.ExtendsType(ArrayTypeId) Then If Not value Then value = bbRefArrayNull() EndIf EndIf bbRefArrayNull() is the better decision (imho) as it uses the "internal" representation - maybe "object[]" does that too, but am not sure about this. I understand your scepticism to things like Find("]") :-). If array recognition works flawless, there would be no need for this. Regarding your sample: _assign is only used when using reflection to manipulate values - so in my case this is most probably a Clone-Method for cloning instances (which might contain uninitialized arrays). As there were other issues (already tackled but: dimensions were not correct for some (copied) arrays - happens on Mac and windows) things might have come together without us knowing the real issues. --- I just searched my emails for the correspondence with Brucey about this subject and found an issue for this, but he only adjusted it for "bmx-ng/brl.mod": Brucey: In some cases, bbArrayCastFromObject will return a &bbNullObject. It should probably always return an array of some kind - at least a &bbEmptyArray. https://github.com/bmx-ng/brl.mod/issues/7 @different null arrays Seems I did not express myself well then. What I am was talking about is, that "nullArray" is a freshly created local variable - each time. the bbRefArrayNull() is returning the same variable each time (but an function call of course - or is the "ref" different each time?). I assume "local nullarray:object[]" is returning the very same thing (uninitialized). BTW: I assumed "myB" would have a length of 0 - but it throws out that myB is not an arrayType... Conclusion: Your code (nullarray) should work as expected now (until I get it to crash again :-)). Nonetheless I would prefer doing it similar to other object types and return the "bb***" type (as Brucey did) - of course then, with your "Extends-variant". The most up to date variant is now: https://github.com/GWRon/brl.mod-vanilla/commits/feat_extendedReflection2/reflection.mod/reflection.bmx @agree No problem, most of codes are zlib/libpng - or in this case they are just the same as the original code, so feel free to adopt/copy/print out ... :-) bye Ron |
| ||
bbRefArrayNull() is the better decision (imho) as it uses the "internal" representation - maybe "object[]" does that too, but am not sure about this. Any array declaration without a size will be set to bbEmptyArray no matter what.Otherwise you could not do .Length on it without it returning bogus values or crashing. brl.reflection does contain the .cpp-file already, so MinGW is used regardless of the adjustment Brucey's fix uses. Not if it has already been compiled. So long as the CPP file itself hasent changed it will just import the object file unmodified.But since both you and Brucey seem to like it better il cave ;) The reason it fails for the second array in your test is because it expects TTypeId._ElementType to be filled, the Null[] type didnt do this.. So a bug :) Stick this after the definition of NullTypeId to fix it: ' finish setup of ArrayTypeId ArrayTypeId._ElementType = NullTypeId Updated top post with new version. |
| ||
So for my sample this now responds with: myB: Null[] length: 0 While "myB" is of type int[] - so a null-sized integer-array. "So a bug :)" :-) @precompiled cpp You are right with that - nonetheless people will already have MinGW installed if they compiled BlitzMax from github.com (as it is an open source project now :-). *teeth grinding* you are right - but at least I tried to exculpate. bye Ron |
| ||
While "myB" is of type int[] - so a null-sized integer-array. Even though the type of the field is Int[] there is no way for TTypeId.ForObject() to know that. All it sees is bbEmptyArray, hence the Null[]. *teeth grinding* you are right - but at least I tried to exculpate. Sorry for being a pedant :p |
| ||
Right, but for "Fields" we could find out the type by asking the "parent".SuperStrict Framework Brl.StandardIO Import Brl.Reflection 'the modded one! Type TMyType Field B:Int[0] End Type global my:TMyType = new TMyType print "Definition: TMyType.B type="+TTypeID.ForObject(my).FindField("B").TypeID().name() print "Content: B type="+TTypeID.ForObject(my.B).name() Definition: TMyType.B type=Int[] Content: B type=Null[] But returning "Null[]" for all possibilities is surely more consistent. Else we could return the definition-TTypeId for empty arrays when possible. But for this, "ForObject(my.B)" should know about the object "my", which it doesn't (could be referenced by multiple objects). Hmm, seems there is no 100% working way, except adding this data right on compilation (with BCC, kind of "meta data"). Things should be kept up to date then as BlitzMax allows assigning 0-sized arrays ("bla = New Int[0]"). Ideas how this could get solved? Also ideas on how to access globals are very welcome. BTW: ' finnish setup of array type Might be better than a Danish setup :-) bye Ron |
| ||
But for this, "ForObject(my.B)" should know about the object "my", which it doesn't (could be referenced by multiple objects). You just cant. Not because of some limitation of reflection, but because its an expression returning a value, and that value is Null.An evil example to further the point. Type TTest Field X:Float[] EndType Local x:TTest = New TTest Local a:Int[] = [ 1 ] Byte Ptr Ptr(Varptr x.X)[0] = Byte Ptr Ptr(Varptr a)[0] Print TTypeId.ForObject(x.X).Name() except adding this data right on compilation (with BCC, kind of "meta data") Its not impossible, but it would blow up the meta-data, as every level of every object expression would have to be added. And its not something one really needs anyway. BlitzMax allows assigning 0-sized arrays ("bla = New Int[0]"). True, but it still returns bbEmptyArray for them, so no type is assigned.You could make bbEmptyIntArray and friends but that would break a whole lot of code expecting only 3 null types (object, array, string) and would probably make things slower when checking for Null. Also ideas on how to access globals are very welcome. Not unless mark decides to add them to the meta-data.Though i guess now that BlitzMax is opensource it wouldnt be to difficult, i just prefer to use vanilla myself. Might be better than a Danish setup :-) Damn, i could swear i fixed that! Thats how it goes when one juggles 4 editor instances of the same file lol |
| ||
You could make bbEmptyIntArray and friends but that would break a whole lot of code expecting only 3 null types (object, array, string) and would probably make things slower when checking for Null. couldnt bbEmptyIntArray inherit bbEmptyArray so "old code" is still able to checkwhether something is an empty array at all? Problem stays, that empty "MyObject[]"-arrays would need their "MyObjectEmptyArray" too - which is not existing. So we only would add exceptions for the inbuilt-simple-"types" (int, float, ...). @other stuff Thanks for the elaboration. Disregarding this we advanced with the code and got rid of some bugs. Benefits for all (and for free ;-)). Appended the last revision to my repository. bye Ron |
| ||
couldnt bbEmptyIntArray inherit bbEmptyArray so "old code" is still able to checkwhether something is an empty array at all? It may work like that with reflection, but blitz itself does simple pointer compares so it would have to check a loooong list of stuff. And it would require compiler help to do it, not something i would advocate at all! In fact there are too many null types already, it would be best to coalesce the 3 into a single one. Less confusion for the runtime and compiler. Always nice to get rid of bugs :D |
| ||
When using The DX10/11 modules (https://github.com/SRSSoftware/srs.mod) the resulting binary crashes at the "Throw" in "Function TypeTagForId$( id:TTypeId )". But it then crashes in one of my types, which I cannot explain. As soon as I remove the connection to that modules, everything works nicely again. Ideas? bye Ron |
| ||
Could you change that Throw into:Throw "~q" + id.Name() + "~q was unexpected at this time"To narrow it down a bit? Im just guessing here, but it might happen upon an extern type and getting confused... |
| ||
Thrown (as expected): "Null" was unexpected at this time. ![]() ![]() ![]() The odd thing is, I did not even use that TBatchImage, I just imported the module. And as you see on the pictures, the source of the throw is in "base.util.helper" - no function given, which means it troubled within two globals I define there: Global ListTypeID:TTypeId= TTypeId.ForObject(new TList) Global MapTypeID:TTypeId= TTypeId.ForObject(new TMap) (I use them to check in a clone method whether an object extends from a Tlist or a tmap - as they are often used containers) Disabling the "ForObject" call there, delays the error for some milliseconds to trigger at something else trying to use some reflection. So I assume it was coincidence to crash on these globals ... they are just the first things to use reflection (right upon start). As I am not able to "shrink it down" to something useable. Download my complete game (code + assets), copy the SRS.mod to your modules, import it from the "TVTower.bmx" file (the project main file) and it should "break". https://github.com/GWRon/TVTower https://github.com/SRSSoftware/srs.mod bye Ron |
| ||
Thrown (as expected): "Null" was unexpected at this time. ![]() ![]() ![]() The odd thing is, I did not even use that TBatchImage, I just imported the module. And as you see on the pictures, the source of the throw is in "base.util.helper" - no function given, which means it troubled within two globals I define there: Global ListTypeID:TTypeId= TTypeId.ForObject(new TList) Global MapTypeID:TTypeId= TTypeId.ForObject(new TMap) (I use them to check in a clone method whether an object extends from a Tlist or a tmap - as they are often used containers) Disabling the "ForObject" call there, delays the error for some milliseconds to trigger at something else trying to use some reflection. So I assume it was coincidence to crash on these globals ... they are just the first things to use reflection (right upon start). As I am not able to "shrink it down" to something useable for now: Download my complete game (code + assets), copy the SRS.mod to your modules, import it from the "TVTower.bmx" file (the project main file) and it should "break". https://github.com/GWRon/TVTower https://github.com/SRSSoftware/srs.mod bye Ron |
| ||
I downloaded the source and tried to run, but all i get is this weird error:Building TVTower error loading "C:/TVTower/source/main.bmx" Process completeNever run into something like this before :( I suspect my BMK is broken for some reason, but everything else seems to work so im stumped... |
| ||
Ah ok... think you use the vanilla BMK ? It has no support for some additional things done on compilation (creation of a "source/version.txt" containing the compilation date) So it might then stumble over the missing incbin or so? bye Ron |
| ||
Yeah i use vanilla bmx. And its not the version.txt it bugs on, it just doesnt like reading from UTF-16-LE files. At all. Meaning it fails to read even the first byte. This is surely weird. EDIT: It manages to read the BOM atleast, and figures out the correct format. But fails to read the next byte. |
| ||
They should be UTF8 with BOM ... as BlitzMax else even is not able to print "äüö" (Umlauts) - which are present in the ANSI chars (246 is "ö").$ file -i main.bmx main.bmx: text/plain; charset=utf-8 (i also run for f in `ls *.bmx`; do echo "$f" ' -- ' `file -bi "$f"` ; done and only got us-ascii and utf-8 files) Saving the file as UTF16-LE resulted in the correct recognition as utf-16le. Only alternative to UTF8 with BOM was to extract every string to text files and then importing them... which I only did for localized files. But one my developer buddies uses German comments - resulting in the usage of umlauts... I compile the very same code within my Windows XP VM using the default BlitzMax 1.50 (plus its MaxIDE) and MinGW 4.6.1. I updated BMK to use Brucey's (as this allows for some pre/post-compilation scripts). bye Ron |
| ||
Yeah, i see now the original is UTF8 with BOM, must have been maxide that saved it as UTF16LE for some reason. But it still fails to read it :( And opening the file in Scite i can see it has highlighted umlauts in Red, signaling that they may be incorrect.. or something. Il try to remove all occurances of that and see what happens. |
| ||
Yes... editing these files in MaxIDE is not recommended ... same for blIDE (that dev used blIDE [full version]) as this also destroyed these characters as it tried to save it in some odd encoding mix. Even if it destroys the character, the error you got is more than misleading: the source file is there, it just might run into problems compiling them... very odd. PS: Brucey did compile the game more than once and never mentioned such an error, so it might be something with your BlitzMax-installation (1.50 - as some older versions stalled when processing some comments in my code). bye Ron |
| ||
Scratch that, i forgot i replaced LoadText() with LoadString() to test that ;) The odd thing too, is that i can use LoadText() to load that same file without trouble. Its just my BMK that is borked for whatever reason :( |
| ||
I am using "Framework BRL.StandardIO" :-) ... but I cannot explain why removing the framework-command resolves such an issue... Edit: registered your "scratch this" If LoadText was the thing failing, then the incbin might be problematic - albeit it fails differently here, when the to-incbin-file is not existing. Edit2: Do you use the vanilla bmk or a custom built one ? Maybe you are able to try Bruceys BMK (do not forget to copy core.bmk + make.bmk to the bin-dir). It will really speed up compilation. Newer incarnations of his BMK look for BlitzMax/MinGW32 to find a custom MinGW and else fall back to the default one. bye Ron |
| ||
I use vanilla BMK, just modified to work with GCC 5.1.0. So nothing special, just some added flags to various parts. Nothing that should mess with TTextStream. I have tried Bruceys BMK before, but never gotten it to work sadly. By removing the BOM it does compile though, which is weird to say the least. |
| ||
Ok ... then - if the game is running now on your side (hopefully it does :-)) the next step would be to download the DX10-module and place it in your mods-folder. The import it within the code (main.bmx or so - I used source/Dig/base.util.graphicsmanager.win32.bmx - as it would be used there) and after compilation it should error when executing (because of the reflection). Your reflection code is there: source/Dig/external/reflectionExtended/reflection.bmx Edit: if you miss maxmod2.mod then you could find a "lite" version of it in source/Dig/external/maxmod2_lite.mod.zip If you do not want to have to use another module (and then fall back to "FreeAudio"), open up source/Dig/base.sfx.soundmanager.bmx and use the "nortaudio" variant for your platform (I use this for a user who runs Knoppix/Linux and has issues with PulseAudio...). bye Ron |
| ||
It will take some time, i have to compile until it fails on a file. Remove the BOM on that file. And then recompile until it hits another file with the same error. Surprisingly its not all of the files, just a few of them. |
| ||
Sorry to read about that tedious job :-) Meanwhile you could check my post before yours ...as I edited it (maxmod2.mod). bye Ron |
| ||
Got it to compile, but it now fails in the linker:C:/TVTower/source/.bmx/zip.c.release.win32.x86.o:zip.c:(.text+0x197b): undefined reference to `_time32' C:/TVTower/source/Dig/external/libxml/src/.bmx/nanohttp.c.release.win32.x86.o:nanohttp.c:(.text+0x7d2): undefined reference to `WspiapiGetAddrInfo@16' C:/TVTower/source/Dig/external/libxml/src/.bmx/nanohttp.c.release.win32.x86.o:nanohttp.c:(.text+0x847): undefined reference to `WspiapiFreeAddrInfo@4' C:/TVTower/source/Dig/external/libxml/src/.bmx/nanohttp.c.release.win32.x86.o:nanohttp.c:(.text+0x864): undefined reference to `WspiapiFreeAddrInfo@4' C:/TVTower/source/Dig/external/libxml/src/.bmx/nanohttp.c.release.win32.x86.o:nanohttp.c:(.text+0x8bf): undefined reference to `WspiapiFreeAddrInfo@4' Nothing i do manages to fix it either. I guess our build systems are just too different :( Sorry, but im giving up now. Unless you manage to narrow the reflection bug down to a smaller sample. Ive updated top post with a possible fix. (added NullTypeId check) |
| ||
Sorry to hear (but i understand ...) Dunno why you get this error, people on the internet suggest to import "-lws2_32" ... but this is not needed here. Assume this has to do with our minGW versions. Will try your "possible fix" tomorrow when sober and awake :-) Maybe I can come up with a smaller example then. bye Ron |
| ||
SuperStrict Import SRS.D3D11Max2D Import "../TVTower.WorkingCopy/TVTower.git/source/Dig/external/reflectionExtended/reflection.bmx" Global ListTypeID:TTypeId=TTypeId.ForObject(New TList) Print "done" This errors out here... of course you need to adjust the path to the reflection file. bye Ron |
| ||
Hmmm.. It works here :/ Even when loading only that version of reflection. Framework BRL.StandardIO SuperStrict Import SRS.D3D11Max2D Import "c:/TVTower/source/Dig/external/reflectionExtended/reflection.bmx" Global ListTypeID:TTypeId=TTypeId.ForObject(New TList) Print "done" |
| ||
That's very odd then... Hmm.. potential source of the error? I mean ... I understand that it should not "error" as I do not use the imported source, so reflection does not know about it... some "framework" thingy ? bye Ron |
| ||
And i got this to error out: SuperStrict Import SRS.D3D11Max2D Local o:Object = New TList Global ListTypeID:TTypeId=TTypeId.ForObject(o) Print ListTypeID.Name() Print ListTypeID.FindMethod("ToString").Invoke(o, Null).ToString() Print "done" Type TList Method ToString:String() Return "new TList" EndMethod EndTypeComment out the D3D11 module and it works like it should again. Im going to bed now but il look into it more tomorrow. At least i have something to work with now :) |
| ||
I couldnt sleep, so did some tests and figured out what was causing the error. Var parameters ;) Seems they get converted to pointers in the metadata. Well it was the cause, but the bug in reflection code was in TTypeId.PointerType() which caused it to recurse over its root PointerTypeId when it shouldnt. Top post updated with fix. I hope this works for you Derron, and thanks for being patient :) EDIT: Heres the test i ended up using: SuperStrict Type TSample Method Update(pos:Float[] Var) EndMethod EndType Local o:Object = New TSample Global t:TTypeId=TTypeId.ForObject(o) Print t.Name() Local m:TMethod = t.FindMethod("Update") For Local a:TTypeId = EachIn m.ArgTypes() Print a.Name() Next Print "done" |
| ||
'finnish -> finish :-) Type TMethod Method Invoke:Object( obj:Object,args:Object[] ) -> Method Invoke:Object( obj:Object,args:Object[] = Null ) TFunction and TField already use "= Null", so adding it is nice for consistency. === SNIP === Now to the important: it works (does not crash). Do you have an explanation why it did not crash without that module? Why is it using some reflection stuff of that module even if I do not use it? Thanks for "not being able to sleep" (and solving another issue) :-) bye Ron |
| ||
Do you have an explanation why it did not crash without that module? Why is it using some reflection stuff of that module even if I do not use it? Because when reflection is first used, it goes through ALL registered types and adds them internally to a TMap.At which point it happened upon a Type with a Method with Var parameters. I guess Var parameters arent used much on Methods elsewhere, but SRS.D3D11Max2D has one in TBatchImage with 4 of them ;) Fixed the typo (again! lol) and added Null as suggested. Thanks for "not being able to sleep" (and solving another issue) :-) Hehe, no problem :) |
| ||
Version 1.21 - fixed _Push not setting bbEmptyArray for Null arrays. |
| ||
Updated my Pull Request (Brucey's Maxmod: github.com/maxmods/brl.mod) to incorporate 1.21. bye Ron |
| ||
Version 1.22 - fixed _Call not working with Long/Double return values. Weird that i (or anyone else) havent noticed this before, so to be sure. Run this before trying 1.22 to verify that it really is bugged: |
| ||
Version 1.23: Added _bbCallMethod() asm function for calling with proper number of arguments. Increased maximum argument count to 30. I was inspired by this post to finally add proper calling :) |
| ||
@Test "long/double": segfaulting with current implementation (v1.21) Updated reflection code (all 2 files + 1 new file). ./bmk makeapp -t console -a -r -x "/testcodes/reflectionExtendedTest.bmx" [ 6%] Compiling:reflection.cpp [ 74%] Archiving:reflection.release.linux.x86.a [ 99%] Processing:reflectionExtendedTest.bmx ar: creating /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a [ 99%] Compiling:reflectionExtendedTest.bmx.console.release.linux.x86.s flat assembler version 1.68 (32768 kilobytes memory) 3 passes, 5544 bytes. [100%] Linking:reflectionExtendedTest /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xb7f): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xbaa): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xbcc): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xbf7): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xc21): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o):(code+0xc4e): more undefined references to `bbCallMethod' follow collect2: error: ld returned 1 exit status Build Error: Failed to link /testcodes/reflectionExtendedTest Did I miss something? bye Ron |
| ||
Hmm thats a bit weird. TClass is virtually empty, no references to bbCallMethod there. Only used in _Call 6 times. The log doesnt show callmethod.s either, maybe it isnt picked up by bmk and then not compiled in? To double check that, see if reflection.bmx.release.linux.x86.s has _bbCallMethod as an extrn at the top somewhere. Other than that, maybe try a recompile of the mod alone. |
| ||
reflection.bmx.release.linux.x86.s:format ELF extrn __bb_blitz_blitz extrn __bb_linkedlist_linkedlist extrn __bb_map_map extrn bbArrayNew1D extrn bbArraySlice extrn bbCallMethod extrn bbEmptyArray ... compiled the module via: ./bmk makemods -a brl.reflection it compiled flawlessly removed all .bmx stuff and i/a files. re-compiled your sample (which should rebuild everything if needed): ./bmk makeapp -t console -a -r -x "/testcodes/reflectionExtendedTest.bmx" [ 6%] Compiling:callmethod.s flat assembler version 1.68 (32768 kilobytes memory) 1 passes, 170 bytes. [ 6%] Compiling:reflection.cpp [ 69%] Processing:reflection.bmx [ 72%] Compiling:reflection.bmx.release.linux.x86.s flat assembler version 1.68 (32768 kilobytes memory) 5 passes, 38112 bytes. [ 74%] Archiving:reflection.release.linux.x86.a [ 99%] Processing:reflectionExtendedTest.bmx ar: creating /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a [ 99%] Compiling:reflectionExtendedTest.bmx.console.release.linux.x86.s flat assembler version 1.68 (32768 kilobytes memory) 3 passes, 5544 bytes. [100%] Linking:reflectionExtendedTest /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xb7f): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xbaa): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xbcc): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xbf7): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o): In function `_brl_reflection_TClass_SetClass': (code+0xc21): undefined reference to `bbCallMethod' /BlitzMax/mod/brl.mod/reflection.mod/reflection.release.linux.x86.a(reflection.bmx.release.linux.x86.o):(code+0xc4e): more undefined references to `bbCallMethod' follow collect2: error: ld returned 1 exit status Build Error: Failed to link /testcodes/reflectionExtendedTest bye Ron |
| ||
Aha, i forgot about ELF ;) The .s file is using "MS COFF". Im surprised fasm and bmk doesnt complain about it though, they really should! Anyway, try version 1.24 with own files for linux and win32. |
| ||
What's up with MacOS - special handling needed too? Linux still fails: ./bmk makeapp -t console -r -x "/testcodes/reflectionExtendedTest.bmx" [ 6%] Compiling:callmethod.linux.x86.s flat assembler version 1.68 (32768 kilobytes memory) /BlitzMax/mod/brl.mod/reflection.mod/callmethod.linux.x86.s [6]: section "code" code error: invalid argument. Build Error: Failed to assemble /BlitzMax/mod/brl.mod/reflection.mod/callmethod.linux.x86.s bye Ron |
| ||
Damn fasm is fickle ;) Yeah, il add one for macos as well. Even though i have to use AT&T syntax :( Updated top post with version 1.25, hopefully this is it :p |
| ||
Back to the error in #65 (removed module's .i/.a files, .bmx directory, and precompilates of the test sample before compiling it again) bye Ron |
| ||
Hmm seems linux doesnt like underscores or something, or it adds them itself. Anyway, remove the underscores from all the labels (including _memcpy) and it should compile. Had to install linux in a vm to test ;) MacOS is still untested. Updated top post. |
| ||
Works now. Seems you were right with the underscore. @Mac There are options to install a Mac OS X in a VM too.. bye Ron |
| ||
The versions starting with 1.14/1.15 lead to a bugged BMK (Brucey's BMK). This BMK calls some Lua files (.bmk) - but these now fail with "arg0" being invalid data - so passing things to lua is bit of broken. Do not know what exactly, as my game's lua-scripts work as intented (think so at least). bye Ron |
| ||
I assume its the one from here https://github.com/bmx-ng/bmk .. I am unable to reproduce it though, arg0 contains valid data for assemble, compileBMX and compileC (arg0 in those contains the entire commandline). In what instances does this happen, and what platforms? |
| ||
Using Brl.mod from https://github.com/maxmods/brl.mod and Pub.mod from https://github.com/maxmods/pub.mod Copied your Brl.reflection-code from the first post (reflection.bmx, reflection.cpp, callmethod.linux.x68.s). Recompiled modules via "bmk makemods brl" (recompiled a bunch of modules, as brl.blitz is recompiled too (base for many things). Then I recompiled BMK with vanilla BCC and the modified Brl.reflection. Put BMK into another BlitzMax-Directory (BlitzMaxNG-overload) and when trying to execute a compilation (eg. modules) I get this: $ ./bmk makemods ERROR [string "function bmk_source_type(...)..."]:5: attempt to concatenate local 'arg0' (a userdata value) This errors is based on a .bmk-file executed before compilation - saying "arg0" is invalid data. OS: Linux 64Bit. As "callmethod***" is introduced after it started getting "borked", I assume it must be something different. bye Ron |
| ||
There is only 4 places where it spits out "ERROR", in _Push(), _Assign() and two in _Call(). Im guessing its one of them in _Call(), both of them are thrown when the number of arguments is exceeded. Though with a maximum of 30 arguments that is a bit weird... The reason for the invalid data in arg0 is probably because it throws that exception and skips some init code related to the lua call. Could you number the throws in reflection.bmx to narrow it down perhaps? Il try to narrow it down in any case, but it might take me a while to reproduce. |
| ||
I tried that already (Error1 - Error4) but it keeps saying "ERROR" (no number). I rebuilt all modules afterwards (and manually deleted the modules precompilates), rebuild BMK completely ... - removed brl.mod completely, unzipped a new one, pasted reflection code into it, adjusted "Error" to "errorNumber" and recompiled BMK ... message is "ERROR". Maybe "Error" is the LUA message, not the message from reflection. I think this is the case and the error is, that "arg0" is kind of "nil" (Lua-"Null") which disallows access to it. My game's Lua-code might run without trouble as I do not use MaxLua but a custom implementation with some extensions/differences. Edit: maxlua.bmx: Function LuaDumpErr() WriteStdout "ERROR~n" WriteStdout lua_tostring( LuaState(),-1 ) End Function This is where the ERROR comes from. bye Ron |
| ||
Ah, my bad :p I did the same as in your recipe, and got an access violation when calling RunCommand (in bmk) And then remembered that i had to modify brl.maxlua for the changed ReturnType() thing, and after that everything went as normal. This is on Windows though, il try the same dance in Linux too. |
| ||
So would you mind sharing what you have changed in maxlua? :-) I assume this: Function Invoke( L:Byte Ptr ) Local t:Object=meth.Invoke( obj,args ) Select meth.TypeId() ' becomes Select meth.ReturnType() ... This explains why my lua-engine still works - I use this code line: Local typeId:TTypeId = funcOrMeth.TypeID().ReturnType() bye Ron |
| ||
Its in the top post.. Line 77 of maxlua.bmx, same change as yours. EDIT: Just tried it on linux, still not able to reproduce :( |
| ||
As soon as I adjusted that maxlua line, compilation with the newly compiled BMK was possible again (no LUA-error anylonger). Thanks for your help. bye Ron |
| ||
Ah, good to know, no problem dude :) |
| ||
Not a bug, but a question: Do you see any chance to make that "ReturnType()" portion compatible to the original mod? When trying out things with Bruceys NG (and the NG-modules) I used the brl.reflection of NG as it contained Method/Function/Field/Const already (and your code contained some things not compatible with NG/overload). It compiled fine but the issue was, that my lua-engine relied on Local typeId:TTypeId = funcOrMeth.TypeID().ReturnType() which resulted in different types in your code file and Bruceys brl.reflection. So the question is based on the idea of keeping things "compatible" as much as possible. It would also get rid of the needed modification of brl.maxlua. Thoughts? bye Ron |
| ||
Well, since you have control over your own lua glue you could use the ?bmx-ng directive and revert to original behavior inside that. There is a reason for the change though, because of Function Types. Notice that TypeId() is implemented in TMember, and it returns the full typeid. So a TField can contain a FunctionType, and that type can have a return type which is also a FunctionType etc. I see it as a limitation of the original BRL.Reflection being incomplete in a way, not only missing types but also overloading the TypeId() method to mean different things. It really should have had a ReturnType() instead :p I dont want to override it for TMethod and TFunction to be honest, as that way you cant treat a TMember and its TypeId() uniformly. But since this modification is more or less complete (barring any new bugs) overriding them yourself isnt that much of a chore.. All you would need is adding these two methods to TMethod and TFunction. Method TypeId:TTypeId() Return ReturnType() End Method Method FunctionTypeId:TTypeId() Return _typeId End MethodNote that i have not tested this ;) reflection.bmx with original semantics. |
| ||
Missed your reply - so excuse the delay. I understand your reasons on why you did it that way. Of course I am using "?bmxng"-conditionals, but the problem is, that once, bmxng adjusts its behaviour to "yours", then the application needs manual adjustment (if you miss removing that conditional adjustments, it breaks logic/bugs out). Hmpf. Thanks again for your time. bye Ron |
| ||
Just recognized, that invoking functions does not work as expected:SuperStrict Framework Brl.StandardIO Import Brl.Reflection 'extended variant Type Test Function Func:Int() End Function End Type Local tID:TTypeId = TTypeId.ForName("Test") Local func:TFunction = tID.FindFunction("Func") 'segfaults in "invoke" func.Invoke(Null) Print "invoked" When adding a "debugstop" and then going into all called functions it segfaults when calling the external function "bbRefMethodPtr" (because "obj" is null) Method FunctionPtr:Byte Ptr( obj:Object) If _fptr Then Return _fptr If _index < 65536 Then ~~~~> _fptr = bbRefMethodPtr( obj ,_index) EndIf Return _fptr End Method So the problem is that I pass "null" to invoke (as the obj-param) ... but am I really supposed to pass an instance of the type there? Functions are meant to be callable also via "TMyClass.FunctionName()". Replacing that "func.Invoke(null)" with an existing type-instance as param, gets rid of the segfault... 'works Local t:Test = New Test func.Invoke(t) Invoking a method works. bye Ron |
| ||
Thanks, its fixed in v0.26 by using the Self TypeId class directly on Null arguments. |
| ||
Thanks for the update. bye Ron |
| ||
Your code does not compile with my Mac OS X... the *.x86.s contains invalid characters - also things like ".global" do not exist (you need to use ".globl") - and ".extern" seems to be not needed. bye Ron |
| ||
Thanks for the heads up, without a mac its hard to test these things. The invalid characters might be CRLF? Since i develop on windows, my editors use that as EOL, and its not UTF-8 either, which both linux and macosx might expect. But that AT&T syntax really sucks :( Some docs say ".global" other say ".globl", other say they are aliased. But apparently its up the the platform?? Usually one uses size suffixes, but it complains when i do. And when i dont it also complains, so i am at a loss here. Stupid me forgets i have 64bit mingw now ;) Does it work just with changing to .globl for you? In any case, i updated it with your change at least. But im leaving .extern in to make it similar to the others, and just because its the right thing to do ;) EDIT: Oh and btw, what version of AS are you using? Since 2.10 they added .intel_syntax directive so i can probably use that instead. EDIT2: I re-uploaded the archive with linux and macosx files in UTF-8 and with only LF chars. |
| ||
I use a Mac in a VM ... so it is outdated (but used to work). as -v Apple Inc version cctools-750-70, GNU assembler version 1.38 Stored with LineEnding "CR" ("LF" is Linux, "CR/LF" is Windows) and it compiled with .globl _bbCallMethod _memcpy .text _bbCallMethod: push %ebp mov %esp, %ebp sub 16(%ebp), %esp push 16(%ebp) push 12(%ebp) push %esp call _memcpy add 4, %esp call *8(%ebp) mov %ebp, %esp pop %ebp ret Then on linking: Undefined symbols: "_bbCallMethod", referenced from: _814 in reflection.bmx.release.macos.x86.o _816 in reflection.bmx.release.macos.x86.o _808 in reflection.bmx.release.macos.x86.o _809 in reflection.bmx.release.macos.x86.o _810 in reflection.bmx.release.macos.x86.o _811 in reflection.bmx.release.macos.x86.o ld: symbol(s) not found PS: Excuse my request without a solution - was prepared to release a new version of my open source game ... and then it did not compile for Mac ... fiddling with little hotfixes for 3 hrs now ...arrrgh ;-) bye Ron |
| ||
Apple Inc version cctools-750-70, GNU assembler version 1.38 Ah yes, the things ive heard about seriously outdated gnu tools on mac isnt an exaggeration i suppose. Im surprised it compiled with only CR, so far as i know OSX follows its BSD roots and uses LF like linux does. Excuse my request without a solution - was prepared to release a new version of my open source game ... and then it did not compile for Mac ... fiddling with little hotfixes for 3 hrs now ...arrrgh ;-) No problem dude. Its my baby so i have to keep it well fed :p But it seems your the only one using it though hehe |
| ||
Any ideas about the linking issue? Is there a real need for the ASM files at all? I mean: could that get achieved with c/bmx only? Bye Ron |
| ||
Any ideas about the linking issue? Oh, sorry. I missed that. Its probably the number of underscores before the symbol. Windows tends to always have one, the others not so much. You can look at the generated S files on mac and see what bmx spits out, or try removing/adding underscores. Allso, after trying it on here it crashes. Which is probably because i didnt use size suffixes so it inferred the wrong size. I disassembled the win32 code, and saw that it really did use them, so i did too and it now works here (on Windows, but still) So try using this snippet until it compiles. .globl bbCallMethod .extern _memcpy .text bbCallMethod: push %ebp mov %esp,%ebp sub 0x10(%ebp),%esp pushl 0x10(%ebp) pushl 0xc(%ebp) push %esp call _memcpy add $0x4,%esp call *0x8(%ebp) mov %ebp,%esp pop %ebp retNote the removed underscore, this wont compile on windows. When you figure out the underscore thing il update the top post :) EDIT: Is there a real need for the ASM files at all? I mean: could that get achieved with c/bmx only? Well, sure. The original did just that, but it was limited by number of arguments and it was probably a bit slower. Though i havent benched it. ASM is needed in this case to support unlimited arguments. |
| ||
I tried your code... and it compiled ... but the linker error kept the same. So while I removed the underscore from "bbCallMethod" (two times) and _REBUILT_ my application (so no cache usage) the error kept saying Undefined symbols: "_bbCallMethod", referenced from: _814 in reflection.bmx.release.macos.x86.o _816 in reflection.bmx.release.macos.x86.o _808 in reflection.bmx.release.macos.x86.o _809 in reflection.bmx.release.macos.x86.o _810 in reflection.bmx.release.macos.x86.o _811 in reflection.bmx.release.macos.x86.o ld: symbol(s) not found (same line numbers than before) reflection.bmx.release.linux.x86.s only contains "bbCallMethod", no underscore. bye Ron |
| ||
Hmm.. After looking over how BRL.Blitz does it, it uses underscore for macos so i was wrong on that one. What i did notice though was that Blitz.bmx always uses the extern name with no underscores, so maybe that will work. Change line 125 of reflection.bmx to: Function bbCallMethod:Int( p:Byte Ptr, args:Byte Ptr, sz:Int) = "bbCallMethod"EDIT: And add the underscore back in to the one i posted above.. |
| ||
That did not do it. So I build up a small example for the reflection stuff (my game just takes too long to compile in the Mac VM). - switching back to LF-LineEnding (Unix-Style) (required, CR does not work) - removed the "_memcpy" (invalid character '_' in mnemonic) - added back underscores -> compiled and executed I think ".extern _memcpy" is not needed, as "_memcpy" is automatically "externed". .globl _bbCallMethod .text _bbCallMethod: push %ebp mov %esp, %ebp sub 16(%ebp), %esp push 16(%ebp) push 12(%ebp) push %esp call _memcpy add 4, %esp call *8(%ebp) mov %ebp, %esp pop %ebp ret reflection.bmx kept as before: Function bbCallMethod:Int( p:Byte Ptr, args:Byte Ptr, sz:Int) Function bbCallMethod_Float:Float( p:Byte Ptr, args:Byte Ptr, sz:Int) = "bbCallMethod" Function bbCallMethod_Object:Object( p:Byte Ptr, args:Byte Ptr, sz:Int) = "bbCallMethod" Function bbCallMethod_Double:Double( p:Byte Ptr, args:Byte Ptr, sz:Int) = "bbCallMethod" Edit: My Game now crashes when going into a specific situation. Will check in the evening if it has to do with the new reflection stuff (debug build surely takes some time ...time I do not have now). bye Ron |
| ||
Weird... At least it compiles now :) But you need to use the one with size suffixes, or it will read/write bytes instead of longs. .globl _bbCallMethod .text _bbCallMethod: pushl %ebp movl %esp,%ebp subl 0x10(%ebp),%esp pushl 0x10(%ebp) pushl 0xc(%ebp) pushl %esp calll _memcpy addl $0x4,%esp calll *0x8(%ebp) movl %ebp,%esp popl %ebp ret Updated top post with the new code as well. EDIT: I think ".extern _memcpy" is not needed, as "_memcpy" is automatically "externed". Its a GCC builtin, which is probably why you dont have to define it. Still its the right thing to do ;) declaring intent and all. |
| ||
@ extern not needed It is not "allowed" in that ancient build chain. So I did not "optionally" remove it, but was forced to do so. Recompiled with your adjustments (in "debug mode"): "TVTower.debug wurde unerwartet beendet." - think it is telling something in the likes of "unconditionally exited the application". So even the debugger did not "hop in". Running it via "GDB" saays Program received signal EXC_BADACCESS, Could not access memory. Reason: KERN_PROTECTION_FAILURE at address: ... the backtrace then contains "in std::list<IMaxModChannel*, std::allocator<IMaxModChannel*> >:: ..." So it somehow crashes when doing something with MaxMod2 (audio streaming module). But I doubt it has to do something - did not change that code portions the last days. Ok, so I replaced the reflection stuff with a variant "before ASM" ... compiled and run the game without that crash. bye Ron |
| ||
Well thats a bummer. The code is identical for all 3 platforms, but there may be some stack layout or other im not aware of on MacOSX (or Linux for that matter). Hmm weird that it should propagate into there, but if there is some stack misalignment that would do it. Il have to look into this... At least you only have to replace _Call() with an earlier version. Are you compiling this on Linux as well btw? |
| ||
You can try the code below. Which aligns the arguments and the stack on 16 a byte boundary (with some waste of course) for MacOSX only..globl _bbCallMethod .text _bbCallMethod: pushl %ebp movl %esp, %ebp andl $0xFFFFFFF0, %esp subl 0x10(%ebp), %esp pushl 0x10(%ebp) pushl 0xc(%ebp) pushl %esp calll _memcpy addl $0x4, %esp calll *0x8(%ebp) movl %ebp, %esp popl %ebp ret |
| ||
Compiled with your adjustments. Compilation successful, game starts ... crashes on a specific action (going to next screen) It must be some "specific thing". I also tried to removed "play sound"-parts but it still crashes. @ Linux Yes, my main development takes place on a Linux Mint 64 bit installation. Windows is compiled via MicroXP-VM and Mac via a Mac OS X VM. (Windows then could be tested on winXP, 7, 8 and 10 - for now I only had trouble with win10 and some graphics thingies) Edit: I also tried the "demoapp"-sample of my framework Dig (http://github.com/GWRon/Dig.git) and when replacing the "external/reflectionExtended"-portion with yours - aka "updating your reflection stuff") it crashes too - as soon as I close the modal dialogue (some gui stuff). So it seems to be not connected to sound stuff. bye Ron |
| ||
Hmm, if that didnt do it i dont know what will. I havent found any other "rules" for asm on macs either. At least its only macs that are fussy, the rest are ok. So for now, im going to revert back to the old way without assembly for macs. |
| ||
Excuse me for not being able to solve that puzzle with you. ASM and memory/internal stuff is way over my head. bye Ron |
| ||
Hehe no problem dude :) I will look into it some more though, whenever i get osx running in virtualbox. Tried the 2 latest versions last year, but they both failed. Maybe itl work now, who knows :p |
| ||
I wasnt aligning the stack properly, it needs to be aligned before each call apparently. If you still want a go at this, replace the code in v1.27 with the one below. .globl _bbCallMethod .text _bbCallMethod: push %ebp mov %esp,%ebp mov %esp,%eax sub 0x10(%ebp),%eax and $0xfffffff0,%eax mov %eax,%esp push $0x0 pushl 0x10(%ebp) pushl 0xc(%ebp) push %eax call _memcpy add $0x10,%esp call *0x8(%ebp) mov %ebp,%esp pop %ebp ret |