Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to specify libraries paths in gcc?

Tags:

c

gcc

I am writing a program using OpenCV calls and I want to compile it and make the executable. I already read the gcc tutorial but I still would like to know exactly how to link the OpenCV libraries I am using. My command and the related output is below:

$ gcc -I/home/savio/opencv-3.0.0/include/opencv -L/home/savio/opencv-3.0.0/cmake_binary_dir/lib \
>     -lopencv_core -lopencv_highgui -lopencv_imgproc imagefilter.c -o imagefilter
/tmp/ccDUEgAk.o: nella funzione "cvDecRefData":
imagefilter.c:(.text+0xa6a): riferimento non definito a "cvFree_"
imagefilter.c:(.text+0xaf2): riferimento non definito a "cvFree_"
/tmp/ccDUEgAk.o: nella funzione "cvGetRow":
imagefilter.c:(.text+0xc08): riferimento non definito a "cvGetRows"
/tmp/ccDUEgAk.o: nella funzione "cvGetCol":
imagefilter.c:(.text+0xc36): riferimento non definito a "cvGetCols"
/tmp/ccDUEgAk.o: nella funzione "cvReleaseMatND":
imagefilter.c:(.text+0xc50): riferimento non definito a "cvReleaseMat"
/tmp/ccDUEgAk.o: nella funzione "cvSubS":
imagefilter.c:(.text+0xdac): riferimento non definito a "cvAddS"
/tmp/ccDUEgAk.o: nella funzione "cvCloneSeq":
imagefilter.c:(.text+0xde5): riferimento non definito a "cvSeqSlice"
/tmp/ccDUEgAk.o: nella funzione "cvSetNew":
imagefilter.c:(.text+0xe52): riferimento non definito a "cvSetAdd"
/tmp/ccDUEgAk.o: nella funzione "cvGetSetElem":
imagefilter.c:(.text+0xefa): riferimento non definito a "cvGetSeqElem"
/tmp/ccDUEgAk.o: nella funzione "cvReadIntByName":
imagefilter.c:(.text+0xfa9): riferimento non definito a "cvGetFileNodeByName"
/tmp/ccDUEgAk.o: nella funzione "cvReadRealByName":
imagefilter.c:(.text+0x1053): riferimento non definito a "cvGetFileNodeByName"
/tmp/ccDUEgAk.o: nella funzione "cvReadStringByName":
imagefilter.c:(.text+0x10e6): riferimento non definito a "cvGetFileNodeByName"
/tmp/ccDUEgAk.o: nella funzione "cvReadByName":
imagefilter.c:(.text+0x1126): riferimento non definito a "cvGetFileNodeByName"
imagefilter.c:(.text+0x113c): riferimento non definito a "cvRead"
/tmp/ccDUEgAk.o: nella funzione "cvContourPerimeter":
imagefilter.c:(.text+0x1170): riferimento non definito a "cvArcLength"
/tmp/ccDUEgAk.o: nella funzione "cvCalcHist":
imagefilter.c:(.text+0x11b2): riferimento non definito a "cvCalcArrHist"
/tmp/ccDUEgAk.o: nella funzione "cvEllipseBox":
imagefilter.c:(.text+0x127e): riferimento non definito a "cvEllipse"
/tmp/ccDUEgAk.o: nella funzione "cvFont":
imagefilter.c:(.text+0x12c8): riferimento non definito a "cvInitFont"
/tmp/ccDUEgAk.o: nella funzione "main":
imagefilter.c:(.text+0x1396): riferimento non definito a "cvLoadImage"
imagefilter.c:(.text+0x13af): riferimento non definito a "cvGetSize"
imagefilter.c:(.text+0x13c1): riferimento non definito a "cvCreateImage"
imagefilter.c:(.text+0x13ed): riferimento non definito a "cvSmooth"
imagefilter.c:(.text+0x1403): riferimento non definito a "cvSaveImage"
imagefilter.c:(.text+0x141b): riferimento non definito a "cvReleaseImage"
imagefilter.c:(.text+0x1427): riferimento non definito a "cvReleaseImage"
collect2: error: ld returned 1 exit status
$

How should I correctly specify the libraries?


I ran the command below. It compiles and links but does not run correctly:

$ gcc imagefilter.c -o imagefilter -I/home/savio/opencv-3.0.0/include/opencv \
>     -L/home/savio/opencv-3.0.0/cmake_binary_dir/lib \
>     -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui -lopencv_core
$ ./imagefilter lena_noise.BMP
./imagefilter: error while loading shared libraries: libopencv_imgcodecs.so.3.0: cannot open shared object file: No such file or directory
$

What else am I missing?

like image 852
Saverio Avatar asked Jul 16 '15 13:07

Saverio


2 Answers

Move the -L and -l to the end of the command line:

gcc imagefilter.c -o imagefilter -I/home/savio/opencv-3.0.0/include/opencv -L/home/savio/opencv-3.0.0/cmake_binary_dir/lib -lopencv_core -lopencv_highgui -lopencv_imgproc 
like image 54
Eregrith Avatar answered Oct 15 '22 23:10

Eregrith


Linking

For linking, make sure you specify object files (or source files) before libraries (-lxxx options). And make sure the -L option for a given library appears before the -l option that uses it. The order of libraries can matter; list libraries in an order such that libraries listed earlier reference code in those listed later. (When designing sets of libraries, avoid circular references between libraries; they're a plague.)

$ gcc imagefilter.c -o imagefilter -I/home/savio/opencv-3.0.0/include/opencv \
>     -L/home/savio/opencv-3.0.0/cmake_binary_dir/lib \
>     -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui -lopencv_core

Running

Both the compiler/linker and the runtime system need to be able to find the shared objects. You use the -L option to tell the linker where to find the libraries. You have a variety of ways of telling the runtime (dynamic loader) where to find the libraries:

  1. On some systems, you can add a -R option to the command line to specify where libraries may be found at runtime:

    $ gcc imagefilter.c -o imagefilter -I/home/savio/opencv-3.0.0/include/opencv \
    >     -L/home/savio/opencv-3.0.0/cmake_binary_dir/lib \
    >     -R/home/savio/opencv-3.0.0/cmake_binary_dir/lib \
    >     -lopencv_imgcodecs -lopencv_imgproc -lopencv_highgui -lopencv_core
    

    Not all systems support this option. If yours doesn't, you have to move on.

    The disadvantage of this option is that the location you specify is embedded in the binary. If the libraries on the customers' machines is not in the same place, the library won't be found. Consequently, a path under someone's home directory is only appropriate for that user on their machines — not for the general population. OTOH, if the software is installed by default in, say, /opt/packagename/lib, then specifying that with -R is probably appropriate.

  2. Add the directory to LD_LIBRARY_PATH environment variable (or its equivalent; for example, DYLD_LIBRARY_PATH on Mac OS X, or SHLIB_PATH on HP-UX IIRC).

    LD_LIBRARY_PATH=/home/savio/opencv-3.0.0/cmake_binary_dir/lib:$LD_LIBRARY_PATH \
    ./imagefilter
    

    or:

    export LD_LIBRARY_PATH=/home/savio/opencv-3.0.0/cmake_binary_dir/lib:$LD_LIBRARY_PATH
    ./imagefilter
    

    The first notation sets the environment variable just for as long as the program is running. It can be useful if you need to compare the behaviour of two versions of a library, for example. The second notation sets the environment variable for the session. You might include that in your .profile or equivalent so it applies to every session.

    Some systems have an LD_RUN_PATH environment variable too. And some have 32-bit and 64-bit variants of the environment variables.

    This is fiddly for users and installers alike; how do you ensure the environment variable is set for everyone that uses your code? An environment-setting shell script that then runs the real program can help here.

  3. Add the directory to the configuration file that specifies the list of known directories for the dynamic loader to search. Needless to say, that's platform specific — file name, format, location (usually under /etc somewhere) and mechanism used to edit it. The file might be /etc/ld.so.conf. There might well be a program to edit the config file correctly.

  4. Install the libraries in a location that will be searched anyway (without reconfiguring the dynamic loader). This might be /usr/lib, or maybe /usr/local/lib or some other related directory.

like image 43
Jonathan Leffler Avatar answered Oct 15 '22 22:10

Jonathan Leffler