Nimrod logo

Interfacing with C/C++

Interfacing with C

2 options

Dynlib import

1
2
3
4
5
6
7
8
type
  GtkWidget = object
    data: cint
    binary: cfloat
    compatible: char

proc gtk_image_new(): ptr GtkWidget
  {.cdecl, dynlib: "libgtk-x11-2.0.so", importc.}

Header import

1
2
3
4
5
6
7
8
9
10
11
type
  GtkWidget {.importc: "GtkWidget_t", header: "<gtk.h>".} = object
    data {.importc: "Data".}: cint
    binary {.importc: "Binary".}: cfloat
    compatible: char

proc gtk_image_new(): ptr GtkWidget
  {.cdecl, header: "<gtk.h>", importc.}

{.passC: staticExec("pkg-config --cflags gtk").}
{.passL: staticExec("pkg-config --libs gtk").}

Header import

1
2
3
4
proc printf(formatstr: cstring)
  {.header: "<stdio.h>", importc: "printf", varargs.}

printf("%s%s", "Nim strings ", "converted to cstring for you")

Data exchange with C

C typeNim type
intcint
unsigned longculong
floatcfloat
int x[4]array[4, cint]
int*ptr int
char*cstring
char**cstringArray = ptr array [0..ArrayDummySize, cstring]

Data exchange with C

1
2
3
4
5
6
int sum(int* x, size_t len) {
  int result = 0;
  for (size_t i = 0; i < len; i++)
    result += x[i];
  return result;
}

Data exchange with C

1
2
3
4
5
6
int sum(int* x, size_t len) {
  int result = 0;
  for (size_t i = 0; i < len; i++)
    result += x[i];
  return result;
}
1
2
3
4
5
6
7
8
9
proc sum(x: ptr cint; len: int): cint
  {.importc: "sum", cdecl, header: "foo.h".}

proc callSum =
  var x = @[1.cint, 2, 3, 4]
  echo sum(addr x[0], x.len)
  
  var y = [1.cint, 2, 3, 4]
  echo sum(addr y[0], y.len)

CodegenDecl pragma

1
2
3
4
5
var
  a {.codegenDecl: "$# progmem $#".}: int

proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
  echo "realistic interrupt handler"

Wrapping C++

1
2
3
4
5
6
class Foo {
public:
  int value;
  int GetValue() { return value; }
  int& SetValue(int x) { field = x; return &field; }
};
1
2
3
4
5
6
7
8
type
  Foo* {.importcpp: "Foo", header: "file.h".} = object
    value*: cint

proc getValue*(this: var Foo): cint
  {.importcpp: "GetValue", header: "file.h".}
proc setValue*(this: var Foo; x: cint): var cint
  {.importcpp: "SetValue", header: "file.h".}

Wrapping C++

1
2
3
4
5
6
class Foo {
public:
  int value;
  int GetValue() { return value; }
  int& SetValue(int x) { field = x; return &field; }
};
1
2
3
4
5
6
7
8
type
  Foo* {.importcpp: "Foo", header: "file.h".} = object
    value*: cint

proc getValue*(this: var Foo): cint
  {.importcpp: "#.GetValue(@)", header: "file.h".}
proc setValue*(this: var Foo; x: cint): var cint
  {.importcpp: "#.SetValue(@)", header: "file.h".}

Constructors

1
2
3
4
5
6
7
8
class Foo {
public:
  int value;
  int GetValue() { return value; }
  int& SetValue(int x) { field = x; return &field; }
  
  Foo(int x): field(x) {}
};
1
2
3
4
5
6
7
8
9
10
11
type
  Foo* {.importcpp: "Foo", header: "file.h".} = object
    value*: cint

proc getValue*(this: var Foo): cint
  {.importcpp: "#.GetValue(@)", header: "file.h".}
proc setValue*(this: var Foo; x: cint): var cint
  {.importcpp: "#.SetValue(@)", header: "file.h".}

proc constructFoo*(x: cint): Foo
  {.importcpp: "Foo(@)", header: "file.h".}

Constructors

1
2
3
Foo foo = Foo(1, 2, 3);

auto foo = Foo(1, 2, 3);

Constructors

1
2
3
Foo foo = Foo(1, 2, 3);
// Calls copy constructor!
auto foo = Foo(1, 2, 3);

Constructors

1
2
3
4
5
Foo foo = Foo(1, 2, 3);
// Calls copy constructor!
auto foo = Foo(1, 2, 3);

Foo foo(1, 2, 3);

Constructors

1
2
proc constructFoo*(x: cint): Foo
  {.importcpp: "Foo(@)", header: "file.h", constructor.}
1
2
3
4
5
6
proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".}

let x = newFoo(3, 4)


proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.}

Generics

For example:

1
2
3
4
5
type Input {.importcpp: "System::Input".} = object
proc getSubsystem*[T](): ptr T
  {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}

let x: ptr Input = getSubsystem[Input]()

Produces:

1
x = SystemManager::getSubsystem<System::Input>()

Emit pragma

1
2
3
4
5
6
7
8
9
10
11
12
{.emit: """
static int cvariable = 420;
""".}

{.push stackTrace:off.}
proc embedsC() =
  var nimVar = 89
  # use backticks to access Nim symbols within an emit section:
  {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".}
{.pop.}

embedsC()

Questions?