refs #2973; manual contains almost all pragmas now, few are left in the compiler guide
This commit is contained in:
parent
dd0acfdf37
commit
134c44f3be
2 changed files with 464 additions and 457 deletions
|
|
@ -511,3 +511,467 @@ Example:
|
||||||
add "foo"
|
add "foo"
|
||||||
add "bar"
|
add "bar"
|
||||||
|
|
||||||
|
|
||||||
|
Implementation Specific Pragmas
|
||||||
|
===============================
|
||||||
|
|
||||||
|
This section describes additional pragmas that the current Nim implementation
|
||||||
|
supports but which should not be seen as part of the language specification.
|
||||||
|
|
||||||
|
|
||||||
|
Volatile pragma
|
||||||
|
---------------
|
||||||
|
The ``volatile`` pragma is for variables only. It declares the variable as
|
||||||
|
``volatile``, whatever that means in C/C++ (its semantics are not well defined
|
||||||
|
in C/C++).
|
||||||
|
|
||||||
|
**Note**: This pragma will not exist for the LLVM backend.
|
||||||
|
|
||||||
|
|
||||||
|
NoDecl pragma
|
||||||
|
-------------
|
||||||
|
The ``noDecl`` pragma can be applied to almost any symbol (variable, proc,
|
||||||
|
type, etc.) and is sometimes useful for interoperability with C:
|
||||||
|
It tells Nim that it should not generate a declaration for the symbol in
|
||||||
|
the C code. For example:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
var
|
||||||
|
EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as
|
||||||
|
# Nim does not know its value
|
||||||
|
|
||||||
|
However, the ``header`` pragma is often the better alternative.
|
||||||
|
|
||||||
|
**Note**: This will not work for the LLVM backend.
|
||||||
|
|
||||||
|
|
||||||
|
Header pragma
|
||||||
|
-------------
|
||||||
|
The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be
|
||||||
|
applied to almost any symbol and specifies that it should not be declared
|
||||||
|
and instead the generated code should contain an ``#include``:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
type
|
||||||
|
PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
|
||||||
|
# import C's FILE* type; Nim will treat it as a new pointer type
|
||||||
|
|
||||||
|
The ``header`` pragma always expects a string constant. The string contant
|
||||||
|
contains the header file: As usual for C, a system header file is enclosed
|
||||||
|
in angle brackets: ``<>``. If no angle brackets are given, Nim
|
||||||
|
encloses the header file in ``""`` in the generated C code.
|
||||||
|
|
||||||
|
**Note**: This will not work for the LLVM backend.
|
||||||
|
|
||||||
|
|
||||||
|
IncompleteStruct pragma
|
||||||
|
-----------------------
|
||||||
|
The ``incompleteStruct`` pragma tells the compiler to not use the
|
||||||
|
underlying C ``struct`` in a ``sizeof`` expression:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
type
|
||||||
|
DIR* {.importc: "DIR", header: "<dirent.h>",
|
||||||
|
final, pure, incompleteStruct.} = object
|
||||||
|
|
||||||
|
|
||||||
|
Compile pragma
|
||||||
|
--------------
|
||||||
|
The ``compile`` pragma can be used to compile and link a C/C++ source file
|
||||||
|
with the project:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
{.compile: "myfile.cpp".}
|
||||||
|
|
||||||
|
**Note**: Nim computes a SHA1 checksum and only recompiles the file if it
|
||||||
|
has changed. You can use the ``-f`` command line option to force recompilation
|
||||||
|
of the file.
|
||||||
|
|
||||||
|
|
||||||
|
Link pragma
|
||||||
|
-----------
|
||||||
|
The ``link`` pragma can be used to link an additional file with the project:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
{.link: "myfile.o".}
|
||||||
|
|
||||||
|
|
||||||
|
PassC pragma
|
||||||
|
------------
|
||||||
|
The ``passC`` pragma can be used to pass additional parameters to the C
|
||||||
|
compiler like you would using the commandline switch ``--passC``:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
{.passC: "-Wall -Werror".}
|
||||||
|
|
||||||
|
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
||||||
|
embed parameters from an external command at compile time:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
{.passC: gorge("pkg-config --cflags sdl").}
|
||||||
|
|
||||||
|
PassL pragma
|
||||||
|
------------
|
||||||
|
The ``passL`` pragma can be used to pass additional parameters to the linker
|
||||||
|
like you would using the commandline switch ``--passL``:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
{.passL: "-lSDLmain -lSDL".}
|
||||||
|
|
||||||
|
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
||||||
|
embed parameters from an external command at compile time:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
{.passL: gorge("pkg-config --libs sdl").}
|
||||||
|
|
||||||
|
|
||||||
|
Emit pragma
|
||||||
|
-----------
|
||||||
|
The ``emit`` pragma can be used to directly affect the output of the
|
||||||
|
compiler's code generator. So it makes your code unportable to other code
|
||||||
|
generators/backends. Its usage is highly discouraged! However, it can be
|
||||||
|
extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
{.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()
|
||||||
|
|
||||||
|
As can be seen from the example, to Nim symbols can be referred via backticks.
|
||||||
|
Use two backticks to produce a single verbatim backtick.
|
||||||
|
|
||||||
|
For a toplevel emit statement the section where in the generated C/C++ file
|
||||||
|
the code should be emitted can be influenced via the
|
||||||
|
prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/`` or ``/*INCLUDESECTION*/``:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
{.emit: """/*TYPESECTION*/
|
||||||
|
struct Vector3 {
|
||||||
|
public:
|
||||||
|
Vector3(): x(5) {}
|
||||||
|
Vector3(float x_): x(x_) {}
|
||||||
|
float x;
|
||||||
|
};
|
||||||
|
""".}
|
||||||
|
|
||||||
|
type Vector3 {.importcpp: "Vector3", nodecl} = object
|
||||||
|
x: cfloat
|
||||||
|
|
||||||
|
proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
|
||||||
|
|
||||||
|
|
||||||
|
ImportCpp pragma
|
||||||
|
----------------
|
||||||
|
|
||||||
|
**Note**: `c2nim <c2nim.html>`_ can parse a large subset of C++ and knows
|
||||||
|
about the ``importcpp`` pragma pattern language. It is not necessary
|
||||||
|
to know all the details described here.
|
||||||
|
|
||||||
|
|
||||||
|
Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
|
||||||
|
``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols
|
||||||
|
in general. The generated code then uses the C++ method calling
|
||||||
|
syntax: ``obj->method(arg)``. In combination with the ``header`` and ``emit``
|
||||||
|
pragmas this allows *sloppy* interfacing with libraries written in C++:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
# Horrible example of how to interface with a C++ engine ... ;-)
|
||||||
|
|
||||||
|
{.link: "/usr/lib/libIrrlicht.so".}
|
||||||
|
|
||||||
|
{.emit: """
|
||||||
|
using namespace irr;
|
||||||
|
using namespace core;
|
||||||
|
using namespace scene;
|
||||||
|
using namespace video;
|
||||||
|
using namespace io;
|
||||||
|
using namespace gui;
|
||||||
|
""".}
|
||||||
|
|
||||||
|
const
|
||||||
|
irr = "<irrlicht/irrlicht.h>"
|
||||||
|
|
||||||
|
type
|
||||||
|
IrrlichtDeviceObj {.final, header: irr,
|
||||||
|
importcpp: "IrrlichtDevice".} = object
|
||||||
|
IrrlichtDevice = ptr IrrlichtDeviceObj
|
||||||
|
|
||||||
|
proc createDevice(): IrrlichtDevice {.
|
||||||
|
header: irr, importcpp: "createDevice(@)".}
|
||||||
|
proc run(device: IrrlichtDevice): bool {.
|
||||||
|
header: irr, importcpp: "#.run(@)".}
|
||||||
|
|
||||||
|
The compiler needs to be told to generate C++ (command ``cpp``) for
|
||||||
|
this to work. The conditional symbol ``cpp`` is defined when the compiler
|
||||||
|
emits C++ code.
|
||||||
|
|
||||||
|
|
||||||
|
Namespaces
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
The *sloppy interfacing* example uses ``.emit`` to produce ``using namespace``
|
||||||
|
declarations. It is usually much better to instead refer to the imported name
|
||||||
|
via the ``namespace::identifier`` notation:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
type
|
||||||
|
IrrlichtDeviceObj {.final, header: irr,
|
||||||
|
importcpp: "irr::IrrlichtDevice".} = object
|
||||||
|
|
||||||
|
|
||||||
|
Importcpp for enums
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When ``importcpp`` is applied to an enum type the numerical enum values are
|
||||||
|
annotated with the C++ enum type, like in this example: ``((TheCppEnum)(3))``.
|
||||||
|
(This turned out to be the simplest way to implement it.)
|
||||||
|
|
||||||
|
|
||||||
|
Importcpp for procs
|
||||||
|
~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Note that the ``importcpp`` variant for procs uses a somewhat cryptic pattern
|
||||||
|
language for maximum flexibility:
|
||||||
|
|
||||||
|
- A hash ``#`` symbol is replaced by the first or next argument.
|
||||||
|
- A dot following the hash ``#.`` indicates that the call should use C++'s dot
|
||||||
|
or arrow notation.
|
||||||
|
- An at symbol ``@`` is replaced by the remaining arguments, separated by
|
||||||
|
commas.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".}
|
||||||
|
var x: ptr CppObj
|
||||||
|
cppMethod(x[], 1, 2, 3)
|
||||||
|
|
||||||
|
Produces:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
x->CppMethod(1, 2, 3)
|
||||||
|
|
||||||
|
As a special rule to keep backwards compatibility with older versions of the
|
||||||
|
``importcpp`` pragma, if there is no special pattern
|
||||||
|
character (any of ``# ' @``) at all, C++'s
|
||||||
|
dot or arrow notation is assumed, so the above example can also be written as:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".}
|
||||||
|
|
||||||
|
Note that the pattern language naturally also covers C++'s operator overloading
|
||||||
|
capabilities:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".}
|
||||||
|
proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".}
|
||||||
|
|
||||||
|
|
||||||
|
- An apostrophe ``'`` followed by an integer ``i`` in the range 0..9
|
||||||
|
is replaced by the i'th parameter *type*. The 0th position is the result
|
||||||
|
type. This can be used to pass types to C++ function templates. Between
|
||||||
|
the ``'`` and the digit an asterisk can be used to get to the base type
|
||||||
|
of the type. (So it "takes away a star" from the type; ``T*`` becomes ``T``.)
|
||||||
|
Two stars can be used to get to the element type of the element type etc.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
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
|
||||||
|
x = SystemManager::getSubsystem<System::Input>()
|
||||||
|
|
||||||
|
|
||||||
|
- ``#@`` is a special case to support a ``cnew`` operation. It is required so
|
||||||
|
that the call expression is inlined directly, without going through a
|
||||||
|
temporary location. This is only required to circumvent a limitation of the
|
||||||
|
current code generator.
|
||||||
|
|
||||||
|
For example C++'s ``new`` operator can be "imported" like this:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.}
|
||||||
|
|
||||||
|
# constructor of 'Foo':
|
||||||
|
proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)".}
|
||||||
|
|
||||||
|
let x = cnew constructFoo(3, 4)
|
||||||
|
|
||||||
|
Produces:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
x = new Foo(3, 4)
|
||||||
|
|
||||||
|
However, depending on the use case ``new Foo`` can also be wrapped like this
|
||||||
|
instead:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".}
|
||||||
|
|
||||||
|
let x = newFoo(3, 4)
|
||||||
|
|
||||||
|
|
||||||
|
Wrapping constructors
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Sometimes a C++ class has a private copy constructor and so code like
|
||||||
|
``Class c = Class(1,2);`` must not be generated but instead ``Class c(1,2);``.
|
||||||
|
For this purpose the Nim proc that wraps a C++ constructor needs to be
|
||||||
|
annotated with the `constructor`:idx: pragma. This pragma also helps to generate
|
||||||
|
faster C++ code since construction then doesn't invoke the copy constructor:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
# a better constructor of 'Foo':
|
||||||
|
proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.}
|
||||||
|
|
||||||
|
|
||||||
|
Wrapping destructors
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Since Nim generates C++ directly, any destructor is called implicitly by the
|
||||||
|
C++ compiler at the scope exits. This means that often one can get away with
|
||||||
|
not wrapping the destructor at all! However when it needs to be invoked
|
||||||
|
explicitly, it needs to be wrapped. But the pattern language already provides
|
||||||
|
everything that is required for that:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".}
|
||||||
|
|
||||||
|
|
||||||
|
Importcpp for objects
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Generic ``importcpp``'ed objects are mapped to C++ templates. This means that
|
||||||
|
you can import C++'s templates rather easily without the need for a pattern
|
||||||
|
language for object types:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
type
|
||||||
|
StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object
|
||||||
|
proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {.
|
||||||
|
importcpp: "#[#] = #", header: "<map>".}
|
||||||
|
|
||||||
|
var x: StdMap[cint, cdouble]
|
||||||
|
x[6] = 91.4
|
||||||
|
|
||||||
|
|
||||||
|
Produces:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
std::map<int, double> x;
|
||||||
|
x[6] = 91.4;
|
||||||
|
|
||||||
|
|
||||||
|
- If more precise control is needed, the apostrophe ``'`` can be used in the
|
||||||
|
supplied pattern to denote the concrete type parameters of the generic type.
|
||||||
|
See the usage of the apostrophe operator in proc patterns for more details.
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
|
||||||
|
type
|
||||||
|
VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
|
||||||
|
|
||||||
|
var x: VectorIterator[cint]
|
||||||
|
|
||||||
|
|
||||||
|
Produces:
|
||||||
|
|
||||||
|
.. code-block:: C
|
||||||
|
|
||||||
|
std::vector<int>::iterator x;
|
||||||
|
|
||||||
|
|
||||||
|
ImportObjC pragma
|
||||||
|
-----------------
|
||||||
|
Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
|
||||||
|
``importobjc`` pragma can be used to import `Objective C`:idx: methods. The
|
||||||
|
generated code then uses the Objective C method calling syntax: ``[obj method
|
||||||
|
param1: arg]``. In addition with the ``header`` and ``emit`` pragmas this
|
||||||
|
allows *sloppy* interfacing with libraries written in Objective C:
|
||||||
|
|
||||||
|
.. code-block:: Nim
|
||||||
|
# horrible example of how to interface with GNUStep ...
|
||||||
|
|
||||||
|
{.passL: "-lobjc".}
|
||||||
|
{.emit: """
|
||||||
|
#include <objc/Object.h>
|
||||||
|
@interface Greeter:Object
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)greet:(long)x y:(long)dummy;
|
||||||
|
@end
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
@implementation Greeter
|
||||||
|
|
||||||
|
- (void)greet:(long)x y:(long)dummy
|
||||||
|
{
|
||||||
|
printf("Hello, World!\n");
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
""".}
|
||||||
|
|
||||||
|
type
|
||||||
|
Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int
|
||||||
|
|
||||||
|
proc newGreeter: Id {.importobjc: "Greeter new", nodecl.}
|
||||||
|
proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.}
|
||||||
|
proc free(self: Id) {.importobjc: "free", nodecl.}
|
||||||
|
|
||||||
|
var g = newGreeter()
|
||||||
|
g.greet(12, 34)
|
||||||
|
g.free()
|
||||||
|
|
||||||
|
The compiler needs to be told to generate Objective C (command ``objc``) for
|
||||||
|
this to work. The conditional symbol ``objc`` is defined when the compiler
|
||||||
|
emits Objective C code.
|
||||||
|
|
||||||
|
|
||||||
|
CodegenDecl pragma
|
||||||
|
------------------
|
||||||
|
|
||||||
|
The ``codegenDecl`` pragma can be used to directly influence Nim's code
|
||||||
|
generator. It receives a format string that determines how the variable or
|
||||||
|
proc is declared in the generated code:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
var
|
||||||
|
a {.codegenDecl: "$# progmem $#".}: int
|
||||||
|
|
||||||
|
proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
|
||||||
|
echo "realistic interrupt handler"
|
||||||
|
|
||||||
|
|
||||||
|
InjectStmt pragma
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The ``injectStmt`` pragma can be used to inject a statement before every
|
||||||
|
other statement in the current module. It is only supposed to be used for
|
||||||
|
debugging:
|
||||||
|
|
||||||
|
.. code-block:: nim
|
||||||
|
{.injectStmt: gcInvariants().}
|
||||||
|
|
||||||
|
# ... complex code here that produces crashes ...
|
||||||
|
|
||||||
|
|
|
||||||
457
doc/nimc.txt
457
doc/nimc.txt
|
|
@ -263,454 +263,6 @@ Nim manual. Some of the features here only make sense for the C code
|
||||||
generator and are subject to change.
|
generator and are subject to change.
|
||||||
|
|
||||||
|
|
||||||
NoDecl pragma
|
|
||||||
-------------
|
|
||||||
The ``noDecl`` pragma can be applied to almost any symbol (variable, proc,
|
|
||||||
type, etc.) and is sometimes useful for interoperability with C:
|
|
||||||
It tells Nim that it should not generate a declaration for the symbol in
|
|
||||||
the C code. For example:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
var
|
|
||||||
EACCES {.importc, noDecl.}: cint # pretend EACCES was a variable, as
|
|
||||||
# Nim does not know its value
|
|
||||||
|
|
||||||
However, the ``header`` pragma is often the better alternative.
|
|
||||||
|
|
||||||
**Note**: This will not work for the LLVM backend.
|
|
||||||
|
|
||||||
|
|
||||||
Header pragma
|
|
||||||
-------------
|
|
||||||
The ``header`` pragma is very similar to the ``noDecl`` pragma: It can be
|
|
||||||
applied to almost any symbol and specifies that it should not be declared
|
|
||||||
and instead the generated code should contain an ``#include``:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
type
|
|
||||||
PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer
|
|
||||||
# import C's FILE* type; Nim will treat it as a new pointer type
|
|
||||||
|
|
||||||
The ``header`` pragma always expects a string constant. The string contant
|
|
||||||
contains the header file: As usual for C, a system header file is enclosed
|
|
||||||
in angle brackets: ``<>``. If no angle brackets are given, Nim
|
|
||||||
encloses the header file in ``""`` in the generated C code.
|
|
||||||
|
|
||||||
**Note**: This will not work for the LLVM backend.
|
|
||||||
|
|
||||||
|
|
||||||
IncompleteStruct pragma
|
|
||||||
-----------------------
|
|
||||||
The ``incompleteStruct`` pragma tells the compiler to not use the
|
|
||||||
underlying C ``struct`` in a ``sizeof`` expression:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
type
|
|
||||||
DIR* {.importc: "DIR", header: "<dirent.h>",
|
|
||||||
final, pure, incompleteStruct.} = object
|
|
||||||
|
|
||||||
|
|
||||||
Compile pragma
|
|
||||||
--------------
|
|
||||||
The ``compile`` pragma can be used to compile and link a C/C++ source file
|
|
||||||
with the project:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
{.compile: "myfile.cpp".}
|
|
||||||
|
|
||||||
**Note**: Nim computes a SHA1 checksum and only recompiles the file if it
|
|
||||||
has changed. You can use the ``-f`` command line option to force recompilation
|
|
||||||
of the file.
|
|
||||||
|
|
||||||
|
|
||||||
Link pragma
|
|
||||||
-----------
|
|
||||||
The ``link`` pragma can be used to link an additional file with the project:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
{.link: "myfile.o".}
|
|
||||||
|
|
||||||
|
|
||||||
PassC pragma
|
|
||||||
------------
|
|
||||||
The ``passC`` pragma can be used to pass additional parameters to the C
|
|
||||||
compiler like you would using the commandline switch ``--passC``:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
{.passC: "-Wall -Werror".}
|
|
||||||
|
|
||||||
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
|
||||||
embed parameters from an external command at compile time:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
{.passC: gorge("pkg-config --cflags sdl").}
|
|
||||||
|
|
||||||
PassL pragma
|
|
||||||
------------
|
|
||||||
The ``passL`` pragma can be used to pass additional parameters to the linker
|
|
||||||
like you would using the commandline switch ``--passL``:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
{.passL: "-lSDLmain -lSDL".}
|
|
||||||
|
|
||||||
Note that you can use ``gorge`` from the `system module <system.html>`_ to
|
|
||||||
embed parameters from an external command at compile time:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
{.passL: gorge("pkg-config --libs sdl").}
|
|
||||||
|
|
||||||
|
|
||||||
Emit pragma
|
|
||||||
-----------
|
|
||||||
The ``emit`` pragma can be used to directly affect the output of the
|
|
||||||
compiler's code generator. So it makes your code unportable to other code
|
|
||||||
generators/backends. Its usage is highly discouraged! However, it can be
|
|
||||||
extremely useful for interfacing with `C++`:idx: or `Objective C`:idx: code.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
{.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()
|
|
||||||
|
|
||||||
As can be seen from the example, to Nim symbols can be referred via backticks.
|
|
||||||
Use two backticks to produce a single verbatim backtick.
|
|
||||||
|
|
||||||
For a toplevel emit statement the section where in the generated C/C++ file
|
|
||||||
the code should be emitted can be influenced via the
|
|
||||||
prefixes ``/*TYPESECTION*/`` or ``/*VARSECTION*/`` or ``/*INCLUDESECTION*/``:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
{.emit: """/*TYPESECTION*/
|
|
||||||
struct Vector3 {
|
|
||||||
public:
|
|
||||||
Vector3(): x(5) {}
|
|
||||||
Vector3(float x_): x(x_) {}
|
|
||||||
float x;
|
|
||||||
};
|
|
||||||
""".}
|
|
||||||
|
|
||||||
type Vector3 {.importcpp: "Vector3", nodecl} = object
|
|
||||||
x: cfloat
|
|
||||||
|
|
||||||
proc constructVector3(a: cfloat): Vector3 {.importcpp: "Vector3(@)", nodecl}
|
|
||||||
|
|
||||||
|
|
||||||
ImportCpp pragma
|
|
||||||
----------------
|
|
||||||
|
|
||||||
**Note**: `c2nim <c2nim.html>`_ can parse a large subset of C++ and knows
|
|
||||||
about the ``importcpp`` pragma pattern language. It is not necessary
|
|
||||||
to know all the details described here.
|
|
||||||
|
|
||||||
|
|
||||||
Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
|
|
||||||
``importcpp`` pragma can be used to import `C++`:idx: methods or C++ symbols
|
|
||||||
in general. The generated code then uses the C++ method calling
|
|
||||||
syntax: ``obj->method(arg)``. In combination with the ``header`` and ``emit``
|
|
||||||
pragmas this allows *sloppy* interfacing with libraries written in C++:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
# Horrible example of how to interface with a C++ engine ... ;-)
|
|
||||||
|
|
||||||
{.link: "/usr/lib/libIrrlicht.so".}
|
|
||||||
|
|
||||||
{.emit: """
|
|
||||||
using namespace irr;
|
|
||||||
using namespace core;
|
|
||||||
using namespace scene;
|
|
||||||
using namespace video;
|
|
||||||
using namespace io;
|
|
||||||
using namespace gui;
|
|
||||||
""".}
|
|
||||||
|
|
||||||
const
|
|
||||||
irr = "<irrlicht/irrlicht.h>"
|
|
||||||
|
|
||||||
type
|
|
||||||
IrrlichtDeviceObj {.final, header: irr,
|
|
||||||
importcpp: "IrrlichtDevice".} = object
|
|
||||||
IrrlichtDevice = ptr IrrlichtDeviceObj
|
|
||||||
|
|
||||||
proc createDevice(): IrrlichtDevice {.
|
|
||||||
header: irr, importcpp: "createDevice(@)".}
|
|
||||||
proc run(device: IrrlichtDevice): bool {.
|
|
||||||
header: irr, importcpp: "#.run(@)".}
|
|
||||||
|
|
||||||
The compiler needs to be told to generate C++ (command ``cpp``) for
|
|
||||||
this to work. The conditional symbol ``cpp`` is defined when the compiler
|
|
||||||
emits C++ code.
|
|
||||||
|
|
||||||
|
|
||||||
Namespaces
|
|
||||||
~~~~~~~~~~
|
|
||||||
|
|
||||||
The *sloppy interfacing* example uses ``.emit`` to produce ``using namespace``
|
|
||||||
declarations. It is usually much better to instead refer to the imported name
|
|
||||||
via the ``namespace::identifier`` notation:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
type
|
|
||||||
IrrlichtDeviceObj {.final, header: irr,
|
|
||||||
importcpp: "irr::IrrlichtDevice".} = object
|
|
||||||
|
|
||||||
|
|
||||||
Importcpp for enums
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
When ``importcpp`` is applied to an enum type the numerical enum values are
|
|
||||||
annotated with the C++ enum type, like in this example: ``((TheCppEnum)(3))``.
|
|
||||||
(This turned out to be the simplest way to implement it.)
|
|
||||||
|
|
||||||
|
|
||||||
Importcpp for procs
|
|
||||||
~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Note that the ``importcpp`` variant for procs uses a somewhat cryptic pattern
|
|
||||||
language for maximum flexibility:
|
|
||||||
|
|
||||||
- A hash ``#`` symbol is replaced by the first or next argument.
|
|
||||||
- A dot following the hash ``#.`` indicates that the call should use C++'s dot
|
|
||||||
or arrow notation.
|
|
||||||
- An at symbol ``@`` is replaced by the remaining arguments, separated by
|
|
||||||
commas.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".}
|
|
||||||
var x: ptr CppObj
|
|
||||||
cppMethod(x[], 1, 2, 3)
|
|
||||||
|
|
||||||
Produces:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
x->CppMethod(1, 2, 3)
|
|
||||||
|
|
||||||
As a special rule to keep backwards compatibility with older versions of the
|
|
||||||
``importcpp`` pragma, if there is no special pattern
|
|
||||||
character (any of ``# ' @``) at all, C++'s
|
|
||||||
dot or arrow notation is assumed, so the above example can also be written as:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".}
|
|
||||||
|
|
||||||
Note that the pattern language naturally also covers C++'s operator overloading
|
|
||||||
capabilities:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".}
|
|
||||||
proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".}
|
|
||||||
|
|
||||||
|
|
||||||
- An apostrophe ``'`` followed by an integer ``i`` in the range 0..9
|
|
||||||
is replaced by the i'th parameter *type*. The 0th position is the result
|
|
||||||
type. This can be used to pass types to C++ function templates. Between
|
|
||||||
the ``'`` and the digit an asterisk can be used to get to the base type
|
|
||||||
of the type. (So it "takes away a star" from the type; ``T*`` becomes ``T``.)
|
|
||||||
Two stars can be used to get to the element type of the element type etc.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
|
|
||||||
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
|
|
||||||
x = SystemManager::getSubsystem<System::Input>()
|
|
||||||
|
|
||||||
|
|
||||||
- ``#@`` is a special case to support a ``cnew`` operation. It is required so
|
|
||||||
that the call expression is inlined directly, without going through a
|
|
||||||
temporary location. This is only required to circumvent a limitation of the
|
|
||||||
current code generator.
|
|
||||||
|
|
||||||
For example C++'s ``new`` operator can be "imported" like this:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
proc cnew*[T](x: T): ptr T {.importcpp: "(new '*0#@)", nodecl.}
|
|
||||||
|
|
||||||
# constructor of 'Foo':
|
|
||||||
proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)".}
|
|
||||||
|
|
||||||
let x = cnew constructFoo(3, 4)
|
|
||||||
|
|
||||||
Produces:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
x = new Foo(3, 4)
|
|
||||||
|
|
||||||
However, depending on the use case ``new Foo`` can also be wrapped like this
|
|
||||||
instead:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".}
|
|
||||||
|
|
||||||
let x = newFoo(3, 4)
|
|
||||||
|
|
||||||
|
|
||||||
Wrapping constructors
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Sometimes a C++ class has a private copy constructor and so code like
|
|
||||||
``Class c = Class(1,2);`` must not be generated but instead ``Class c(1,2);``.
|
|
||||||
For this purpose the Nim proc that wraps a C++ constructor needs to be
|
|
||||||
annotated with the `constructor`:idx: pragma. This pragma also helps to generate
|
|
||||||
faster C++ code since construction then doesn't invoke the copy constructor:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
# a better constructor of 'Foo':
|
|
||||||
proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.}
|
|
||||||
|
|
||||||
|
|
||||||
Wrapping destructors
|
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Since Nim generates C++ directly, any destructor is called implicitly by the
|
|
||||||
C++ compiler at the scope exits. This means that often one can get away with
|
|
||||||
not wrapping the destructor at all! However when it needs to be invoked
|
|
||||||
explicitly, it needs to be wrapped. But the pattern language already provides
|
|
||||||
everything that is required for that:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".}
|
|
||||||
|
|
||||||
|
|
||||||
Importcpp for objects
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Generic ``importcpp``'ed objects are mapped to C++ templates. This means that
|
|
||||||
you can import C++'s templates rather easily without the need for a pattern
|
|
||||||
language for object types:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
type
|
|
||||||
StdMap {.importcpp: "std::map", header: "<map>".} [K, V] = object
|
|
||||||
proc `[]=`[K, V](this: var StdMap[K, V]; key: K; val: V) {.
|
|
||||||
importcpp: "#[#] = #", header: "<map>".}
|
|
||||||
|
|
||||||
var x: StdMap[cint, cdouble]
|
|
||||||
x[6] = 91.4
|
|
||||||
|
|
||||||
|
|
||||||
Produces:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
std::map<int, double> x;
|
|
||||||
x[6] = 91.4;
|
|
||||||
|
|
||||||
|
|
||||||
- If more precise control is needed, the apostrophe ``'`` can be used in the
|
|
||||||
supplied pattern to denote the concrete type parameters of the generic type.
|
|
||||||
See the usage of the apostrophe operator in proc patterns for more details.
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
|
|
||||||
type
|
|
||||||
VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
|
|
||||||
|
|
||||||
var x: VectorIterator[cint]
|
|
||||||
|
|
||||||
|
|
||||||
Produces:
|
|
||||||
|
|
||||||
.. code-block:: C
|
|
||||||
|
|
||||||
std::vector<int>::iterator x;
|
|
||||||
|
|
||||||
|
|
||||||
ImportObjC pragma
|
|
||||||
-----------------
|
|
||||||
Similar to the `importc pragma for C <manual.html#importc-pragma>`_, the
|
|
||||||
``importobjc`` pragma can be used to import `Objective C`:idx: methods. The
|
|
||||||
generated code then uses the Objective C method calling syntax: ``[obj method
|
|
||||||
param1: arg]``. In addition with the ``header`` and ``emit`` pragmas this
|
|
||||||
allows *sloppy* interfacing with libraries written in Objective C:
|
|
||||||
|
|
||||||
.. code-block:: Nim
|
|
||||||
# horrible example of how to interface with GNUStep ...
|
|
||||||
|
|
||||||
{.passL: "-lobjc".}
|
|
||||||
{.emit: """
|
|
||||||
#include <objc/Object.h>
|
|
||||||
@interface Greeter:Object
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)greet:(long)x y:(long)dummy;
|
|
||||||
@end
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
@implementation Greeter
|
|
||||||
|
|
||||||
- (void)greet:(long)x y:(long)dummy
|
|
||||||
{
|
|
||||||
printf("Hello, World!\n");
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
""".}
|
|
||||||
|
|
||||||
type
|
|
||||||
Id {.importc: "id", header: "<objc/Object.h>", final.} = distinct int
|
|
||||||
|
|
||||||
proc newGreeter: Id {.importobjc: "Greeter new", nodecl.}
|
|
||||||
proc greet(self: Id, x, y: int) {.importobjc: "greet", nodecl.}
|
|
||||||
proc free(self: Id) {.importobjc: "free", nodecl.}
|
|
||||||
|
|
||||||
var g = newGreeter()
|
|
||||||
g.greet(12, 34)
|
|
||||||
g.free()
|
|
||||||
|
|
||||||
The compiler needs to be told to generate Objective C (command ``objc``) for
|
|
||||||
this to work. The conditional symbol ``objc`` is defined when the compiler
|
|
||||||
emits Objective C code.
|
|
||||||
|
|
||||||
|
|
||||||
CodegenDecl pragma
|
|
||||||
------------------
|
|
||||||
|
|
||||||
The ``codegenDecl`` pragma can be used to directly influence Nim's code
|
|
||||||
generator. It receives a format string that determines how the variable or
|
|
||||||
proc is declared in the generated code:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
var
|
|
||||||
a {.codegenDecl: "$# progmem $#".}: int
|
|
||||||
|
|
||||||
proc myinterrupt() {.codegenDecl: "__interrupt $# $#$#".} =
|
|
||||||
echo "realistic interrupt handler"
|
|
||||||
|
|
||||||
|
|
||||||
InjectStmt pragma
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
The ``injectStmt`` pragma can be used to inject a statement before every
|
|
||||||
other statement in the current module. It is only supposed to be used for
|
|
||||||
debugging:
|
|
||||||
|
|
||||||
.. code-block:: nim
|
|
||||||
{.injectStmt: gcInvariants().}
|
|
||||||
|
|
||||||
# ... complex code here that produces crashes ...
|
|
||||||
|
|
||||||
|
|
||||||
LineDir option
|
LineDir option
|
||||||
--------------
|
--------------
|
||||||
The ``lineDir`` option can be turned on or off. If turned on the
|
The ``lineDir`` option can be turned on or off. If turned on the
|
||||||
|
|
@ -744,15 +296,6 @@ The *breakpoint* pragma was specially added for the sake of debugging with
|
||||||
ENDB. See the documentation of `endb <endb.html>`_ for further information.
|
ENDB. See the documentation of `endb <endb.html>`_ for further information.
|
||||||
|
|
||||||
|
|
||||||
Volatile pragma
|
|
||||||
---------------
|
|
||||||
The ``volatile`` pragma is for variables only. It declares the variable as
|
|
||||||
``volatile``, whatever that means in C/C++ (its semantics are not well defined
|
|
||||||
in C/C++).
|
|
||||||
|
|
||||||
**Note**: This pragma will not exist for the LLVM backend.
|
|
||||||
|
|
||||||
|
|
||||||
DynlibOverride
|
DynlibOverride
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue