www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Creating Libraries Callable from C

reply "TJB" <broughtj gmail.com> writes:
Is it possible to write a library that is callable from C without 
the enduser even knowing it was written in D? That is, can a C 
programmer use the library as though it were written in C 
straightforwardly? Or for that matter, by an enduser programming 
in Python or Lua where the library is being exposed through those 
languages' C API?

I'm sure this is a widely discussed and well understood topic, 
but I am a newbie (and have no formal training in CS) and don't 
know where to look for documentation.

A little baby tutorial would be super helpful and well received 
by this newbie.

Thanks so much!

TJB
Apr 26 2014
parent reply =?UTF-8?B?UsOpbXkgTW91w6t6YQ==?= <remy.moueza gmail.com> writes:
It is possible to write a D library useable from C. However, we may not 
be able to hide the fact that the library has been written in D.

You must first export some D function you want to use from C, using 
extern (C)  declaration.

Then declare them in your C program or headers.
You will also have to declare 2 function for initializing and 
terminating D's runtime:
     char rt_init(long long);
     char rt_term(long long);

call rt_init(0) before using your D functions (this will initialize D 
runtime - the D GC amongst other things), then use rt_term(0) at the end 
of the program - you may want to register an exit function with atexit().

With older versions of DMD we had also to create a D module with an 
empty main() function that had to be linked with the C program to force 
the D compiler to generate some symbols that were not generated within 
the object files. As of dmd 2.064, this is no longer necessary.

Below is an example I once retrieve from this newsgroup:

dlibrary.d
==========
import std.stdio, std.array, std.range;

extern(C) void printf(in char*,...);

extern(C) void funcD(){
     printf("C's printf in D\n");
     writeln("D's writeln");
     writeln("D's array alloc: ", new double[3]);
     writeln("D's iota: ", iota(0, 30, 4));
}

cmain.c
=======
int printf(char*, ...);

void funcC() {
     printf("C's printf in C\n");
}

char rt_init(long long);
char rt_term(long long);

void main(){
     // code without D
     funcC();

     rt_init(0); // initialize D's runtime

     //code with D
     funcD();

     rt_term(0); // terminate D's runtime

     //code without D
}

Compilation
===========
Compiling the D library
-----------------------
dmd -c dlibrary.d

Compiling the C executable
--------------------------
You can do it with either dmd or gcc

gcc -o cmain cmain.c  dlibrary.o \
  -m32 -lrt -lphobos2 -lpthread -lm \
  -Xlinker -L$DMD/linux/lib32 \
  -Xlinker --no-warn-search-mismatch \
  -Xlinker --export-dynamic

To get the proper gcc flags, use dmd in verbose mode:
- first compile cmain: gcc -c cmain.c
- then: dmd -v cmain.o dlibrary.o


Executing
---------
./cmain
C's printf in C
C's printf in D
D's writeln
D's array alloc: [nan, nan, nan]
D's iota: [0, 4, 8, 12, 16, 20, 24, 28]


D from other programming languages
==================================

There is a project to write python extensions in D PYD:
     https://bitbucket.org/ariovistus/pyd

I also wrote about my experiment of using Swig for a proof of concept 
PHP extension in D:
     http://forum.dlang.org/post/gwqstgaiivknieyqfseu forum.dlang.org

What works for PHP can work for the other Swig supported languages 
(Java, C#, Go, Perl, Ruby...).

On 04/26/2014 07:13 PM, TJB wrote:
 Is it possible to write a library that is callable from C without the
 enduser even knowing it was written in D? That is, can a C programmer
 use the library as though it were written in C straightforwardly? Or for
 that matter, by an enduser programming in Python or Lua where the
 library is being exposed through those languages' C API?

 I'm sure this is a widely discussed and well understood topic, but I am
 a newbie (and have no formal training in CS) and don't know where to
 look for documentation.

 A little baby tutorial would be super helpful and well received by this
 newbie.

 Thanks so much!

 TJB
Apr 26 2014
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/26/2014 11:27 AM, Rémy Mouëza wrote:

 You will also have to declare 2 function for initializing and
 terminating D's runtime:
      char rt_init(long long);
      char rt_term(long long);

 call rt_init(0) before using your D functions (this will initialize D
 runtime - the D GC amongst other things), then use rt_term(0) at the end
 of the program - you may want to register an exit function with atexit().
And if those functions are called from the library's own initialization and deinitialization functions, the C program need not know anything about the D runtime dependence: void mylib_init() { rt_init(0); // ... other initialization } Ali
Apr 26 2014
parent "ketmar" <ketmar ketmar.no-ip.org> writes:
On Sunday, 27 April 2014 at 02:15:59 UTC, Ali Çehreli wrote:
 And if those functions are called from the library's own 
 initialization and deinitialization functions, the C program 
 need not know anything about the D runtime dependence:

 void mylib_init() {
     rt_init(0);
     // ... other initialization
 }
and what if user links two such libraries? ;-)
Apr 26 2014