¿Cómo especificar rutas de bibliotecas en gcc?

8 minutos de lectura

avatar de usuario
Saverio

Estoy escribiendo un programa usando llamadas OpenCV y quiero compilarlo y hacer el ejecutable. Ya leí el tutorial de gcc pero aún me gustaría saber exactamente cómo vincular las bibliotecas de OpenCV que estoy usando. Mi comando y la salida relacionada están a continuación:

$ 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
$

¿Cómo debo especificar correctamente las bibliotecas?


Ejecuté el siguiente comando. Compila y vincula pero no se ejecuta correctamente:

$ 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
$

¿Qué más me estoy perdiendo?

Mueva -L y -l al final de la línea de comando:

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 

  • savio@savio-R580:~/programmi$ 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 /tmp/ccyNTX5t.o: nella funzione “main”: imagefilter.c:(.text+0x1396): riferimento non definito a “cvLoadImage” imagefilter.c:(.text+0x1403): riferimento non definito un “cvSaveImage” collect2: error: ld devolvió 1 estado de salida

    – Saverio

    16 de julio de 2015 a las 13:52

  • No usaste el comando que escribí. Por qué -l/home/... ? Esto no funcionará. Necesitas -L/home/...../opencv

    – Eregrith

    16 de julio de 2015 a las 13:54

  • Copié y pegué exactamente su comando y el resultado es ese.

    – Saverio

    16/07/2015 a las 14:00

  • ah es un I no un l si, lo siento. Has comprobado que hay esos libopencv_highgui.a, libopencv_core.a y libopencv_imgproc.a en /home/savio/opencv-3.0.0/cmake_binary_dir/lib ?

    – Eregrith

    16 de julio de 2015 a las 14:07


  • los -l las opciones que especifican los nombres de las bibliotecas deben aparecer después de los nombres de los archivos de objetos. los -L Las opciones, que especifican un directorio de biblioteca, deben aparecer antes de la -l opciones para las bibliotecas que están almacenadas en el directorio.

    –Jonathan Leffler

    16 de julio de 2015 a las 14:23

avatar de usuario
jonathan leffler

Enlace

Para vincular, asegúrese de especificar los archivos de objeto (o archivos de origen) antes de las bibliotecas (-lxxx opciones). Y asegúrese de que -L opción para una biblioteca determinada aparece antes de la -l opción que lo utiliza. El orden de las bibliotecas puede importar; enumere las bibliotecas en un orden tal que las bibliotecas enumeren el código de referencia anterior en las enumeradas más adelante. (Al diseñar conjuntos de bibliotecas, evite las referencias circulares entre bibliotecas; son una plaga).

$ 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

Correr

Tanto el compilador/enlazador como el sistema de tiempo de ejecución deben poder encontrar los objetos compartidos. usas el -L opción para decirle al enlazador dónde encontrar las bibliotecas. Tiene una variedad de formas de decirle al tiempo de ejecución (cargador dinámico) dónde encontrar las bibliotecas:

  1. En algunos sistemas, puede agregar un -R opción a la línea de comando para especificar dónde se pueden encontrar las bibliotecas en tiempo de ejecución:

    $ 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
    

    No todos los sistemas admiten esta opción. Si el tuyo no lo hace, tienes que seguir adelante.

    La desventaja de esta opción es que la ubicación que especifique está incrustada en el binario. Si las bibliotecas de los equipos de los clientes no están en el mismo lugar, no se encontrará la biblioteca. En consecuencia, una ruta en el directorio de inicio de alguien solo es apropiada para ese usuario en sus máquinas, no para la población en general. OTOH, si el software está instalado de forma predeterminada en, digamos, /opt/packagename/libluego especificando que con -R probablemente sea apropiado.

  2. Añadir el directorio a LD_LIBRARY_PATH variable de entorno (o su equivalente; por ejemplo, DYLD_LIBRARY_PATH en Mac OS X, o SHLIB_PATH en HP-UX IIRC).

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

    o:

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

    La primera notación establece la variable de entorno solo durante el tiempo que se ejecuta el programa. Puede ser útil si necesita comparar el comportamiento de dos versiones de una biblioteca, por ejemplo. La segunda notación establece la variable de entorno para la sesión. Podrías incluir eso en tu .profile o equivalente por lo que se aplica a cada sesión.

    Algunos sistemas tienen un LD_RUN_PATH variable de entorno también. Y algunos tienen variantes de 32 y 64 bits de las variables de entorno.

    Esto es complicado tanto para los usuarios como para los instaladores; ¿Cómo se asegura de que la variable de entorno esté configurada para todos los que usan su código? Un script de shell de configuración del entorno que luego ejecuta el programa real puede ayudar aquí.

  3. Agregue el directorio al archivo de configuración que especifica la lista de directorios conocidos para que busque el cargador dinámico. No hace falta decir que eso es específico de la plataforma: nombre de archivo, formato, ubicación (generalmente bajo /etc en algún lugar) y el mecanismo utilizado para editarlo. El archivo podría ser /etc/ld.so.conf. Bien podría haber un programa para editar el archivo de configuración correctamente.

  4. Instale las bibliotecas en una ubicación en la que se buscará de todos modos (sin reconfigurar el cargador dinámico). Esto podría ser /usr/libo tal vez /usr/local/lib o algún otro directorio relacionado.

  • Con respecto al primer artículo. La opción -R no se reconoce en mi sistema Ubuntu/gcc. ¿Con respecto al directorio de adición a LD_LIBRARY_PATH? ¿Cómo puedo hacerlo?

    – Saverio

    16 de julio de 2015 a las 14:51


  • Lo lamento; si la primera opción no funciona, pase a las opciones 2 y 3 (y la opción 4 recién agregada).

    –Jonathan Leffler

    16 de julio de 2015 a las 14:58

La forma en que mi IDE maneja el proceso es colocar la etiqueta -L al frente y la etiqueta -l al final. Todas las etiquetas -l deben aparecer después de su objetivo para que el compilador sepa qué símbolos deben resolverse antes de buscar.

gcc -L/path/to/library -o target_here -lfirst -lsecond -lthird ...

¿Ha sido útil esta solución?