www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Calling D code from C

reply Niko Korhonen <niktheblak hotmail.com> writes:
I'm playing around with an idea to make my D library partially callable
in C. Getting C and D to interface with each other is something totally
new for me, and thus I've stumbled into a weird problem.

Consider the following short programs:

ctest.d: (D code)

<code>
module ctest;

extern (C)
{
	void test()
	{
		int[] x = new int[10];
		printf("x.length: %u\n", x.length);
	}
}
</code>

ctest-c.c: (C code)

<code>
void test(void); // Declare the D function

int main()
{
	test();
	return 0;
}
</code>

The purpose is to compile the D file into an obj, compile the C file and
link it with the D obj file. When I do this using DMD/DMC in the
following way:

<code>
dmd -c ctest.d
dmc ctest-c.c ctest.obj c:\tools\dmd\lib\phobos.lib
</code>

It works correctly, but when executing ctest-c.exe, it crashes with a
trying to write to a null pointer message. Apparently the 'new' clause
in the D file causes the crash.

Should this work, or have I missed something very important in C/D
interoperability? For instance, is it forbidden to use D memory
management facilities or something like that?
May 26 2005
parent reply Vathix <vathix dprogramming.com> writes:
On Thu, 26 May 2005 16:18:21 -0400, Niko Korhonen <niktheblak hotmail.com>  
wrote:

 I'm playing around with an idea to make my D library partially callable
 in C. Getting C and D to interface with each other is something totally
 new for me, and thus I've stumbled into a weird problem.

 Consider the following short programs:

 ctest.d: (D code)

 <code>
 module ctest;

 extern (C)
 {
 	void test()
 	{
 		int[] x = new int[10];
 		printf("x.length: %u\n", x.length);
 	}
 }
 </code>

 ctest-c.c: (C code)

 <code>
 void test(void); // Declare the D function

 int main()
 {
 	test();
 	return 0;
 }
 </code>

 The purpose is to compile the D file into an obj, compile the C file and
 link it with the D obj file. When I do this using DMD/DMC in the
 following way:

 <code>
 dmd -c ctest.d
 dmc ctest-c.c ctest.obj c:\tools\dmd\lib\phobos.lib
 </code>

 It works correctly, but when executing ctest-c.exe, it crashes with a
 trying to write to a null pointer message. Apparently the 'new' clause
 in the D file causes the crash.

 Should this work, or have I missed something very important in C/D
 interoperability? For instance, is it forbidden to use D memory
 management facilities or something like that?
The problem is that D's main() initializes things. Using a C main() bypasses that startup code. Put the main() in the D file (with D extern) and have it call a function in the C file that you will treat as main. (D code) extern(C) { int cmain(); void test() { printf("test!\n"); } } int main() { return cmain(); } (C code) void test(void); int cmain(void) { test(); return 0; }
May 26 2005
next sibling parent Niko Korhonen <niktheblak hotmail.com> writes:
Vathix wrote:
 The problem is that D's main() initializes things. Using a C main()
 bypasses that startup code. Put the main() in the D file (with D
 extern)  and have it call a function in the C file that you will treat
 as main.
Thanks a million, that fixed the problem! BTW, is anything about this mentioned in the docs/FAQs? I couldn't find anything when I tried to google for this issue.
May 27 2005
prev sibling parent reply Stefan <stefan schuerger.com> writes:
On Thursday, 26 May 2005 at 20:41:10 UTC, Vathix wrote:

 The problem is that D's main() initializes things. Using a C 
 main() bypasses that startup code. Put the main() in the D file 
 (with D extern) and have it call a function in the C file that 
 you will treat as main.
That's correct, but not always an option, such as when writing a D library which can be called from C programs you can't touch. But you can easily do the initialization in your D code, by calling rt_init() and rt_term(), like this: import std.stdio; import core.memory : GC; extern(C) int rt_init(); extern(C) int rt_term(); extern(C) __gshared bool rt_initialized = false; extern(C) void d_function(){ writeln("Initializing D runtime"); if(!rt_initialized) rt_init(); rt_initialized = true; char[] big = new char[10000000]; big = null; writeln("Calling GC"); GC.collect(); writeln("Finishing D function"); scope(exit){ writeln("Terminating D runtime"); if(rt_initialized) rt_term(); rt_initialized = false; } } ...just be careful that you don't do anything requiring memory allocation before rt_init() or after rt_term().
Jan 08 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 08, 2020 at 06:12:01PM +0000, Stefan via Digitalmars-d-learn wrote:
[...]
 But you can easily do the initialization in your D code, by calling
 rt_init() and rt_term(), like this:
[...]
 extern(C) int rt_init();
 extern(C) int rt_term();
 extern(C) __gshared bool rt_initialized = false;
[...]
 	if(!rt_initialized)
 	  rt_init();
 	rt_initialized = true;
I believe the rt_initialized flag is unnecessary, because rt_init/rt_term use an atomic counter to keep track of how many times they were called. So you just have to call rt_init and make sure you have a matching call to rt_term, and it should Just Work(tm). T -- The richest man is not he who has the most, but he who needs the least.
Jan 08 2020
parent reply Ferhat =?UTF-8?B?S3VydHVsbXXFnw==?= <aferust gmail.com> writes:
On Wednesday, 8 January 2020 at 19:05:29 UTC, H. S. Teoh wrote:
 On Wed, Jan 08, 2020 at 06:12:01PM +0000, Stefan via 
 Digitalmars-d-learn wrote: [...]
 But you can easily do the initialization in your D code, by 
 calling
 rt_init() and rt_term(), like this:
[...]
 extern(C) int rt_init();
 extern(C) int rt_term();
 extern(C) __gshared bool rt_initialized = false;
[...]
 	if(!rt_initialized)
 	  rt_init();
 	rt_initialized = true;
I believe the rt_initialized flag is unnecessary, because rt_init/rt_term use an atomic counter to keep track of how many times they were called. So you just have to call rt_init and make sure you have a matching call to rt_term, and it should Just Work(tm). T
What is going on here? The original post date appears as to be of 2005 :D. And a reminder that druntime must be linked along with phobos when it is a library.
Jan 08 2020
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 08, 2020 at 09:42:03PM +0000, Ferhat Kurtulmuş via
Digitalmars-d-learn wrote:
[...]
 What is going on here? The original post date appears as to be of 2005
 :D.
[...] Haha yeah, I'm not sure why Stefan replied to a post dating from 2005. T -- Just because you can, doesn't mean you should.
Jan 08 2020
parent bachmeier <no spam.net> writes:
On Wednesday, 8 January 2020 at 22:00:03 UTC, H. S. Teoh wrote:
 On Wed, Jan 08, 2020 at 09:42:03PM +0000, Ferhat Kurtulmuş via 
 Digitalmars-d-learn wrote: [...]
 What is going on here? The original post date appears as to be 
 of 2005 :D.
[...] Haha yeah, I'm not sure why Stefan replied to a post dating from 2005. T
Google is good at resurrection.
Jan 08 2020