oscon2015/4_cppinterop.rst
2015-07-17 10:22:09 +02:00

340 lines
6 KiB
ReStructuredText

======================
Interfacing with C/C++
======================
Interfacing with C
==================
2 options
- via ``dynlib``
- via ``header``
Dynlib import
=============
.. code-block:: Nim
:number-lines:
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
=============
.. code-block::
:number-lines:
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
=============
.. code-block::
:number-lines:
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 type Nim type
================= ==========================================================
``int`` ``cint``
``unsigned long`` ``culong``
``float`` ``cfloat``
``int x[4]`` ``array[4, cint]``
``int*`` ``ptr int``
``char*`` ``cstring``
``char**`` ``cstringArray = ptr array [0..ArrayDummySize, cstring]``
================= ==========================================================
Data exchange with C
====================
.. code-block:: C
:number-lines:
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
====================
.. code-block:: C
:number-lines:
int sum(int* x, size_t len) {
int result = 0;
for (size_t i = 0; i < len; i++)
result += x[i];
return result;
}
.. code-block:: Nim
:number-lines:
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
==================
.. code-block:: nim
:number-lines:
var
a {.codegenDecl: "$# progmem $#".}: int
proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
echo "realistic interrupt handler"
Wrapping C++
============
.. code-block:: C++
:number-lines:
class Foo {
public:
int value;
int GetValue() { return value; }
int& SetValue(int x) { field = x; return &field; }
};
.. code-block:: Nim
:number-lines:
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++
============
.. code-block:: C++
:number-lines:
class Foo {
public:
int value;
int GetValue() { return value; }
int& SetValue(int x) { field = x; return &field; }
};
.. code-block:: Nim
:number-lines:
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
============
.. code-block:: C++
:number-lines:
class Foo {
public:
int value;
int GetValue() { return value; }
int& SetValue(int x) { field = x; return &field; }
Foo(int x): field(x) {}
};
.. code-block:: Nim
:number-lines:
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
============
.. code-block:: C++
:number-lines:
Foo foo = Foo(1, 2, 3);
auto foo = Foo(1, 2, 3);
Constructors
============
.. code-block:: C++
:number-lines:
Foo foo = Foo(1, 2, 3);
// Calls copy constructor!
auto foo = Foo(1, 2, 3);
Constructors
============
.. code-block:: C++
:number-lines:
Foo foo = Foo(1, 2, 3);
// Calls copy constructor!
auto foo = Foo(1, 2, 3);
Foo foo(1, 2, 3);
Constructors
============
.. code-block:: Nim
:number-lines:
proc constructFoo*(x: cint): Foo
{.importcpp: "Foo(@)", header: "file.h", constructor.}
.. code-block:: nim
:number-lines:
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:
.. code-block:: nim
:number-lines:
type Input {.importcpp: "System::Input".} = object
proc getSubsystem*[T](): ptr T
{.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.}
let x: ptr Input = getSubsystem[Input]()
Produces:
.. code-block:: C
:number-lines:
x = SystemManager::getSubsystem<System::Input>()
Emit pragma
===========
.. code-block:: Nim
:number-lines:
{.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()
..
A tour through the standard library
-----------------------------------
- system module: basic arithmetic and IO
- strutils module; Unicode module
- OS and osproc modules
- sequtils and algorithm
- tables and sets
- linked lists, queues
- watchpoints
- tracing
- lexer generation
- ORM
Questions?
==========