Re: Translating C headers to D: How do I compile it?
On Sunday, 28 June 2020 at 04:59:12 UTC, Kirill wrote: Hello. I am learning how to translate C headers to D. But how do I compile it? I am stuck with this. You can try just to use dpp: https://code.dlang.org/packages/dpp instead of doing the translation manually.
Re: Translating C headers to D: How do I compile it?
On 28/06/2020 4:59 PM, Kirill wrote: module something; extern(C) int add(int a, int b); Compile as static library some.c, add to command line of dmd. Should be this simple more or less, depending on compilers and target involved.
Re: Translating C headers to D: How do I compile it?
On Sunday, 28 June 2020 at 04:59:12 UTC, Kirill wrote: Hello. I am learning how to translate C headers to D. But how do I compile it? I am stuck with this. I have 4 files in the same directory: main.d, something.d, some.h, some.c some.h: //header guards int add(int a, int b); some.c: #include "some.h" int add(int a, int b) { return a+b; } something.d: module something; int add(int a, int b); This should be extern(C) int add(int a, int b). The extern(C) tells the D compiler to use the standard C calling convention when calling that function. main.d: import std.stdio: writeln; import something; void main() { writeln("5+7=", add(5, 7); } How do I compile this correctly? Thank you for your time. The C file and the header do not need to be (and arguably shouldn't be) in the same directory as the D files. Use a C compiler to compile the C file to an object file or into a static library. Assuming you're using DMD, then on Windows you'll want to use the Microsoft compiler (cl) which is part of the Microsoft Build Tools distribution and Visual Studio. Otherwise, you'll need the Digital Mars C and C++ compiler. On other platforms, GCC or clang will be fine. If you don't know how to compile C programs, there's plenty of information online for all the major compilers. Then, when you compile your D program, you'll need to link with the object file or the static library you compiled with the C compiler. On Windows, if you used Digital Mars C (dmc), then you won't need to pass any special compiler flags if you are calling DMD directly. If you used the MS compiler, you'll need to pass either -m32mscoff for 32-bit, or -m64 for 64-bit.
Translating C headers to D: How do I compile it?
Hello. I am learning how to translate C headers to D. But how do I compile it? I am stuck with this. I have 4 files in the same directory: main.d, something.d, some.h, some.c some.h: //header guards int add(int a, int b); some.c: #include "some.h" int add(int a, int b) { return a+b; } something.d: module something; int add(int a, int b); main.d: import std.stdio: writeln; import something; void main() { writeln("5+7=", add(5, 7); } How do I compile this correctly? Thank you for your time.
Re: foreach iterator with closure
On 6/27/20 8:19 PM, Denis wrote: > Is it possible to write an iterator It is arguable whether D's ranges are iterators but if nouns are useful, we call them ranges. :) (Iterators can be written in D as well and then it would really be confusing.) >struct letters { > string str; > int pos = 0; > char front() { return str[pos]; } > void popFront() { pos ++; } > bool empty() { >if (pos == 0) writeln(`BEGIN`); >else if (pos == str.length) writeln("\nEND"); >return pos == str.length; }} > >void main() { > foreach (letter; letters(`hello`)) { >write(letter, ' '); } > writeln(); } > > The obvious problems with this code include: > > (1) The user can pass a second argument, which will set the initial > value of pos. That problem can be solved by a constructor that takes a single string. Your BEGIN code would normally go there as well. And END goes into the destructor: struct letters { this(string str) { this.str = str; this.pos = 0; // Redundant writeln(`BEGIN`); } ~this() { writeln("\nEND"); } // [...] } Note: You may want to either disallow copying of your type or write copy constructor that does the right thing: https://dlang.org/spec/struct.html#struct-copy-constructor However, it's common to construct a range object by a function. The actual range type can be kept as an implementation detail: struct Letters { // Note capital L // ... } auto letters(string str) { // ... return Letters(str); } struct Letter can be a private type of its module or even a nested struct inside letters(), in which case it's called a "Voldemort type". Ali
foreach iterator with closure
Is it possible to write an iterator that does the following, using a struct and some functions? - Operates in a foreach loop - Has BEGIN-like and END-like blocks or functions that are executed automatically, before and after the iterations - Initializes variables in the BEGIN block that are used in the other two. These variables are for internal use only, i.e. must not be accessible to the user of the foreach loop I'd like to use the simplest solution while keeping the code clean. As a starting point, here's a contrived example using a struct with a range-style iterarator: import std.stdio; struct letters { string str; int pos = 0; char front() { return str[pos]; } void popFront() { pos ++; } bool empty() { if (pos == 0) writeln(`BEGIN`); else if (pos == str.length) writeln("\nEND"); return pos == str.length; }} void main() { foreach (letter; letters(`hello`)) { write(letter, ' '); } writeln(); } The obvious problems with this code include: (1) The user can pass a second argument, which will set the initial value of pos. This must not be allowed. (The real code will need to initialize a half dozen internal-only variables, and do some additional work, before the looping starts.) (2) Sticking the code for the BEGIN and END blocks into the empty() function is ugly. Can this iterator be written using a range-style struct? Or is something more complicated needed, like an OO solution? I should add that the final version of this will be put in a separate module, possibly in a library, so I can call it from many programs. Not sure if that might help simplify things. Thanks for your guidance.
Re: mixin template compile-time compute declared name
On Saturday, 27 June 2020 at 21:23:10 UTC, Adam D. Ruppe wrote: On Saturday, 27 June 2020 at 21:10:59 UTC, NonNull wrote: Is it possible to use a template to declare something whose name is computed at compile time? You'd have to string mixin the contents inside the mixin template. Worked! Thank you!!
Re: mixin template compile-time compute declared name
On Saturday, 27 June 2020 at 21:10:59 UTC, NonNull wrote: Is it possible to use a template to declare something whose name is computed at compile time? You'd have to string mixin the contents inside the mixin template.
mixin template compile-time compute declared name
Want mixin mytemplate!("foo", .); to be able to declare names dependent upon the text foo in the context it is used. For example declaring enum x_foo = ; blah foo_value = ; . . . . Is it possible to use a template to declare something whose name is computed at compile time?
Re: How to send ownerTid into a parallel foreach loop?
On Saturday, 27 June 2020 at 07:51:21 UTC, adnan338 wrote: On Saturday, 27 June 2020 at 07:31:56 UTC, Kagamin wrote: std.concurrency is for noninteractive appications, the approach with gui timer was the correct one. Thank you. That works but my progress bar is sometimes getting stuck because of a possible data race. See https://forum.dlang.org/post/gacweulvbyorkseti...@forum.dlang.org Sometimes? In that code you write the progress variable only once, so it doesn't change after that. Nothing else can possibly happen there with or without multithreading.
Re: Garbage collection
On Saturday, 27 June 2020 at 14:49:34 UTC, James Gray wrote: On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote: [...] Thank you for doing this. I hope my example doesn't obscure what you show here. (I borrowed some of your code). [...] In case it helps, setting all the next and previous pointers in the link list to null allows the garbage collector to collect in the above code.
Re: Garbage collection
On Saturday, 27 June 2020 at 16:03:12 UTC, kinke wrote: On Saturday, 27 June 2020 at 15:27:34 UTC, Stanislav Blinov wrote: Hrm... What happens if you call collect() twice? Nothing changes, even when collecting 5 times at the end of each iteration. In the filed testcase, I've extracted the stack ref to a dedicated function, so that there really shouldn't be any refs on the stack (this is unoptimized code after all...). Here on Linux, the double collection results in this output: GC stats: 0M used, 0M free, 0M total Starting string size: 943M GC stats: 0M used, 2306M free, 2306M total Starting string size: 943M GC stats: 0M used, 2306M free, 2306M total Starting string size: 943M GC stats: 0M used, 2306M free, 2306M total Starting string size: 943M GC stats: 0M used, 2306M free, 2306M total
Re: Garbage collection
On Saturday, 27 June 2020 at 15:27:34 UTC, Stanislav Blinov wrote: On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote: Note that I explicitly clear the `str` slice before GC.collect(), so that the stack shouldn't contain any refs to the fat string anymore. Hrm... What happens if you call collect() twice? Nothing changes, even when collecting 5 times at the end of each iteration. In the filed testcase, I've extracted the stack ref to a dedicated function, so that there really shouldn't be any refs on the stack (this is unoptimized code after all...).
Re: Garbage collection
On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote: Note that I explicitly clear the `str` slice before GC.collect(), so that the stack shouldn't contain any refs to the fat string anymore. Hrm... What happens if you call collect() twice?
Re: Garbage collection
On Saturday, 27 June 2020 at 14:12:09 UTC, kinke wrote: On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote: have run into a memory leak Something seems really off indeed. I've run this on Win64 with DMD (2.092) and LDC (1.22), without any extra cmdline options: - import core.memory; import core.stdc.stdio; import std.range; import std.format; auto f(R)(R r) { return format("%s", r); } int toMB(ulong size) { return cast(int) (size / 1048576.0 + 0.5); } void printGCStats() { const stats = GC.stats; const used = toMB(stats.usedSize); const free = toMB(stats.freeSize); const total = toMB(stats.usedSize + stats.freeSize); printf(" GC stats: %dM used, %dM free, %dM total\n", used, free, total); } void main() { printGCStats(); while (true) { puts("Starting"); string str = f(iota(100_000_000)); printf(" string size: %dM\n", toMB(str.length)); str = null; GC.collect(); printGCStats(); } } - Output with DMD (no change with the precise GC via `--DRT-gcopt=gc:precise`): - GC stats: 0M used, 1M free, 1M total Starting string size: 943M GC stats: 1168M used, 1139M free, 2306M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total - With LDC: - GC stats: 0M used, 1M free, 1M total Starting string size: 943M GC stats: 1168M used, 1139M free, 2306M total Starting string size: 943M GC stats: 2335M used, 1288M free, 3623M total Starting string size: 943M GC stats: 2335M used, 2605M free, 4940M total Starting string size: 943M GC stats: 2335M used, 2605M free, 4940M total Starting string size: 943M GC stats: 2335M used, 2605M free, 4940M total - Note that I explicitly clear the `str` slice before GC.collect(), so that the stack shouldn't contain any refs to the fat string anymore. Thank you for doing this. I hope my example doesn't obscure what you show here. (I borrowed some of your code). I have produced something which essentially reproduces my problem. --- import std.range; import std.algorithm; import std.format; import std.stdio; import core.thread; import core.memory; struct Node { Node* next; Node* prev; ulong val; } Node* insertAfter(Node* cur, ulong val) { Node* node = new Node; if (cur != null) { node.next = cur.next; node.prev = cur; cur.next = node; node.next.prev = node; } else { node.next = node; node.prev = node; } node.val = val; return node; } int toMB(ulong size) { return cast(int) (size / 1048576.0 + 0.5); } void printGCStats() { const stats = GC.stats; const used = toMB(stats.usedSize); const free = toMB(stats.freeSize); const total = toMB(stats.usedSize + stats.freeSize); writef(" GC stats: %dM used, %dM free, %dM total\n", used, free, total); } void main() { while(true) { printGCStats(); writeln("Starting"); Node* dll; dll = iota(2).fold!((c,x)=>insertAfter(c,x))(dll); writef("Last element %s\n", dll.val); dll = null; writeln("Done"); GC.collect(); GC.minimize(); Thread.sleep( dur!("msecs")( 1 ) ); } } -- With DMD this produces: GC stats: 0M used, 0M free, 0M total Starting Last element 1 Done GC stats: 6104M used, 51M free, 6155M total Starting Last element 1 Done GC stats: 12207M used, 28M free, 12235M total With LDC2 this produces: GC stats: 0M used, 0M free, 0M total Starting Last element 1 Done GC stats: 6104M used, 51M free, 6155M total Starting Last element 1 Done GC stats: 12207M used, 28M free, 12235M total
Re: Garbage collection
=> https://issues.dlang.org/show_bug.cgi?id=20983
Re: Garbage collection
On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote: have run into a memory leak Something seems really off indeed. I've run this on Win64 with DMD (2.092) and LDC (1.22), without any extra cmdline options: - import core.memory; import core.stdc.stdio; import std.range; import std.format; auto f(R)(R r) { return format("%s", r); } int toMB(ulong size) { return cast(int) (size / 1048576.0 + 0.5); } void printGCStats() { const stats = GC.stats; const used = toMB(stats.usedSize); const free = toMB(stats.freeSize); const total = toMB(stats.usedSize + stats.freeSize); printf(" GC stats: %dM used, %dM free, %dM total\n", used, free, total); } void main() { printGCStats(); while (true) { puts("Starting"); string str = f(iota(100_000_000)); printf(" string size: %dM\n", toMB(str.length)); str = null; GC.collect(); printGCStats(); } } - Output with DMD (no change with the precise GC via `--DRT-gcopt=gc:precise`): - GC stats: 0M used, 1M free, 1M total Starting string size: 943M GC stats: 1168M used, 1139M free, 2306M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total Starting string size: 943M GC stats: 1168M used, 2456M free, 3623M total - With LDC: - GC stats: 0M used, 1M free, 1M total Starting string size: 943M GC stats: 1168M used, 1139M free, 2306M total Starting string size: 943M GC stats: 2335M used, 1288M free, 3623M total Starting string size: 943M GC stats: 2335M used, 2605M free, 4940M total Starting string size: 943M GC stats: 2335M used, 2605M free, 4940M total Starting string size: 943M GC stats: 2335M used, 2605M free, 4940M total - Note that I explicitly clear the `str` slice before GC.collect(), so that the stack shouldn't contain any refs to the fat string anymore.
Re: Arduino and MCU Support
On Friday, 26 June 2020 at 09:30:15 UTC, Dukc wrote: On Thursday, 25 June 2020 at 03:00:04 UTC, Dylan Graham wrote: I'm currently making an automatic transmission controller with Arduino. C++ just has too many traps that I keep falling into. Since stability is critical (if the code screws up at 100km/h I'm dead), I'd rather use a sane language like D. No, don't! Regardless of the language, you should never trust your safety on one single program. See https://www.digitalmars.com/articles/b39.html Realistically, doing such a controller cannot be one man/woman endeavour. Thank you for the article. It was an intriguing read. I don't really have any capacity to implement multiple concurrent programs given how limited the hardware is. What I do have is a "pipeline" of modules that have their own checks to mitigate logical errors. The transmission also has a mechanical backup should the electronics fail. What I meant more so was creature comforts D provides that you begin missing when you revert to C++ -- something that can assist me in avoiding certain classes of bugs, which is what was referring to in my original message and I fear the most. I have a running controller that even interacts with car's stock computers and is passing real world tests at current. Automotive engineering is more approachable than it first appears.
Re: Garbage collection
On Saturday, 27 June 2020 at 12:07:19 UTC, Stanislav Blinov wrote: On Saturday, 27 June 2020 at 11:35:12 UTC, Arafel wrote: If you are using linux, have in mind that the memory is often not returned to the OS even after a (libc) free. That's a good observation. Although a GC implementation is not required to actually use malloc, so depending on that falls into "know what you're doing" territory :) Thanks for the help, but unfortunately it isn't stopping memory usage growing in the original app. I will try and build a minimal example. In the meantime perhaps someone can suggest how I might figure out what is going on. Repeating the same action is giving memory usage growth as follows. 1.7GB first time (which now drops to about 1GB), then 2.7GB dropping to about 2GB and so on.
Re: Garbage collection
On Saturday, 27 June 2020 at 12:53:01 UTC, James Gray wrote: On Saturday, 27 June 2020 at 12:07:19 UTC, Stanislav Blinov wrote: On Saturday, 27 June 2020 at 11:35:12 UTC, Arafel wrote: [...] That's a good observation. Although a GC implementation is not required to actually use malloc, so depending on that falls into "know what you're doing" territory :) Thanks for the help, but unfortunately it isn't stopping memory usage growing in the original app. I will try and build a minimal example. In the meantime perhaps someone can suggest how I might figure out what is going on. Repeating the same action is giving memory usage growth as follows. 1.7GB first time (which now drops to about 1GB), then 2.7GB dropping to about 2GB and so on. Which eventually results in mac os running out of memory.
Re: Garbage collection
On Saturday, 27 June 2020 at 11:35:12 UTC, Arafel wrote: If you are using linux, have in mind that the memory is often not returned to the OS even after a (libc) free. That's a good observation. Although a GC implementation is not required to actually use malloc, so depending on that falls into "know what you're doing" territory :)
Re: Garbage collection
On 27/6/20 13:21, Stanislav Blinov wrote: I would think collect + minimize should do the trick. Just keep in mind that that's grossly inefficient. If you are using linux, have in mind that the memory is often not returned to the OS even after a (libc) free. If you check with tools like `top`, it'll still show as assigned to the process. What I had to do (both in D and in C/C++) was to call malloc_trim [1] manually to have the memory actually sent back to the OS. [1]: https://man7.org/linux/man-pages/man3/malloc_trim.3.html
Re: Garbage collection
On Saturday, 27 June 2020 at 11:11:38 UTC, James Gray wrote: I am measuring the memory usage using top from the command line. GC.minimize() does seem to stop the leak. That is not a memory leak. That's the allocator keeping pages for itself to not have to go to the kernel every time you allocate. But it doesn't explain why the program isn't releasing essentially all the memory between calls to f (it using around 2GB ram all the time). Allocators usually don't do that. They keep (at least some) memory mapped to make allocations more efficient. Is there a way of achieving that? I would think collect + minimize should do the trick. Just keep in mind that that's grossly inefficient.
Re: Garbage collection
On Saturday, 27 June 2020 at 11:11:38 UTC, James Gray wrote: I am measuring the memory usage using top from the command line. GC.minimize() does seem to stop the leak. But it doesn't explain why the program isn't releasing essentially all the memory between calls to f (it using around 2GB ram all the time). Is there a way of achieving that? It's not a leak. The GC allocates memory as it needs it and holds on to it. When something is collected, the GC can reuse then released memory when it needs it.
Re: Garbage collection
On Saturday, 27 June 2020 at 11:00:58 UTC, Stanislav Blinov wrote: On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote: I find that the memory usage grows to about 1.5GB and never decreases. Is there something I am not understanding? How are you measuring that? GC.collect() does not necessarily release the pages to the OS. For that, there's the GC.minimize(). I am measuring the memory usage using top from the command line. GC.minimize() does seem to stop the leak. But it doesn't explain why the program isn't releasing essentially all the memory between calls to f (it using around 2GB ram all the time). Is there a way of achieving that?
Re: Garbage collection
On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote: I find that the memory usage grows to about 1.5GB and never decreases. Is there something I am not understanding? How are you measuring that? GC.collect() does not necessarily release the pages to the OS. For that, there's the GC.minimize().
Re: Garbage collection
On Saturday, 27 June 2020 at 10:08:15 UTC, James Gray wrote: I am writing a web application using vibe.d (not sure whether that is relevant or not), and have run into a memory leak. I wrote the following code to try and replicate the problem. [...] I now compiled the same code above with ldc2 and it is leaking. Any suggestions?
Garbage collection
I am writing a web application using vibe.d (not sure whether that is relevant or not), and have run into a memory leak. I wrote the following code to try and replicate the problem. import std.algorithm; import std.range; import std.format; import std.stdio; import core.thread; import core.memory; auto f(R)(R r) { return format("%s", r); } void main() { while(true) { writeln("Starting"); { auto str = f(iota(1).map!(x=>x+1)); } writeln("Done"); GC.collect(); Thread.sleep( dur!("msecs")( 3 ) ); } } It doesn't replicate the problem but it still doesn't behave as I would expect. I would expect the memory usage of this code to grow and shrink. However, I find that the memory usage grows to about 1.5GB and never decreases. Is there something I am not understanding?
Re: How to send ownerTid into a parallel foreach loop?
On Saturday, 27 June 2020 at 07:31:56 UTC, Kagamin wrote: std.concurrency is for noninteractive appications, the approach with gui timer was the correct one. Thank you. That works but my progress bar is sometimes getting stuck because of a possible data race. See https://forum.dlang.org/post/gacweulvbyorkseti...@forum.dlang.org Today I discovered Glib Idle so I was trying that out.
Re: How to send ownerTid into a parallel foreach loop?
std.concurrency is for noninteractive appications, the approach with gui timer was the correct one.