Search code examples
c++g++mingwlinker-errorspsapi

Why does the compiler throw "undefined reference to ..." despite providing all needed libraries in the arguments


I'm working on a program that will monitor the usage of chosen programs and will log it into a .csv file. That way, I can determine what programs use up the most of a certain resource while I run a game in full-screen. I have included the psapi header like so:

...
#include <psapi.h>
...

And I compile with MinGW's G++ with the following options and necessary libraries for the function I'm using (libraries were from the documentation of the function): g++ -lkernel32 -lpsapi test.cpp -o test.exe

Yet it still throws the error:

c:/mingw/bin/../lib/gcc/mingw32/8.2.0/../../../../mingw32/bin/ld.exe: C:\Users\james\AppData\Local\Temp\cclpYDm2.o:test.cpp:(.text+0x3e7): undefined reference to `GetProcessMemoryInfo@12'
collect2.exe: error: ld returned 1 exit status

I feel that either something is wrong with my library or there's something I'm doing wrong. I've tried surrounding the header with "extern "C"" and I still get the same exact message. I have also verified that the library exists; if it did not, the compiler would have thrown a different error. #pragma comment does not work either, and using the -static flag has no effect. I have also tried defining the PSAPI_VERSION macro and setting it to 1, placing it before the include statement of psapi.

TL;DR: Compiler is throwing an undefined reference error despite having correct libraries. I suspect it's either:

  • Library was installed incorrectly
  • I'm doing something wrong on linking

Solution

  • Please try this instead. The sequence of arguments you provided to g++ actually matters. Always put the library at the end of your arguments.

    g++ -o test.exe test.cpp -lkernel32 -lpsapi
    

    The g++ tool chain will first go through test.cpp and compile it to a binary object file, which is a temporary file having a funny name, but let us call it test.o for now. At this time, there are still some function references in test.o which cannot be resolved.

    Then, the g++ tool chain sees -lkernel32 and then -lpsapi. It goes in these two libraries in sequence and find those missing functions in test.o for you.

    If you are linking statically, it will copy the compiled binary code of the functions in need from the library and splice it to test.o. If you are linking dynamically, it will set up some "entry" to the dynamic library.

    This is what makes the sequence to be important. The compiler tool chain will only copy (set up entry) those function in need, since a library is typically very large and contains many other functions you don't really need. When currently nothing is needed from the libraries, like the command you originally wrote, g++ needs nothing from -lkernel32 -lpsapi before running into test.cpp, it will simply skip those libraries.

    In short, if lib_a depends on lib_b, you should put lib_a before lib_b in the arguments. In rare cases where lib_x depends on lib_y which in turn depends on lib_x, you must write something like g++ file.cpp lib_x lib_y lib_x.

    Note that this rule only applies to libraries. All functions in the source file will be kept in the binary object file. Thus, even if file_x depends on file_y, writing g++ file_y.cpp file_x.cpp is okay, since all functions are kept in file_y.o and file_x.o, when linking them together, the linker can find them.

    Related question: GCC C++ Linker errors: Undefined reference to 'vtable for XXX', Undefined reference to 'ClassName::ClassName()'