Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

ImportC

Note: This document is under construction. Please excuse the dust and noise.

ImportC is a C compiler embedded into the D implementation. Its purpose is to enable direct importation of C files, without needing to manually prepare a D file corresponding to the the declarations in the C file. It enables directly compiling C files into modules, and linking them in with D code to form an executable. It can be used as a C compiler to compile and link 100% C programs.

This is not a C reference manual nor programming tutorial. It describes the specifics of the dialect of C that ImportC is, and how to use it effectively.

ImportC and are very different. ImportC is an actual C compiler. BetterC is a subset of D that relies only on the existence of the C Standard library.

ImportC Dialect

There are many versions of C. ImportC is designed to be an implementation of ISO/IEC 9899:2011, which will hereafter be referred to as C11. References to the C11 Standard will be C11 followed by the paragraph number. Prior versions, such as C99, C89, and K+R C, are not supported.

Adjustment to the ImportC dialect is made to match the behavior of the C compiler that the D compiler is matched to. For example, on Win32 D is matched to the Digital Mars C compiler, and can be matched to the Visual C compiler using the -m32mscoff switch. Win64 D is matched to the Visual C compiler. On Posix targets, the matching C compiler is Gnu C or Clang C.

Further adjustment is made to take advantage of some of the D implementation's capabilities.

This is all covered in the rest of this document.

Invoking ImportC

The ImportC compiler can be invoked in two ways:

ImportC Files on the Command Line

Importing C Files

Preprocessor

ImportC does not have a preprocessor. It is designed to compile C files after they have been first run through the C preprocessor.

Digital Mars C Preprocessor sppn.exe

sppn.exe runs on Win32 and is invoked as:

    sppn file.c
    

and the preprocessed output is written to file.i.

Gnu C Preprocessor

The Gnu C Preprocessor can be invoked as:

    gcc -E file.c > file.i
    

Clang C Preprocessor

The Clang Preprocessor can be invoked as:

    clang -E file.c > file.i
    

dmpp C Preprocessor

The dmpp C Preprocessor can be invoked as:

    dmpp file.c
    

and the preprocessed output is written to file.i.

Preprocessor Directives

Nevertheless, ImportC supports these preprocessor directives:

Line control

C11 6.10.4

Linemarker

linemarker directives are normally embedded in the output of C preprocessors.

Limitations

Exception Handling

ImportC is assumed to never throw exceptions. setjmp and longjmp are not supported.

Const

C11 specifies that const only applies locally. const in ImportC applies transitively, meaning that although

int *const p;
means in C11 that p is a const pointer to int, in ImportC it means p is a const pointer to a const int.

Volatile

The volatile type-qualifier (C11 6.7.3) is ignored. Use of volatile to implement shared memory access is unlikely to work anyway, _Atomic is for that. To use volatile as a device register, call a function to do it that is compiled separately, or use inline assembler.

Restrict

The restrict type-qualifier (C11 6.7.3) is ignored.

_Atomic

The _Atomic type-qualifier (C11 6.7.3) is ignored. To do atomic operations, use an externally compiled function for that, or the inline assembler.

Extensions

Forward References

Any declarations in scope can be accessed, not just declarations that lexically precede a reference.

Compile Time Function Execution

Evaluating constant expressions includes executing functions in the same manner as D's CTFE can.

Function Inlining

Functions for which the function body is present can be inlined by ImportC as well as by the D code that calls them.

Register Storage Class

Objects with register storage class are treated as auto declarations.

Objects with register storage class may have their address taken. C11 6.3.2.1-2

Arrays can have register storage class, and may be enregistered by the compiler. C11 6.3.2.1-3

Gnu and Clang Extensions

Visual C Extensions

Digital Mars C Extensions

ImportC from D's Point of View

There is no one-to-one mapping of C constructs to D constructs, although it is very close. What follows is a description of how the D side views the C declarations that are imported.

Module Name

The module name assigned to the ImportC file is the filename stripped of its path and extension. This is just like the default module name assigned to a D module that does not have a module declaration.

extern (C)

All C symbols are extern (C).

Enums

The C enum:

enum E { A, B = 2 };

appears to D code as:

enum E : int { A, B = 2 }
alias A = E.A;
alias B = E.B;

The .min and .max properties are available:

static assert(E.min == 0 && E.max == 2);

Wrapping C Code

Many difficulties with adapting C code to ImportC can be done without editing the C code itself. Wrap the C code in another C file and then

#include
it. Consider the following problematic C file file.c:

    void func(int *__restrict p);
    int S;
    struct S { int a, b; };
    

The problems are that

__restrict
is not a type qualifier recognized by ImportC (or C11), and the struct S is hidden from D by the declaration
int S;
. To wrap file.c with a fix, create the file file_ic.c with the contents:

    #define __restrict restrict
    #include "file.c"
    typedef struct S S_t;
    

Then, import file_ic; instead of import file;, and use S_t when

struct S
is desired.

Warnings

Many suspicious C constructs normally cause warnings to be emitted by default by typical compilers, such as:

int *p = 3; // Warning: integer implicitly converted to pointer

ImportC does not emit warnings. The presumption is the user will be importing existing C code developed using another C compiler, and it is written as intended. If C11 says it is legal, ImportC accepts it.

ImportC++

ImportC will not compile C++ code. For that, use dpp.

Other Solutions

dpp by Atila Neves

dpp code

dpp Article

From the Article:

dpp is a compiler wrapper that will parse a D source file with the .dpp extension and expand in place any #include directives it encounters, translating all of the C or C++ symbols to D, and then pass the result to a D compiler (DMD by default).

Like DStep, dpp relies on libclang.

DStep by Jacob Carlborg

DStep code

DStep Article

From the Article:

DStep is a tool for automatically generating D bindings for C and Objective-C libraries. This is implemented by processing C or Objective-C header files and outputting D modules. DStep uses the Clang compiler as a library (libclang) to process the header files.

htod by Walter Bright

htod converts a C .h file to a D source file, suitable for importing into D code. htod is built from the front end of the Digital Mars C and C++ compiler. It works just like a C or C++ compiler except that its output is source code for a D module rather than object code.

How ImportC Works

This is a description of how ImportC is implemented, intended to remove the mystery of various design choices.

Better C
Live Functions