Underfined Reference to “xxx” When Use GCC

1. Problem Descirble

It is common for us to meet the problem when we use gcc to link and generate the executable problem, such as:

xxxx.o: undefined reference to `function_name`
error: ld return 1 exit status

Hence, What should we do next?

2. Reason and Solution

It is a command problem, so we should be more specific. According to the error message, we could think the basic reason is:

The Gcc linker can not find the definition of the "function_name"

But Why? What should we do to solve problem?

2.1 Missing the object/library

The most usual reason, the first one we should think about. just the find the source code containing the definition of function_name(.c,.cpp,.f or other), and then compile to object(.o,.a,.so), and then link with the object. Of course, if the function_name belongs to the third party libraries(such math,lapack), we should make sure the library have installed properly and have a correct link method.

In gcc, we could find link in two method: Direct filename and Use -L&l option.

Direct filename is easy, Just add the full/relative path and filename togather, no need for special filename. For example:

gcc a.o ../b.o ../c.so ../../d.a -o a.out

Use -L&l option, which mean that, gcc will search the -L include path, then choose the -l library. It needs special library file name. For example:

gcc -L ./ -la -o a.out

The command above will search under the directory ./(of course, default including system’s library, such as: /usr/lib), and then link liba.so or liba.a(-lb corresponding to libb.so or libb.a). If both have liba.so and liba.a, it will use liba.a preferentially.

2.2 Use -static option

Gcc -static option will force linker to use static library and ignore dynamic shared library, So if we add the option with gcc, the linker will not check the *.so at all!

2.3 Compatibility of Library

We should know that differect versions of library have different api, If we need to use a third party library, we should make sure the compatibility of library.

2.4 c/c++ mixed compilelation

Actually, the prcessing of c and c++ in gcc are a little different, If we just quote each other and compile directly, we may meet the undefined reference problem. The solution is use extern "C" to solve the problem. For exmple:

#ifdef __cplusplus
extern "C"{ //It will generate different object code between g++ and gcc
#endif
    void cpp_implementation_fun();
#ifdef __cplusplus
}
#endif

2.5 The Order of Objects

We must notice the impact of the order of the libraries., Here We will cite a answer of stackoverflow

Common files shared by all below commands

$ cat a.cpp
extern int a;
int main() {
  return a;
}

$ cat b.cpp
extern int b;
int a = b;

$ cat d.cpp
int b;

2.5.1 Linking to static libraries

$ g++ -c b.cpp -o b.o
$ ar cr libb.a b.o
$ g++ -c d.cpp -o d.o
$ ar cr libd.a d.o

$ g++ -L. -ld -lb a.cpp # wrong order
$ g++ -L. -lb -ld a.cpp # wrong order
$ g++ a.cpp -L. -ld -lb # wrong order
$ g++ a.cpp -L. -lb -ld # right order

The linker searches from left to right, and notes unresolved symbols as it go. If a library resolves the symbol, it takes the object files of that library to resolve the symbol (b.o out of libb.a in this case).

Dependencies of static libraries against each other work the same – the library that needs symbols must be first, then the library that resolves the symbol.

If a static library depends on another library, but the other library again depends on the former library, there is a cycle. You can resolve this by enclosing the cyclically dependent libraries by -( and -), such as -( -la -lb -) (you may need to escape the parens, such as -\( and -\)). The linker then searches those enclosed lib multiple times to ensure cycling dependencies are resolved. Alternatively, you can specify the libraries multiple times, so each is before one another: -la -lb -la.

2.5.2 Linking to dynamic libraries

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!

$ g++ -L. -lb a.cpp # wrong order (works on some distributions)
$ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order
$ g++ -Wl,--as-needed a.cpp -L. -lb # right order

It’s the same here – the libraries must follow the object files of the program. The difference here with the static libraries is that you must not care about the dependencies of the libraries against each other, because dynamic libraries sort out their dependencies themselves.

Some recent distributions apparently default to using the --as-neededlinker flag, which enforces that the program’s object files come before the dynamic libraries. If that flag is passed, the linker will not link to libraries that are not actually needed by the executable (and it detects this from left to right). My recent archlinux distribution doesn’t use this flag by default, so it didn’t give an error for not following the correct order.

It is not correct to omit the dependency of b.so against d.so when creating the former. You will be required to specify the library when linking a then, but a doesn’t really need the integer b itself, so it should not be made to care about b‘s own dependencies.

Here is an example of the implications if you miss specifying the dependencies for libb.so

$ export LD_LIBRARY_PATH=.  # not needed if libs go to /usr/lib etc
$ g++ -fpic -shared d.cpp -o libd.so
$ g++ -fpic -shared b.cpp -o libb.so    # wrong (but links)

$ g++ -L. -lb a.cpp         # wrong, as above
$ g++ -Wl,--as-needed -L. -lb a.cpp     # wrong, as above
$ g++ a.cpp -L. -lb         # wrong, missing libd.so
$ g++ a.cpp -L. -ld -lb     # wrong order (works on some distributions)
$ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs)
$ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right" (look right,but wrong)

If you now look into what dependencies the binary has, you note the binary itself depends also on libd, not just libb as it should. The binary will need to be relinked if libb later depends on another library, if you do it this way. And if someone else loads libb using dlopen at runtime (think of loading plugins dynamically), the call will fail as well. So the “right” really should be a wrong as well.

2.5.3 Use –start-group

If you add -Wl,--start-group to the linker flags it does not care which order they’re in or if there are circular dependencies.Saves loads of time messing about and it doesn’t seem to slow down linking much (which takes far less time than compilation anyway).

3 Conclusion

We May need a bit more spirit of exploration.

此条目发表在CODING, LINUX分类目录,贴了标签。将固定链接加入收藏夹。

发表评论

电子邮件地址不会被公开。