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