I tried to call a C library but it does not work, I get the error message undefined reference to listFiles while compiling. I assume the mapping from C types to Nimrod types is not yet correct. I use the types Cdirent etc. only because the pragma at the end of the functions do not seem to bring the C types in scope for the function header.
Here is the relevant part of my code, can someone tell me what is wrong?
import os, strutils
type
Cdirent {.importc: "dirent", header: "<dirent.h>".} = object
Tdirent = ref Cdirent
Cstat {.importc: "stat", header: "<dirent.h>".} = object
Tstat = ref Cstat
proc printStat(fileType: Char, ent: Tdirent, st: Tstat) {.header: "<dirent.h>".} =
echo "$1 $2 $3" % [fileType, st.st_mode & STAT_MASK, ent.d_name]
proc listFiles(path: String, filter: proc(s: String): Bool) {.header: "<dirent.h>".} =
var dir = opendir(path)
if !dir:
echo "could not open directory '", path, "'"
return
var ent = readdir(dir)
while ent != nil:
if filter(dir.d_name):
var st: stat
if lstat(ent.d_name, st):
echo "error: lstat"
return
if S_ISDIR(s.st_mode):
printStat 'd', ent, st
ent = readdir(dir)
closedir(dir)
listFiles "/a/path/", proc(s: String): Bool = True
After applying your suggestions, I still get an undefined reference error. I get it even in this simple case:
proc test() {.header: "<dirent.h>".} =
echo "called test()"
test()
I only found the walkFiles function in the stdlib but it returns the files only as strings, I need access to further information of the files.
I don't want to offend you, but I don't consider documentation that leads to open questions as "pretty well".
The only documentation I found is http://nimrod-lang.org/manual.html#foreign-function-interface and http://nimrod-lang.org/nimrodc.html#header-pragma which didn't answer my questions (and I didn't find this by searching "nimrod call c function").
I had to read code of the stdlib for example to find out that I have to define each C method in Nimrod before I can use it (the first time I thought that I can just import the members of a C header with the header pragma).
I get something that compiles and runs fine now, but it took me quite some time to find out that I have to add the pragma importc: "struct dirent" instead of only importc: "dirent" to Cdirent:
type
CDIR {.importc: "DIR", header: "<stdio.h>", final.} = object
TDIR* = ptr CDIR
Cdirent {.importc: "struct dirent", header: "<dirent.h>", final.} = object
d_name: cstring
Tdirent* = ptr Cdirent
proc opendir*(path: cstring): TDIR {.importc: "opendir", header: "<dirent.h>"}
proc readdir*(dir: TDIR): Tdirent {.importc: "readdir", header: "<dirent.h>"}
proc closedir*(dir: TDIR): Int {.importc: "closedir", header: "<dirent.h>"}
proc test() =
var dir = opendir("/home/sschaef/")
if dir == nil:
echo "error dir"
else:
var ent = readdir(dir)
while ent != nil:
let name = ent.d_name
echo name
ent = readdir(dir)
discard closedir(dir)
when isMainModule:
test()