- was not declared in this scope
- no such a file or directory
- undefined reference to
- error while loading shared library, or cannot open shared object file
The thing is actually very simple: the compiler is not told to find the right file at the right place. The discussion below is based on Linux using GCC for C and C++.
Problem 1: was not declared in this scope
Usually, this problem has nothing to do with your system settings or compiler configuration. It's a problem within your source code. On the top level, the function is not defined. The reason can vary. One reason is that the file declaring (or defining, if the declaration is done together with definition) the functions is not specified, e.g., the header file is not included. This can be easily fixed by including such a file in your source code.
Another reason is that you used the function beyond its class or namespace.
Problem 2: No such a file or directory
for a header file
If a header file is not found, the preprocessor or the preprocessor part of the compiler, will raise the error
No such a file or directory
. Depends on where the header files are supposed to be at, there are different solutions. Most C/C++ compiles treat the quote form of
#include
and angle-bracket form of #include
differently. Simply running $ echo | gcc -E -Wp,-v -will tell you the difference:
#include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/x86_64-linux-gnu/5/include /usr/local/include /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed /usr/include/x86_64-linux-gnu /usr/include
Those directories listed under the section
#include <...> search starts here:
are referred to as standard system directories [1]. They are from the convention of Linux systems' file hierarchy. If you want to expand the search for angle-bracket form
#include<...>
, use the -I
option. The preprocessor will search header files in directories followed by -I
option before searching system directories. Hence, a header file in a -I
-option directory will override its counterpart in system directories and be used to compile your code. For quote form
#include"..."
, the preprocessor will first search in the current directory that the source file is at and then all the directories specified after the -iquote
option.The example below will show you how
-I
and -iquote
append search paths:l$ echo | gcc -iquote/home/forrest/Downloads -I/home/forrest/Dropbox -E -Wp,-v - #include "..." search starts here: /home/forrest/Downloads #include <...> search starts here: /home/forrest/Dropbox /usr/lib/gcc/x86_64-linux-gnu/5/include /usr/local/include /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed /usr/include/x86_64-linux-gnu /usr/include
So, if you have the following macro in your code called
mycode.c
:#include < xyz.h> #include "abc/xyz.h"and your GCC command is like this
gcc mycode.c -I/opq/ -iquote/uvwthen the GCC's preprocessor (again, it's part of the GCC) will look for header files in the following full paths (on Ubuntu Linux 16.04) in addition to the search in system directories:
/opq/xyz.h /uvw/abc/xyz.hAccording to GCC document[1], it searches for header files in quote form
#include"..."
before searching for angle-bracket form #include"..."
. Further specifications can be achieved using two other options
-isystem
and -idirafter
. They are all well documented in GCC document[2]. Problem 3: Undefined reference to
You probably see an error like this face.cpp:(.text._ZN2cv3Mat7releaseEv[_ZN2cv3Mat7releaseEv]+0x4b): undefined reference to `cv::Mat::deallocate()' collect2: error: ld returned 1 exit statusThis is a link-time error when the linker
ld
, which is called automatically when you use GCC, cannot find the binary library that contains at least one function called by your code. To fix, first tell the compiler (actually it's linker part) the path containing library files using the
-L
option [2] and then library file names using the -l
option [4]. If we denote the values after -l
and -L
options as X and Y respectively, the compiler will search for every file called libY.so
under every directory X. That's why on (almost) all Linux systems, a shared library file begins with lib
and ends with the appendix .so
, such as libopencv_core.so
.For example, the command
$ g++ face.cpp -L/opencv/lib -lopencv_core -lopencv_videoiowill ask the linker to find the following binary library files:
/opencv/lib/libopencv_core.so /opencv/lib/libopencv_videoio.so
Note that you may not be able to use some shell directives, such as
~
after the -L
option. In most cases, you do not need to use the
-L
and -l
options because the compiler (again, its linker part) automatically searches in a set of system directories. When you have to, some tools can help you, such as pkg-config. I will write another blog post. Problem 4: error while loading shared libraries
or cannot open shared object file
Now, your program has been successfully compiled. When running it, you probably see an error like this:
./a.out: error while loading shared libraries: libopencv_core.so.3.3: cannot open shared object file: No such file or directoryThis problem is from the loader. Unlike the link-time error above, this problem is a run-time error. The shared library filenames are usually hardcoded into your binary program. To fix it, simply tell the loader where to find the specified shared library files. There are multiple ways.
Solution 1: Most Linux systems maintain an environment variable
LD_LIBRARY_PATH
and the loader will search for binary library files requested by a program in all directories listed in LD_LIBRARY_PATH
, on top of a set of standard system directories, such as /lib
or /usr/lib
. To set LD_LIBRARY_PATH
is like how you set any other environment variables, e.g., export on the Shell or edit and source ~/.bashrc
. Solution 2: Most Linux systems also maintains a shared library cache by a program called
ld-config
. It remembers where to find the default location of each shared library file. Simply run $ ldconfig -pit will tell you the mapping from shared library files to absolute paths in the system, e.g.,
2591 libs found in cache `/etc/ld.so.cache' libzzipwrap-0.so.13 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzzipwrap-0.so.13 libzzipmmapped-0.so.13 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzzipmmapped-0.so.13 libzzipfseeko-0.so.13 (libc6,x86-64) => /usr/lib/x86_64-linux-gnu/libzzipfseeko-0.so.13
To change the mapping, simply edit
/etc/ld.so.conf
and then run $ sudo ldconfigto rebuild the cache.
Solution 3: The two changes above are applied system-wide. A more flexible way is to specify the location of the shared libraries when linking your code using the
-Wl,-rpathoption, e.g.,
g++ face.cpp -idirafter ~/Downloads/opencv_TBB_install/include -L/home/forrest/Downloads/opencv_TBB_install/lib -lopencv_core -lopencv_objdetect -lopencv_highgui -lopencv_imgproc -lopencv_videoio -Wl,-rpath=/home/forrest/Downloads/opencv_TBB_install/lib
The disadvantage of Solution 3 is that if you change the location of the shared library, then you will run into error again.
References:
[1] Filesystem Hierarchy, https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] GCC options for directories https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html
[3] Shared Library How-To, http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
[4] GCC options for linking, https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html
No comments:
Post a Comment