Thread overview
Calling D code from C
May 26, 2005
Niko Korhonen
May 26, 2005
Vathix
May 27, 2005
Niko Korhonen
Jan 08, 2020
Stefan
Jan 08, 2020
H. S. Teoh
Jan 08, 2020
Ferhat Kurtulmuş
Jan 08, 2020
H. S. Teoh
Jan 08, 2020
bachmeier
May 26, 2005
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
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 27, 2005
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.
January 08, 2020
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().
January 08, 2020
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.
January 08, 2020
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.

January 08, 2020
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.
January 08, 2020
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.