I am trying to use the Intel Performance Primitives for some work. Since they are installed in a custom path, I need to add options to the Nim compiler to both find the headers and correctly link the dynamic libraries. I need to link libipps.so and libippcore.so, both of which live inside /opt/intel/ipp/lib/intel64.
The way I am currently invoking Nim is
nim c \
--threads:on \
--cincludes:"/opt/intel/composer_xe_2015.0.090/ipp/include" \
--clibdir:"/opt/intel/ipp/lib/intel64" \
--clib:"ipps" \
--clib:"ippcore" \
--verbosity:0 \
--define:release main.nim
Unfortunately, this does not find the libraries. Turning verbosity on, I can see that GCC is invoked with an option like -l/home/.../myproject/ipps -l/home/.../myproject/ippcore, and of course those do not exist. I would expect Nim to just add -lipps -lippcore - then ld would find the correct libraries, since -L/opt/intel/ipp/lib/intel64 is also provided.
Right now I am just doing
nim c \
--threads:on \
--cincludes:"/opt/intel/composer_xe_2015.0.090/ipp/include" \
--clibdir:"/opt/intel/ipp/lib/intel64" \
--verbosity:3 \
--define:release main.nim
Then ld fails complaining that it does not find the relevant symbols, and I can copy the failed gcc invocation, add the correct options, and run it manually.
I have also tried the --passC and --passL options to manually pass options to gcc or ld respectively, but Nim complains that these options can only be used with --run.
What is the correct way to link external libraries?
if pass in {passCmd2, passPP}: cLinkedLibs.add arg.processPath(true)
or even simply
if pass in {passCmd2, passPP}: cLinkedLibs.add arg
Before making a pull request, though, I would like for someone more experienced to comment whether processPath there is intentional, and how to overcome this in my situation
I am confused: I have posted the entire command I use in the first post. The problem is that the option --clib:"ipps" is converted into the gcc option -l/home/.../myproject/ipps instead of -lipps. In other words, the path to the current project is prepended, but according to the rules that ld uses to find dynamic libraries, it should be omitted
EDIT Sorry, you meant the full command with passL. It seems that now it is working. For some reason, I got Nim complaining that the option required the use of --run, but I am not able to reproduce it. So I guess that passL works fine, my bad.
Sorry, you meant the full command with passL. It seems that now it is working. For some reason, I got Nim complaining that the option required the use of --run, but I am not able to reproduce it. So I guess that passL works fine, my bad.
Indeed. I guessed that you had an error in there, like a space somewhere.
Unfortunately, this does not find the libraries.
Thank you for your example. I tried to link a so called GTK resource file to a Nim application. (At first I avoided that, by simple reading the original xml text files, as suggested by Araq some months ago. But I had the feeling that linking the resource may work also, the advantage is that we have one single executable.) From http://nim-lang.org/docs/backends.html#nim-code-calling-the-backend-c-invocation-example I put
{.compile: "resources.c".}
in the first line of my main.nim file. A plain "nim c main.nim" does not work well because ld can not find a few symbols from gio library. So from your example I tried
nim c --verbosity:3 --parallelBuild:1 --cincludes:"/usr/include/gio-unix-2.0" --clibdir:"/usr/lib64/" --clib:"gio" main.nin
which fails with
gcc -o /home/stefan/nim-app/main /home/stefan/nim-app/nimcache/exampleappprefs.o /home/stefan/nim-app/nimcache/exampleappwin.o /home/stefan/nim-app/nimcache/sup.o /home/stefan/nim-app/nimcache/atk_atk.o /home/stefan/nim-app/nimcache/pango_pango.o /home/stefan/nim-app/nimcache/cairo_cairo.o /home/stefan/nim-app/nimcache/gdk_pixbuf_gdk_pixbuf.o /home/stefan/nim-app/nimcache/stdlib_posix.o /home/stefan/nim-app/nimcache/gio_gio.o /home/stefan/nim-app/nimcache/stdlib_macros.o /home/stefan/nim-app/nimcache/gobject_gobject.o /home/stefan/nim-app/nimcache/stdlib_parseutils.o /home/stefan/nim-app/nimcache/stdlib_strutils.o /home/stefan/nim-app/nimcache/stdlib_times.o /home/stefan/nim-app/nimcache/glib_glib.o /home/stefan/nim-app/nimcache/gdk3_gdk3.o /home/stefan/nim-app/nimcache/gtk3_gtk3.o /home/stefan/nim-app/nimcache/exampleapp.o /home/stefan/nim-app/nimcache/stdlib_system.o /home/stefan/nim-app/nimcache/main.o /home/stefan/nim-app/nimcache/resources.o -l/home/stefan/nim-app/gio -L/usr/lib64/ -ldl [Exec] /usr/lib/gcc/x86_64-pc-linux-gnu/4.9.3/../../../../x86_64-pc-linux-gnu/bin/ld: cannot find -l/home/stefan/nim-app/gio collect2: error: ld returned 1 exit status
Indeed -l/home/stefan/nim-app/gio is wrong. So when I copy this large gcc command but change last parameter to -lgio-2.0 all works fine. (Yes, I also added the -2.0) That is really great. I do not know much about all these linker options, but with your example linking GTK resource files seems to be really easy.
This is for Nim Compiler Version 0.11.3 (2015-08-11) [Linux: amd64], maybe option --clib:"gio" is indeed handled wrong, as you said at the beginning of this thread.
{.compile: "resources.c".}
in the Nim file. Then in working directory
rm -rf nimcache/ mkdir nimcache cp resources.c nimcache/ cd nimcache/ gcc -c `pkg-config --libs --cflags gtk+-3.0` resources.c cd .. nim c --verbosity:3 --parallelBuild:1 --passL:-lgio-2.0 main.nim nim c --verbosity:3 --parallelBuild:1 --passL:-lgio-2.0 main.nim
Yes, call Nim twice. First call gives
/home/stefan/nim-app/resources.c:1:21: fatal error: gio/gio.h: No such file or directory
because Nim tries to compile resources.c. Second call uses existing resources.o from gcc call. :-)
I'd suggest something like the following instead, as it avoids doing the work by hand (or even easier, a makefile):
import strutils, macros
proc makeObjFile*(cfile: string, flags: string = ""): string {.compiletime.} =
if not cfile.endsWith(".c"):
error "C file does not end in .c"
let objfile = cfile[0..^3] & ".o"
let test = "test " & cfile & " -ot " & objfile
let compile = "gcc -c -O2 " & flags & " " & cfile
let redir = " >/dev/null 2>/dev/null"
let cmd = "(" & test & " || " & compile & redir & "); echo $?"
let output = staticExec(cmd).strip
let success = output == "0"
if not success:
error "Command failed: " & compile
result = objfile
{.link: makeObjFile("resource.c",
flags="`pkg-config --libs --cflags gtk+-3.0`").}