Re: opDispatch with string mixin does not work as I would expect.
On Saturday, 10 February 2018 at 06:32:43 UTC, German Diago wrote: Hello everyone, I am trying to forward some member functions from a struct as a Catch-all function, so I did something like this: struct A { struct HeaderData { align(1): char [21] id; ubyte field1; ubyte field2; } Nullable!(HeaderData) headerData; auto opDispatch(string name)() { readHeader(); static foreach (member; __traits(allMembers, HeaderData)) { static if (name == member) { return mixin("headerData." ~ name); } } } The mixin line does not work. I want to generate the access to the field. How could I achieve that? That looks like it should work. Perhaps you need to change `static if (name == member)` to `static if (name == member.stringof)` Alternatively you could do something like auto opDispatch(string name)() if(hasMember!(HeaderData,name){ readHeader(); return mixin("headerData." ~ name); }
Re: opDispatch with string mixin does not work as I would expect.
On Saturday, 10 February 2018 at 06:32:43 UTC, German Diago wrote: The mixin line does not work. I want to generate the access to the field. How could I achieve that? struct Outer { struct Inner { int a; float b; } Inner i; auto opDispatch(string name)() { return __traits(getMember, i, name); } }
opDispatch with string mixin does not work as I would expect.
Hello everyone, I am trying to forward some member functions from a struct as a Catch-all function, so I did something like this: struct A { struct HeaderData { align(1): char [21] id; ubyte field1; ubyte field2; } Nullable!(HeaderData) headerData; auto opDispatch(string name)() { readHeader(); static foreach (member; __traits(allMembers, HeaderData)) { static if (name == member) { return mixin("headerData." ~ name); } } } The mixin line does not work. I want to generate the access to the field. How could I achieve that?
Re: typedef behavior
On Saturday, 10 February 2018 at 02:08:50 UTC, Alex wrote: Inside of the struct E I define more then one static array. Namely, one for each Typedef I plan to instantiate. The Typedefs have to be known at compile time, so the amount of them has to be known by me :) Then, during the initialization, I work only with one of the arrays of E, depending on the Typedef I use. During the work inside of E, the object will have to check, which array was initialized and cooperate with this array, as this is the only possibility. Hmm... No. As the arrays are shared all of them will be initialized for every Typedef and the last point (decision during the work inside of a single Typedef) can not be achieved. So... there has to be another indirection, which will be filled during (possibly static) initialization.
Re: Run-time initialised static variables
On Tuesday, 6 February 2018 at 23:03:07 UTC, dekevin wrote: Hello everyone, I just ran into the problem, that I need a static variable, where the initialisation code for that variable is only accessible during run-time (since part of the initialisation code will be dynamically linked). Is there a way to do this in D? To be a bit more concrete, this is where I have the problem (where ℚ uses GMP, which is dynamically linked): struct ℚInf { ℚ qval; immutable static ℚInf zero = ℚInf(0,1); this(long num, long den) { qval = ℚ(num,den); //this initialisation requires dynamically linked code } } In case anyone is curios, thanks to tgehr i was able to resolve the issue. For static variables: struct ℚInf { ℚ qval; static ℚInf zero = void; static this() { zero = ℚInf(0,1); } } For immutable static variables (a bit hacky since it sidesteps the type system): struct ℚInf { ℚ qval; immutable static ℚInf zero = void; static this() @trusted { import std.conv: emplace; emplace!ℚInf(cast(ℚInf*),ℚInf(0,1)); } }
Re: typedef behavior
On Saturday, 10 February 2018 at 01:23:20 UTC, Ali Çehreli wrote: > > Yup. They are shared by two Typedef instantiations with different cookies. > > So... > The question is two-fold: > Would it help to alter the init value of the Typedef? > If yes, how to alter it? > If no, is this a bug? I think this is a limitation of Typedef. I can't see a way out (at least one that can support any type E). It should be possible if you can modify E but I can't work something out now. Ali Ah... From your hint I arrived at the following: Inside of the struct E I define more then one static array. Namely, one for each Typedef I plan to instantiate. The Typedefs have to be known at compile time, so the amount of them has to be known by me :) Then, during the initialization, I work only with one of the arrays of E, depending on the Typedef I use. During the work inside of E, the object will have to check, which array was initialized and cooperate with this array, as this is the only possibility. As a workaround this will work, I think... Thanks! Nevertheless, I would file a bug later on... all ideas are appreciated in the meanwhile.
Re: typedef behavior
On 02/09/2018 05:14 PM, Alex wrote: >> > struct E >> > { >> > size_t i; >> > static T[] tarr; >> >> To save time to others, note that 'tarr' is a static member that ends >> up being shared by two Typedef instantiations. > > Yup. They are shared by two Typedef instantiations with different cookies. > > So... > The question is two-fold: > Would it help to alter the init value of the Typedef? > If yes, how to alter it? > If no, is this a bug? I think this is a limitation of Typedef. I can't see a way out (at least one that can support any type E). It should be possible if you can modify E but I can't work something out now. Ali
Re: typedef behavior
On Saturday, 10 February 2018 at 01:01:39 UTC, Ali Çehreli wrote: On 02/09/2018 03:45 PM, Alex wrote: > A question about Typedef usage: > Say, I have the following circumstances > > /// --- code --- /// > > import std.typecons; > > void main() > { > MyEA ea; > MyEB eb; > ea.tarr.length = 5; > static assert(!is(MyEA == MyEB)); > static assert(!is(MyEA == E)); > static assert(!is(MyEB == E)); > assert(ea.tarr.length == eb.tarr.length); // line 11 > assert(ea.tarr.length != eb.tarr.length); // line 12 You must have meant assert(ea.tarr.ptr != eb.tarr.ptr); // line 12 Indeed, .ptr are unexpectedly the same. Yes... this is a more precise comparison :) > } > > struct T > { > size_t i; > } > > struct E > { > size_t i; > static T[] tarr; To save time to others, note that 'tarr' is a static member that ends up being shared by two Typedef instantiations. Yup. They are shared by two Typedef instantiations with different cookies. So... The question is two-fold: Would it help to alter the init value of the Typedef? If yes, how to alter it? If no, is this a bug? > } > > alias MyEA = Typedef!(E, E.init, "A"); // line 26 > alias MyEB = Typedef!(E, E.init, "B"); // line 27 > > /// --- code ends --- /// > > Line 12 yields an assertion error, while line 11 does not. > This tells me, that despite the fact the types MyEA and MyEB are > different they still share the static array, which would contradict the > definition of static. > > I suppose, the tricky thing is to tweak the init property of the > typedefs in lines 26/27 to avoid this clash. How to manage this? Ali
Re: typedef behavior
On 02/09/2018 03:45 PM, Alex wrote: > A question about Typedef usage: > Say, I have the following circumstances > > /// --- code --- /// > > import std.typecons; > > void main() > { > MyEA ea; > MyEB eb; > ea.tarr.length = 5; > static assert(!is(MyEA == MyEB)); > static assert(!is(MyEA == E)); > static assert(!is(MyEB == E)); > assert(ea.tarr.length == eb.tarr.length); // line 11 > assert(ea.tarr.length != eb.tarr.length); // line 12 You must have meant assert(ea.tarr.ptr != eb.tarr.ptr); // line 12 Indeed, .ptr are unexpectedly the same. > } > > struct T > { > size_t i; > } > > struct E > { > size_t i; > static T[] tarr; To save time to others, note that 'tarr' is a static member that ends up being shared by two Typedef instantiations. > } > > alias MyEA = Typedef!(E, E.init, "A"); // line 26 > alias MyEB = Typedef!(E, E.init, "B"); // line 27 > > /// --- code ends --- /// > > Line 12 yields an assertion error, while line 11 does not. > This tells me, that despite the fact the types MyEA and MyEB are > different they still share the static array, which would contradict the > definition of static. > > I suppose, the tricky thing is to tweak the init property of the > typedefs in lines 26/27 to avoid this clash. How to manage this? Ali
typedef behavior
A question about Typedef usage: Say, I have the following circumstances /// --- code --- /// import std.typecons; void main() { MyEA ea; MyEB eb; ea.tarr.length = 5; static assert(!is(MyEA == MyEB)); static assert(!is(MyEA == E)); static assert(!is(MyEB == E)); assert(ea.tarr.length == eb.tarr.length); // line 11 assert(ea.tarr.length != eb.tarr.length); // line 12 } struct T { size_t i; } struct E { size_t i; static T[] tarr; } alias MyEA = Typedef!(E, E.init, "A"); // line 26 alias MyEB = Typedef!(E, E.init, "B"); // line 27 /// --- code ends --- /// Line 12 yields an assertion error, while line 11 does not. This tells me, that despite the fact the types MyEA and MyEB are different they still share the static array, which would contradict the definition of static. I suppose, the tricky thing is to tweak the init property of the typedefs in lines 26/27 to avoid this clash. How to manage this?
Re: Error in template instantiation from D-Cookbook example
On Friday, 9 February 2018 at 21:39:22 UTC, Adam D. Ruppe wrote: On Friday, 9 February 2018 at 21:31:29 UTC, ShadoLight wrote: [1] https://run.dlang.io/is/dyElXg There's missing quotes in there: Line 14: code ~= "push(call!"~piece~"(pop(), pop()));\n"; Should be: code ~= "push(call!\""~piece~"\"(pop(), pop()));\n"; [snip] On Friday, 9 February 2018 at 21:58:51 UTC, Meta wrote: On Friday, 9 February 2018 at 21:31:29 UTC, ShadoLight wrote: [snip] The problem becomes apparent once you uncomment one of these and paste the offending string ("5 5 + 3 - 2 * 1 + 3 /") in. [snip] push(call!+(pop(), pop())); [snip] So it takes a string as its sole template argument. The problem is that the code in convertToD forgot to add the quotes around the operators that are supposed to be passed as strings to call. [snip] Indeed, that makes sense! Thanks to you both! Adam, you are right - it was indeed incorrectly mangled... it is shown as... code ~= "push(call!'"~piece~"'(pop(), pop()));\n"; So the escaped quotes \" were mangled as '. I simply removed them since I assumed they were typos in the doc, similar to the other ones I had fixed. My bad. Man, I cannot believe how quickly you guys answered. Thanks again!
Re: Error in template instantiation from D-Cookbook example
On Friday, 9 February 2018 at 21:31:29 UTC, ShadoLight wrote: writeln(parse(code)); // to aid with debugging writeln(convertToD(parse(code))); // debugging aid ..to.. writeln(parse(code)[]); // to aid with debugging writeln(convertToD(parse(code))[]); // debugging aid The problem becomes apparent once you uncomment one of these and paste the offending string ("5 5 + 3 - 2 * 1 + 3 /") in. `writeln(convertToD(parse("5 5 + 3 - 2 * 1 + 3 /"))[]);` prints the following: push(5); push(5); push(call!+(pop(), pop())); push(3); push(call!-(pop(), pop())); push(2); push(call!*(pop(), pop())); push(1); push(call!+(pop(), pop())); push(3); push(call!/(pop(), pop())); If you look at the definition of call: int call(string op)(int a, int b) { return mixin("b"~op~"a"); } So it takes a string as its sole template argument. The problem is that the code in convertToD forgot to add the quotes around the operators that are supposed to be passed as strings to call. If you modify line 14 from the example you pasted to add these quotes to the mixin string, it works: code ~= "push(call!"~piece~"(pop(), pop()));\n"; becomes code ~= "push(call!\""~piece~"\"(pop(), pop()));\n"; Running the modified code, it prints: push(5); push(5); push(call!"+"(pop(), pop())); push(3); push(call!"-"(pop(), pop())); push(2); push(call!"*"(pop(), pop())); push(1); push(call!"+"(pop(), pop())); push(3); push(call!"/"(pop(), pop())); And `runDslCode!"5 5 + 3 - 2 * 1 + 3 /"();` prints `[5]`.
Re: Error in template instantiation from D-Cookbook example
On Friday, 9 February 2018 at 21:31:29 UTC, ShadoLight wrote: [1] https://run.dlang.io/is/dyElXg There's missing quotes in there: Line 14: code ~= "push(call!"~piece~"(pop(), pop()));\n"; Should be: code ~= "push(call!\""~piece~"\"(pop(), pop()));\n"; That might have been an error in the original book. A lot of quotes and semicolons got mangled in the process of copying them from the actual compilable examples into the MS Word manuscript.. But to explain why this is wrong just consider the code generated: push(call!+(pop(), pop())); When the operator is pasted in without quotes, you get the above. And + isn't a valid template arg. But "+" is.
Error in template instantiation from D-Cookbook example
Hi, Trying to improve my CT-fu, I looked at a DSL example (chapter 9) in Adam's D-Cookbook. Although I am sure Adam's original examples would have worked, there were some errors in the example code in the book. The example also contains some code to allow you to test the functions at RT, which had an error i.e. I had to change this... writeln(parse(code)); // to aid with debugging writeln(convertToD(parse(code))); // debugging aid ..to.. writeln(parse(code)[]); // to aid with debugging writeln(convertToD(parse(code))[]); // debugging aid ..to match the actual function arguments. So that worked fine. However I could not get the CT version to work with the current version of DMD i.e. this [1]... [1] https://run.dlang.io/is/dyElXg ...fails with: onlineapp.d-mixin-36(38): Error: template argument expected following ! onlineapp.d(48): Error: template instance onlineapp.runDslCode!"5 5 + 3 - 2 * 1 + 3 /" error instantiating. I find the error message a bit lacking as to the real cause - I really cannot see where the "template argument expected following !" error is. It all looks correct to me. In addition the RT version is working correctly (after fixing the above bug), so that is not helping in identifying the error - particularly since it is failing in the only CT specific function not used/called at RT. So I am not sure how to debug this. Can somebody please put me out of my misery here? Thx!
Re: Elegant way to use dynamic bindings
On Friday, 9 February 2018 at 18:14:06 UTC, Mike Wey wrote: You may need to pass `/s` to implib so it will add the underscore to the symbol in the import library. If it's actually needed depends on what the dll uses. That did it, now both dynamic loading and dynamic linking work. :) Thanks both of you. I'd still like to find a nice way to generate the boilerplate code for dynamic loading, if I come up with something I'll post it here.
Re: Debugging on Windows
On Thursday, 8 February 2018 at 21:09:33 UTC, JN wrote: Hi, is there any way to debug binaries on Windows? I'd at least like to know which line of code made it crash. If it's D code, I get a call trace usually, but if it's a call to a C library, I get a crash and that's it. I am using VSCode and I'd prefer to debug in it if possible, but using other IDEs is a possibility for me if that will help. The best option most likely is to get the Visual Studio Community Edition and then Install the VisualD extension for Visual Studio. This will give you a very good debugging experience with a bulitin D expression evaulator and the usual features the very good Visual Studio debugger comes with. Kind Regards Benjamin Thaut
Re: Elegant way to use dynamic bindings
On 09-02-18 15:04, Dennis wrote: I read the Derelict documentation a while ago, I didn't grasp all of it. Reading it again, I can now make sense of it though. :) On Friday, 9 February 2018 at 12:53:44 UTC, Mike Parker wrote: Did you link with the library you created with implib? That linker error suggests you didn't. I added `pragma(lib, "mupen64plus.lib");` above the extern(C) block. Adding `libs "mupen64plus"` to dub.sdl doesn't make a difference. The thing that confuses me is that the import lib has symbols without underscore prefix (I see them when running `libunres -p mupen64plus.lib`), but when I change the function pointer declaration into a function declaration it tries to link "_CoreGetAPIVersions" and can't find it. I put the .dll's in the root of the project directory by the way. Does that count as a "system library search path"? You may need to pass `/s` to implib so it will add the underscore to the symbol in the import library. If it's actually needed depends on what the dll uses. -- Mike Wey
Re: Debugging bad requests with vibe
On Fri, 09 Feb 2018 15:48:54 +, Nicholas Wilson wrote: > On Friday, 9 February 2018 at 08:06:53 UTC, Seb wrote: >> On Thursday, 8 February 2018 at 17:09:44 UTC, Nicholas Wilson wrote: >>> Is there a way I can see/log what requests are being made? I can >>> change both the client and server. >> >> -v and -vv > > So it turns out that structs do not work as parameters TO rest interface > functions. > > https://github.com/vibe-d/vibe.d/issues/2067 I have a project doing this; I think I solved that (or something) with: ``` @path("/api/") interface RestAPI { // stuff } ``` I cannot reproduce your problem with that code though to see if it will work.
Re: uint[3] not equivalent to void[12]?
On Fri, Feb 09, 2018 at 03:05:33PM +, Ralph Doncaster via Digitalmars-d-learn wrote: > This seems odd to me. Is there a way I can make a function that takes > an array of any type but only of a specific size in bytes? > > void.d(8): Error: function void.foo (void[12] arr) is not callable > using argument types (uint[3]) > Failed: ["/usr/bin/dmd", "-v", "-o-", "void.d", "-I."] > void foo(void [12] arr) > { > } > > void main() > { > uint[3] arr; > foo(arr); > } You probably didn't mean to pass a static array, because those are passed by value and may entail unnecessary copying. (Though in this case, if you're only expecting 12 bytes, that's not that big of a difference.) But in any case, probably something like this would do: void foo(void[] arr) in { assert(arr.length == 12); } do { ... } T -- If creativity is stifled by rigid discipline, then it is not true creativity.
Re: uint[3] not equivalent to void[12]?
On Friday, 9 February 2018 at 16:28:50 UTC, Nicholas Wilson wrote: On Friday, 9 February 2018 at 15:50:24 UTC, Ralph Doncaster wrote: Is there a way I can make a function that takes an array of any type but only of a specific size in bytes? With a template that constrains the types size: void foo(T)(T t) if (T.sizeof == 12) { //... } alternately reject incorrect values at runtime void foo(ubyte[] t) in { assert(t.length == 12); } do { //... } Thanks. That's what I thought. If I stick with using D, I'll probably go with the runtime check.
Re: uint[3] not equivalent to void[12]?
On Friday, 9 February 2018 at 15:50:24 UTC, Ralph Doncaster wrote: On Friday, 9 February 2018 at 15:24:27 UTC, Mike Parker wrote: On Friday, 9 February 2018 at 15:05:33 UTC, Ralph Doncaster wrote: This seems odd to me. Is there a way I can make a function that takes an array of any type but only of a specific size in bytes? void.d(8): Error: function void.foo (void[12] arr) is not callable using argument types (uint[3]) Failed: ["/usr/bin/dmd", "-v", "-o-", "void.d", "-I."] void foo(void [12] arr) { } void main() { uint[3] arr; foo(arr); } void has no size, so what does it mean to have 12 of them? according to the docs and my testing, the size of a void array element is 1, Correct. so the following code prints 12: import std.stdio; void foo(void [] arr) { writeln("length: " arr.length); } void main() { uint[3] arr; foo(arr); } I thought about using templates, but I was looking for a simple way of making a function that takes an array of 12 bytes, whether it is uint[3], ubyte[12], or ushort[6]. uint[3] and void[12] have the same size but are different types so the compiler will reject it. you can reinterpret cast them(i.e. *cast(void[12])() ), but this is a rather blunt tool. Is it safe in the case that the types size is at least 12 but not safe in general. Is there a way I can make a function that takes an array of any type but only of a specific size in bytes? With a template that constrains the types size: void foo(T)(T t) if (T.sizeof == 12) { //... } alternately reject incorrect values at runtime void foo(ubyte[] t) in { assert(t.length == 12); } do { //... }
Re: uint[3] not equivalent to void[12]?
On Friday, 9 February 2018 at 15:24:27 UTC, Mike Parker wrote: On Friday, 9 February 2018 at 15:05:33 UTC, Ralph Doncaster wrote: This seems odd to me. Is there a way I can make a function that takes an array of any type but only of a specific size in bytes? void.d(8): Error: function void.foo (void[12] arr) is not callable using argument types (uint[3]) Failed: ["/usr/bin/dmd", "-v", "-o-", "void.d", "-I."] void foo(void [12] arr) { } void main() { uint[3] arr; foo(arr); } void has no size, so what does it mean to have 12 of them? according to the docs and my testing, the size of a void array element is 1, so the following code prints 12: import std.stdio; void foo(void [] arr) { writeln("length: " arr.length); } void main() { uint[3] arr; foo(arr); } I thought about using templates, but I was looking for a simple way of making a function that takes an array of 12 bytes, whether it is uint[3], ubyte[12], or ushort[6].
Re: Debugging bad requests with vibe
On Friday, 9 February 2018 at 08:06:53 UTC, Seb wrote: On Thursday, 8 February 2018 at 17:09:44 UTC, Nicholas Wilson wrote: Is there a way I can see/log what requests are being made? I can change both the client and server. -v and -vv So it turns out that structs do not work as parameters TO rest interface functions. https://github.com/vibe-d/vibe.d/issues/2067
Re: Elegant way to use dynamic bindings
On Friday, 9 February 2018 at 14:51:30 UTC, Mike Parker wrote: Where was the lib file located? Was it in the root project directory? How are you compiling your project? What does your directory tree look like? (...) That depends. Is that the directory where your executable is written? Are you launching it from inside an Visual Studio or from the command line? Normally, the executable's directory is on the system path, but when using VS the default configuration is to write the executables into configuration-specific subdirectories. I use `dub run` from cmd or Mono-D. All .exe, .lib and .dll files are in the root. Source files are in the subdirectory 'source'. I tried to reduce the problem by making a simple test folder containing the necessary .dll files, import library and source files: freetype6.dll libpng12.dll libpng3.dll main.d main.exe main.obj mupen64plus-audio-sdl.dll mupen64plus-input-sdl.dll mupen64plus-rsp-hle.dll mupen64plus-video-glide64mk2.dll mupen64plus-video-rice.dll mupen64plus.dll mupen64plus.lib SDL.dll zlib1.dll Where main.d is: ``` import std.stdio; version(dynamiclink) { pragma(lib, "mupen64plus.lib"); extern(C) nothrow @nogc { int CoreGetAPIVersions(int*, int*, int*, int*); } int main() { int a, b, c, d; CoreGetAPIVersions(, , , ); writeln("Version: ", a, " - ", b, " - ", c, " - ", d); return 0; } } version(dynamicload) { import core.sys.windows.windows: LoadLibrary, GetProcAddress, GetLastError; extern(C) alias p_CoreGetAPIVersions = int function(int*, int*, int*, int*); p_CoreGetAPIVersions CoreGetAPIVersions; int main() { auto handle = LoadLibrary("mupen64plus.dll"); CoreGetAPIVersions = cast(p_CoreGetAPIVersions) GetProcAddress(handle, "CoreGetAPIVersions"); int a, b, c, d; CoreGetAPIVersions(, , , ); writeln("Version: ", a, " - ", b, " - ", c, " - ", d); return 0; } } ``` With `dmd main.d -version=dynamicload` it works, but with `dmd main.d -version=dynamiclink` it still gives this: main.obj(main) Error 42: Symbol Undefined _CoreGetAPIVersions Error: linker exited with status 1
Re: uint[3] not equivalent to void[12]?
On Friday, 9 February 2018 at 15:24:27 UTC, Mike Parker wrote: import std.stdio; enum numBytes = 12; void foo(T, size_t N)(T[N] arr) if((N * T.sizeof) == numBytes) { writeln(arr); } void bar(ubyte[12] arr) { writeln(arr); } Also, it's worth mentioning in case you aren't aware that this can be expensive, depending on the size of the array. Static arrays are passed by value. You may want to make the arr parameters ref or, if you want to protect the contents, const ref: void foo(T, size_t N)(ref const(T)[N] arr)
Re: uint[3] not equivalent to void[12]?
On Friday, 9 February 2018 at 15:05:33 UTC, Ralph Doncaster wrote: This seems odd to me. Is there a way I can make a function that takes an array of any type but only of a specific size in bytes? void.d(8): Error: function void.foo (void[12] arr) is not callable using argument types (uint[3]) Failed: ["/usr/bin/dmd", "-v", "-o-", "void.d", "-I."] void foo(void [12] arr) { } void main() { uint[3] arr; foo(arr); } void has no size, so what does it mean to have 12 of them? Here are a couple of options, depending on what you need. import std.stdio; enum numBytes = 12; void foo(T, size_t N)(T[N] arr) if((N * T.sizeof) == numBytes) { writeln(arr); } void bar(ubyte[12] arr) { writeln(arr); } void main() { uint[3] arr = [20, 10, 1]; foo(arr); bar(cast(ubyte[12])arr); } === Output: [20, 10, 1] [20, 0, 0, 0, 10, 0, 0, 0, 1, 0, 0, 0]
uint[3] not equivalent to void[12]?
This seems odd to me. Is there a way I can make a function that takes an array of any type but only of a specific size in bytes? void.d(8): Error: function void.foo (void[12] arr) is not callable using argument types (uint[3]) Failed: ["/usr/bin/dmd", "-v", "-o-", "void.d", "-I."] void foo(void [12] arr) { } void main() { uint[3] arr; foo(arr); }
Re: Elegant way to use dynamic bindings
On Friday, 9 February 2018 at 14:04:05 UTC, Dennis wrote: I added `pragma(lib, "mupen64plus.lib");` above the extern(C) block. Adding `libs "mupen64plus"` to dub.sdl doesn't make a difference. Where was the lib file located? Was it in the root project directory? How are you compiling your project? What does your directory tree look like? The thing that confuses me is that the import lib has symbols without underscore prefix (I see them when running `libunres -p mupen64plus.lib`), but when I change the function pointer declaration into a function declaration it tries to link "_CoreGetAPIVersions" and can't find it. Yes, the underscore is normally prepended to cdecl functions on Windows. It makes no difference if your function prototypes are properly declared. I put the .dll's in the root of the project directory by the way. Does that count as a "system library search path"? That depends. Is that the directory where your executable is written? Are you launching it from inside an Visual Studio or from the command line? Normally, the executable's directory is on the system path, but when using VS the default configuration is to write the executables into configuration-specific subdirectories.
Re: Elegant way to use dynamic bindings
I read the Derelict documentation a while ago, I didn't grasp all of it. Reading it again, I can now make sense of it though. :) On Friday, 9 February 2018 at 12:53:44 UTC, Mike Parker wrote: Did you link with the library you created with implib? That linker error suggests you didn't. I added `pragma(lib, "mupen64plus.lib");` above the extern(C) block. Adding `libs "mupen64plus"` to dub.sdl doesn't make a difference. The thing that confuses me is that the import lib has symbols without underscore prefix (I see them when running `libunres -p mupen64plus.lib`), but when I change the function pointer declaration into a function declaration it tries to link "_CoreGetAPIVersions" and can't find it. I put the .dll's in the root of the project directory by the way. Does that count as a "system library search path"?
Re: Debugging bad requests with vibe
On Friday, 9 February 2018 at 11:46:31 UTC, Nicholas Wilson wrote: On Friday, 9 February 2018 at 08:06:53 UTC, Seb wrote: On Thursday, 8 February 2018 at 17:09:44 UTC, Nicholas Wilson wrote: Is there a way I can see/log what requests are being made? I can change both the client and server. -v and -vv All that gives me is a bunch of [FAC3BFF6:FAC451F6 dia] Actively closing TCP connection is there a way to get the JSON being sent? Try Fiddler, great tool too
Re: Elegant way to use dynamic bindings
On Friday, 9 February 2018 at 12:15:04 UTC, Dennis wrote: I presume the .dll isn't loaded properly (if at all), but I can't find a load function in the .lib and don't know how to debug this. So I guess I'll just do it manually since that works, but does anyone have some tips to make .dll bindings elegantly? I suggest you read this first: http://derelictorg.github.io/bindings/ It explains the difference between dynamic bindings and static bindings. The important thing to understand is that both types can be used with DLLs, but only static bindings can be use with static libraries. Dynamic bindings have no link time dependency on the DLL and the DLL must be loaded manually. Static bindings have a link time dependency and can be linked with either a static library, an import library (on Windows -- what you get when you run implib or compile a DLL yourself), or directly with a shared object (.so) on non-Windows systems (and probably .dylib/Frameworks on Mac). Dynamic bindings use function pointer because that's the only way to do manuall loading. For static bindings, you use normal function declarations and the OS will load the DLL automatically when the app starts up (dynamic loading) if you've linked to an import library or .so, and, of course, will load nothing if you've linked to a static library. Some Derelict packages, like DerelictSDL2 and DerelictGLFW3, support both dynamic and static binding. For the former, the function pointer declarations and the loader are all in [1]. For the latter, there is no loader and the declarations are all in [2]. [1] https://github.com/DerelictOrg/DerelictGLFW3/blob/master/source/derelict/glfw3/dynload.d [2] https://github.com/DerelictOrg/DerelictGLFW3/blob/master/source/derelict/glfw3/statfun.d So if you don't need to load manually and don't mind the link-time dependency on the C library, then you can use normal function declarations in your binding: extern(C) @nogc nothrow { void foo(); }
Re: Elegant way to use dynamic bindings
On Friday, 9 February 2018 at 12:15:04 UTC, Dennis wrote: I found the IMPLIB tool (http://www.digitalmars.com//ctg/implib.html) and made a .lib for the .dll and at first I got: Error 42: Symbol Undefined _CoreGetAPIVersions Error: linker exited with status 1 Forgot to address this in the previous post. Did you link with the library you created with implib? That linker error suggests you didn't.
Elegant way to use dynamic bindings
I want to bind to a .dll on Windows, so I looked at how Derelict packages are doing it and found it does it like this: ``` extern(C) { alias da_CoreGetAPIVersions = m64p_error function(int*,int*,int*,int*); ... } __gshared { da_CoreGetAPIVersions CoreGetAPIVersions; ... } protected override void loadSymbols() { bindFunc(cast(void**),"CoreGetAPIVersions"); ... ``` I don't like how each function name is repeated 4 times. Preferably, I'd write it like a static library: ``` extern(C) { ///documentation m64p_error CoreGetAPIVersions(int*,int*,int*,int*); } ``` And then use some reflection and mixins to make it work for dynamic bindings. I found the IMPLIB tool (http://www.digitalmars.com//ctg/implib.html) and made a .lib for the .dll and at first I got: Error 42: Symbol Undefined _CoreGetAPIVersions Error: linker exited with status 1 So apparently, you got to bind functions pointers, not functions. ``` extern(C) { ///documentation m64p_error function(int*,int*,int*,int*) CoreGetAPIVersions; } ``` But then I get: object.Error@(0): Access Violation I presume the .dll isn't loaded properly (if at all), but I can't find a load function in the .lib and don't know how to debug this. So I guess I'll just do it manually since that works, but does anyone have some tips to make .dll bindings elegantly?
Re: Debugging bad requests with vibe
On Friday, 9 February 2018 at 11:46:31 UTC, Nicholas Wilson wrote: On Friday, 9 February 2018 at 08:06:53 UTC, Seb wrote: On Thursday, 8 February 2018 at 17:09:44 UTC, Nicholas Wilson wrote: Is there a way I can see/log what requests are being made? I can change both the client and server. -v and -vv All that gives me is a bunch of [FAC3BFF6:FAC451F6 dia] Actively closing TCP connection is there a way to get the JSON being sent? Wireshark?
Re: Debugging bad requests with vibe
On Thursday, 8 February 2018 at 20:24:19 UTC, Nicholas Wilson wrote: On Thursday, 8 February 2018 at 17:09:44 UTC, Nicholas Wilson wrote: I have set up a vibe.d rest interface (on a server) and have a client on my machine. struct Observation { string desc; DateTime time; } interface Obsever { @property void observe(Observation ra); } void main() { auto test = Observation("a duck", cast(DateTime)Clock.currTime(UTC())); auto client = new RestInterfaceClient! Obsever("http://example.com/observation;); client. observe = test; // 400 } I' pretty sure the url is correct because other ones give 404. Is there a way I can see/log what requests are being made? I can change both the client and server. Never mind, it was because I was accidentally shadowing that path with a get on the server. Hmm, nope it wasn't that.
Re: Debugging bad requests with vibe
On Friday, 9 February 2018 at 08:06:53 UTC, Seb wrote: On Thursday, 8 February 2018 at 17:09:44 UTC, Nicholas Wilson wrote: Is there a way I can see/log what requests are being made? I can change both the client and server. -v and -vv All that gives me is a bunch of [FAC3BFF6:FAC451F6 dia] Actively closing TCP connection is there a way to get the JSON being sent?
Re: Debugging on Windows
On Thursday, 8 February 2018 at 21:09:33 UTC, JN wrote: Hi, is there any way to debug binaries on Windows? I'd at least like to know which line of code made it crash. If it's D code, I get a call trace usually, but if it's a call to a C library, I get a crash and that's it. I am using VSCode and I'd prefer to debug in it if possible, but using other IDEs is a possibility for me if that will help. You can debug D programs from VS Code using the C++ plugin: https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools It requires some configuring, but from what I remember it was all very straightforward.
Re: Debugging bad requests with vibe
On Thursday, 8 February 2018 at 17:09:44 UTC, Nicholas Wilson wrote: Is there a way I can see/log what requests are being made? I can change both the client and server. -v and -vv