header pragma(头文件指示):html
type PFile {.importc: "FILE*", header: "<stdio.h>".} = distinct pointer # 导入c语言的 FILE* 指针类型到Nim里用PFile新类型来代替使用.
Compile pragma(编译指示):
直接让nim文件使用c/c++代码文件, 编译的时候会先编译.c文件成.o而后连接让nim也能使用其内容.node
#test.nim {.compile: "testc.c".} proc csum(n: cint): cint {.importc.} echo csum(100)
//testc.c int csum(int n) { return n + 10; }
Link pragma(链接指示):
直接连接obj文件.c++
{.link: "test.o".}
PassC pragma(编译参数指示):
相似makefile compile flag: -g -Wallgit
{.passC: "-Wall -Werror".} #也可以使用外部程序指令 {.passC: gorge("pkg-config --cflags sdl").}
PassL pragma(链接参数指示):
相似makefile link flag: -L/xxx/sdl -lsdlapp
{.passL: "-lSDLmain -lSDL".} #一样可以使用外部程序指令 {.passL: gorge("pkg-config --libs sdl").}
Emit pragma(发表指示, 这翻起来还真别扭): 这个指示能够直接在nim代码里运行c/c++/objc等代码, 强大如斯.
(注释: '"""'3个引号是nim的语法, 在里面的全部内容都是字符串.)tcp
{.emit: """ static int cvariable = 420; """.} {.push stackTrace:off.} proc embedsC() = var nimVar = 89 # emit里用"`"号(就是~号的按键不要加shift)之间使用nim代码的内容. {.emit: """fprintf(stdout, "%d\n", cvariable + (int)`nimVar`);""".} {.pop.} embedsC()
写类和结构开头要写上/*TYPESECTION*/ 或 /*VARSECTION*/.ide
{.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(C++导入指示): 可用c2nim工具把C/C++库或代码文件转成nim代码.
和使用importc方法相似, 这些符号会在后面详解, 这里有小教如何在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(@)".}
固然也能够不emit命名空间, 能够写成这样.
(嘛~这些都属于C++的内容了, 想必你们都知道, 但仍是多句嘴吧.)工具
type IrrlichtDeviceObj {.final, header: irr, importcpp: "irr::IrrlichtDevice".} = object
Importcpp for procs(c++导入之函数使用):
单独一个"#"号表示代替第一个或下一个参数.
"#"号接"."表示使用c++点操做或指针"->"操做.
"@"号表示代替剩余的参数, 使用时用逗号来分隔.post
proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "#.CppMethod(@)".} var x: ptr CppObj cppMethod(x[], 1, 2, 3)
产生的效果等价于
x->CppMethod(1, 2, 3)
C++的"."或"->"同上面的例子也能够写成:
proc cppMethod(this: CppObj, a, b, c: cint) {.importcpp: "CppMethod".}
一样也能应用于重载函数
//这里应该是代替c++的operator重载操做符+和[] proc vectorAddition(a, b: Vec3): Vec3 {.importcpp: "# + #".} proc dictLookup(a: Dict, k: Key): Value {.importcpp: "#[#]".}
"'"单引号后面接0~9的数字来替换第i个参数, 第0位则做为返回类型, 能够用来传递c++函数模板. "'"单引号和数字之间加入"*"星号表示得到该类型的基类型(因此去掉星号T*就是T类型?), "**"双星表示得到该元素类型的元素类型等. (这句不是很懂, 因此放上原文, E文不错的朋友请告知, 感谢)
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.
type Input {.importcpp: "System::Input".} = object proc getSubsystem*[T](): ptr T {.importcpp: "SystemManager::getSubsystem<'*0>()", nodecl.} let x: ptr Input = getSubsystem[Input]()
产生的效果等价于
x = SystemManager::getSubsystem<System::Input>()
"#@"目前只知道应用于new操做符, 由于new操做符比较特殊吧? 其它功能暂不知. 代替c++的new操做符的示例:
#'*0#@拆开来就是:'*0为该类型, #@指该操做行为是new吧. 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)
等价于
x = new Foo(3, 4)
然而, 依赖new的表示式也能用如下方法代替.
proc newFoo(a, b: cint): ptr Foo {.importcpp: "new Foo(@)".} let x = newFoo(3, 4)
Wrapping constructors(封装构造函数): 构造/析构函数是c++基础内容, 这里不在阐述, 不懂的话能够翻阅相关资料了解一下.
加入constructor的pragma便可.
# a better constructor of 'Foo': proc constructFoo(a, b: cint): Foo {.importcpp: "Foo(@)", constructor.}
Wrapping destructors(封装析构函数):
proc destroyFoo(this: var Foo) {.importcpp: "#.~Foo()".}
Importcpp for objects(c++导入之对象):
这里射映了一个C++的map模板类型并声明使用对象
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
等价于c++的
std::map<int, double> x; x[6] = 91.4;
若是须要更详细的操做, 可使用"'"加数字来射映(嗯, 那啥上面有解释过).
type VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object var x: VectorIterator[cint]
等价于
std::vector<int>::iterator x;
ImportObjC pragma(objc导入指示):
使用objc须要导入libobjc.a的静态库, passL就是这个做用.
# 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()
这里教你如何使用c2nim把c头文件转成nim:Nim Wrapping C
参考资料:importcpp-pragma