Menu

undefined reference

trynalurn
2007-11-26
2012-09-26
  • trynalurn

    trynalurn - 2007-11-26

    I've put a lot of time into trying to solve this on my own. It's complicated, (to me anyway), and I'm having a hard time trying to conceptualize it to explain it. I'm reading Johnson M. Hart's book on Windows System Programming. He gives a couple of error reporting functions to compile with his example programs and makes it necessary to include 4 different header files. One of these header files, "support.h" declare the function prototypes. I tried to compile the program and came up with these linker errors:

    =======
    [Linker Error] undefined reference to _imp__Options' [Linker Error] undefined reference to_impReportError'
    [Linker Error] undefined reference to _imp__PrintMsg' [Linker Error] undefined reference to_imp
    PrintStrings'
    =======

    Well, these are the functions he uses for error reporting. So, I began reading the header files and found that in "support.h" the prototypes are declared thus:

    =========
    LIBSPEC DWORD Options (int, LPCTSTR *, LPCTSTR, ...);
    LIBSPEC VOID ReportError (LPCTSTR, DWORD, BOOL);
    LIBSPEC BOOL PrintMsg (HANDLE, LPCTSTR);
    LIBSPEC BOOL PrintStrings (HANDLE, ...);
    =========

    I had no idea why he prefaced these prototypes with LIBSPEC and I suspected that was the source of my problem. So I removed LIBSPEC from the declarations. When I recompiled three of the four disappeared. The ReportError was now phrased:

    [Linker Error] undefined reference to 'ReportError'

    The main program is called cat.c and and I include the functions as 3 source files in the project. All the header files are includes. Here is my compile log:

    =======
    Compiler: Default GCC compiler
    Building Makefile: "C:\Hart\CAT\Makefile.win"
    Executing make clean
    rm -f Objects/MingW/cat.o Objects/MingW/Options.o Objects/MingW/ReportError.o Objects/MingW/PRINTMSG.o Output/MingW/cat.exe

    gcc.exe -c cat.c -o Objects/MingW/cat.o -I"include" -libws2_32.a

    cat.c: In function main': cat.c:18: warning: passing arg 2 ofOptions' from incompatible pointer type

    gcc.exe: -libws2_32.a: linker input file unused because linking not done

    gcc.exe -c Options.c -o Objects/MingW/Options.o -I"include" -libws2_32.a

    gcc.exe: -libws2_32.a: linker input file unused because linking not done

    g++.exe -c ReportError.c -o Objects/MingW/ReportError.o -I"C:/Program Files/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2" -I"C:/Program Files/Dev-Cpp/include" -I"C:/Program Files/Dev-Cpp/" -I"C:/Program Files/Dev-Cpp/include/common/wx/msw" -I"C:/Program Files/Dev-Cpp/include/common/wx/generic" -I"C:/Program Files/Dev-Cpp/include/common/wx/fl" -I"C:/Program Files/Dev-Cpp/include/common/wx/gizmos" -I"C:/Program Files/Dev-Cpp/include/common/wx/html" -I"C:/Program Files/Dev-Cpp/include/common/wx/mmedia" -I"C:/Program Files/Dev-Cpp/include/common/wx/net" -I"C:/Program Files/Dev-Cpp/include/common/wx/ogl" -I"C:/Program Files/Dev-Cpp/include/common/wx/plot" -I"C:/Program Files/Dev-Cpp/include/common/wx/protocol" -I"C:/Program Files/Dev-Cpp/include/common/wx/stc" -I"C:/Program Files/Dev-Cpp/include/common/wx/svg" -I"C:/Program Files/Dev-Cpp/include/common/wx/xml" -I"C:/Program Files/Dev-Cpp/include/common/wx/xrc" -I"C:/Program Files/Dev-Cpp/include/common/wx" -I"C:/Program Files/Dev-Cpp/include/common" -libws2_32.a

    g++.exe: -libws2_32.a: linker input file unused because linking not done

    g++.exe -c PRINTMSG.C -o Objects/MingW/PRINTMSG.o -I"C:/Program Files/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2" -I"C:/Program Files/Dev-Cpp/include" -I"C:/Program Files/Dev-Cpp/" -I"C:/Program Files/Dev-Cpp/include/common/wx/msw" -I"C:/Program Files/Dev-Cpp/include/common/wx/generic" -I"C:/Program Files/Dev-Cpp/include/common/wx/fl" -I"C:/Program Files/Dev-Cpp/include/common/wx/gizmos" -I"C:/Program Files/Dev-Cpp/include/common/wx/html" -I"C:/Program Files/Dev-Cpp/include/common/wx/mmedia" -I"C:/Program Files/Dev-Cpp/include/common/wx/net" -I"C:/Program Files/Dev-Cpp/include/common/wx/ogl" -I"C:/Program Files/Dev-Cpp/include/common/wx/plot" -I"C:/Program Files/Dev-Cpp/include/common/wx/protocol" -I"C:/Program Files/Dev-Cpp/include/common/wx/stc" -I"C:/Program Files/Dev-Cpp/include/common/wx/svg" -I"C:/Program Files/Dev-Cpp/include/common/wx/xml" -I"C:/Program Files/Dev-Cpp/include/common/wx/xrc" -I"C:/Program Files/Dev-Cpp/include/common/wx" -I"C:/Program Files/Dev-Cpp/include/common" -libws2_32.a

    g++.exe: -libws2_32.a: linker input file unused because linking not done

    g++.exe Objects/MingW/cat.o Objects/MingW/Options.o Objects/MingW/ReportError.o Objects/MingW/PRINTMSG.o -o "Output\MingW\cat.exe" -L"C:/Program Files/Dev-Cpp/Lib"

    Objects/MingW/cat.o:cat.c:(.text+0x124): undefined reference to `ReportError'
    collect2: ld returned 1 exit status

    mingw32-make.exe: *** [Output/MingW/cat.exe] Error 1

    Execution terminated

     
    • trynalurn

      trynalurn - 2007-11-28

      Slocombe wrote:

      "Re-create the project from scratch as an empty C project..."

      Yup. That's what I did and everything compiled and ran correctly, (except for that error warning.)

      So, I must have either set the project up wrong in the beginning or else the compiler options that were initially set played a little havoc.

      I'm really going to have to learn more about the Dev-C++ interface. I still have a heck of a lot more luck with this compiler than any of the MSVC++ compilers. But, relying on so much luck does get tiresome ;o)

      Hey, thanks mighty much for your help.

       
    • trynalurn

      trynalurn - 2007-11-26

      Sorry. Version is 4.9.9.2 and I'm using winxp.

       
    • Anonymous

      Anonymous - 2007-11-26

      Your log exhibits a number of problems and redundant stuff.

      You have added the linker option "-libws2_32.a" to your compiler options which is why it repeatedly says: "g++.exe: -libws2_32.a: linker input file unused because linking not done" for every compilation unit. If you are not using Windows Sockets, you don't need it even in the link.

      Exactly what LIBSPEC does will depend on how it is defined (it must have defined somewhere - it is a macro). Judging from the linker errors you got, I would say that these functions are expected to be found in a DLL. Just removing it may not actually be the correct thing to do. How is it defined?

      You have a large number of header file paths to wxWidgets. If you are not using wxWidgest in this project, I suggest that you remove them. It will shorten teh log and you may be able to see the wood-for-the-trees.

      It is always a good idea to fix problems from top-to-bottom, so you should at least fix the "cat.c:18: warning: passing arg 2 of `Options' from incompatible pointer type" before worrying about the linker.

      Intuitively one would imagine that ReportError() were defined in ReportError.c. Check that that is the case and that it's definition matches the declaration in the header. If it has a different number of parameters or different parameter types C++ will regard it as a different function.

      It is probably significant that the files have a .c extension and are therefore probably C code but you have managed to force Dev-C++ to use C++ compilation. The file PRINTMSG.C has a capital .C extension, this is a little used convention for C++, and the GCC compiler will assume C++ compilation for this if not directed otherwise. You should rename it using a lower case extension, and set the compilation options to C compilation rather than C++ (at least until you get it to build correctly).

      Clifford

       
    • trynalurn

      trynalurn - 2007-11-27

      Hello. Thanks for your help. I've tried to address the issues you've raised. I don't know how I got that linker option or the wxWidget paths into the project, (I must have created the project the wrong way), but they are now out of the program.

      After I posted last night, I actually got the program to compile and run, but I did it by putting #includes in the main file (cat.c) to the other source files. I'm still pretty new to coding, but I think it is incorrect to do that. I listed three additional #include directives besides the one to the "Evrythng.h" header file:

      include "ReportError.c"

      include "PrintMsg.c"

      include "Options.c"

      On compiling I got an error to the effect that "Options.c" was defined multiple times. So I took that include out and then the program compiled and ran correctly. However I do still get my initial warning about the incompatible pointer type.

      I've since compiled and ran one other program that use these same header files and functions along with another function. I was able to compile and run this second program with just #include "PRINTMSG.C" After taking your advice and changing the name of the file to "PrintMsg.c" I was able to remove that #include and so that program actually compiles and runs correctly. (Except for that warning error). So, I'm pretty puzzled. When I changed the name of PrintMsg.c for the cat.c program, I still had to include it in the main to get the program to compile and run.

      The warning error. It says "warning: passing arg 2 of `Options' from incompatible pointer type" and I'm not sure if I'm interpreting this correctly or not.

      The Options prototype is DWORD Options (int, LPCTSTR *, LPCTSTR, ...); (this is AFTER I removed the LIBSPEC prefix.
      So I take it that arg 2 is the second parameter after LPCTSTR; the second argument in the variable list. The call to the function from main that gave the warning is: iFirstFile = Options (argc, argv, _T ("s"), &DashS, NULL); So, my guess is that NULL is the argument they are warning about. I know what the Options function does, though I have to admit I've read it a few times and am a bit shaky on just how it does what it does. Here's the definition:

      ==============
      / Utility function to extract option flags from the command line. /

      include "EvryThng.h"

      include <stdarg.h>

      DWORD Options (int argc, LPCTSTR argv [], LPCTSTR OptStr, ...)

      / argv is the command line.
      The options, if any, start with a '-' in argv[1], argv[2], ...
      OptStr is a text string containing all possible options,
      in one-to-one correspondence with the addresses of Boolean variables
      in the variable argument list (...).
      These flags are set if and only if the corresponding option
      character occurs in argv [1], argv [2], ...
      The return value is the argv index of the first argument beyond the options.
      /

      {
      va_list pFlagList;
      LPBOOL pFlag;
      int iFlag = 0, iArg;

      va_start (pFlagList, OptStr);
      
      while ((pFlag = va_arg (pFlagList, LPBOOL)) != NULL
                  &amp;&amp; iFlag &lt; (int)_tcslen (OptStr)) {
          *pFlag = FALSE;
          for (iArg = 1; !(*pFlag) &amp;&amp; iArg &lt; argc &amp;&amp; argv [iArg] [0] == '-'; iArg++)
              *pFlag = _memtchr (argv [iArg], OptStr [iFlag],
                      _tcslen (argv [iArg])) != NULL;
          iFlag++;
      }
      
      va_end (pFlagList);
      
      for (iArg = 1; iArg &lt; argc &amp;&amp; argv [iArg] [0] == '-'; iArg++);
      
      return iArg;
      

      }

      As for the LIBSPEC the definition occurs in two places. The first checks to see if _STATICLIB and _cplusplus is defined. If so it defines LIBSPEC as extern "C". Otherwise it just says #define LIBSPEC if _STATICLIB is defined:

      ifdef WIN32

      / When building a static library, the only modifier needed is
      extern "C" when calling from a C++ program
      /

      ifdef _STATICLIB

      if defined (__cplusplus)

      define LIBSPEC extern "C"

      else

      define LIBSPEC

      endif / __cplusplus /

      endif / _STATICLIB /

      It then goes on:

      / Not building a static library.
      * Either export or import symbols (function names), depending upon whether we
      * are building the DLL (UTILITY_EXPORTS is defined) or importing
      * the names from a "client" calling program. A C++ client needs extern "C"
      * to use the C (rather than C++) calling convention and to avoid
      * C++ "name decoration" (often called "name mangling").
      /

      if defined(UTILITY_3_0_EXPORTS)

      define LIBSPEC _declspec (dllexport)

      elif defined(__cplusplus)

      define LIBSPEC extern "C" _declspec (dllimport)

      else

      define LIBSPEC _declspec (dllimport)

      endif

      endif / end of #ifdef WIN32 /

      So, if I got all this right I'm left with the last option and LIBSPEC was defining those functions as dllimports. So, when I removed the LIBSPEC they were left just as function prototypes.

      Or not. Maybe when I intially created this project I somehow left C++ option checked instead of switching it to C? That would maybe explain why I got all the wx path names? and why the second program didn't share these problems? (Although the second program also had LIBSPEC removed from the prototypes).

      Sorry for dumping all of this on you. I can follow some of these preprocessor directives but dll files are part of the reason I'm reading this book and I haven't gotten to them yet. Anyway, I'll close with the most recent logfile from cat.c

      =================
      Compiler: Default GCC compiler
      Building Makefile: "C:\Hart\CAT\Makefile.win"
      Executing make clean
      rm -f Objects/MingW/cat.o Objects/MingW/Options.o Objects/MingW/ReportError.o Objects/MingW/PrintMsg.o Output/MingW/cat.exe

      gcc.exe -c cat.c -o Objects/MingW/cat.o

      cat.c: In function main': cat.c:21: warning: passing arg 2 ofOptions' from incompatible pointer type

      gcc.exe -c Options.c -o Objects/MingW/Options.o

      g++.exe -c ReportError.c -o Objects/MingW/ReportError.o -I"C:/Program Files/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2" -I"C:/Program Files/Dev-Cpp/include" -I"C:/Program Files/Dev-Cpp/"

      g++.exe -c PrintMsg.c -o Objects/MingW/PrintMsg.o -I"C:/Program Files/Dev-Cpp/lib/gcc/mingw32/3.4.2/include" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/backward" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2/mingw32" -I"C:/Program Files/Dev-Cpp/include/c++/3.4.2" -I"C:/Program Files/Dev-Cpp/include" -I"C:/Program Files/Dev-Cpp/"

      g++.exe Objects/MingW/cat.o Objects/MingW/Options.o Objects/MingW/ReportError.o Objects/MingW/PrintMsg.o -o "Output\MingW\cat.exe"

      Execution terminated
      Compilation successful
      ===============

       
    • trynalurn

      trynalurn - 2007-11-27

      Forgot to say on the Options function:

      Okay. So, va_arg is written to expect a BOOL value and Null is not that. This is why the warning. But it doesn't seem to me that that is correctable with out modifying his program.

      Sometimes you just want to live with a warning? Or can you somehow cast NULL to be a bool type?

       
    • Anonymous

      Anonymous - 2007-11-27

      >> I don't know how I got that linker option or the wxWidget paths into the project
      Perhaps you have them set in Tool->Compiler options, which are inherited whenever you create a project.

      >> I did it by putting #includes in the main file (cat.c) to the other source files.
      Nasty solution. but it does point to what your problem was (it was apparent in teh original log but I did not spot it directly). By doing that all the modules will be compiled as C code because cat.c was compiled as C code. The other modules were compiled as C++ so will have been incompatible with the calls in cat.c (the symbols will not have matched). So as I suggested, you need to use all C or all C++ compilation, not a mix of both!

      Your second log still shows mixed compilation.

      >> On compiling I got an error to the effect that "Options.c" was defined multiple times.
      Because one of the other files you included also includes it. That is one reason why it is not a practical solution. More complex projects will become unmanagable.

      >> So I take it that arg 2 is the second parameter after LPCTSTR;
      No - arg 2 is the second parameter! argv os a char*, LPCSTR may resolve to something different. Use could use a cast to 'hide' the warning.

      It seems that LIBSPEC is just a macro to force C linkage for code compiled as C++ when building a static library or a DLL. Because you are building neither, it was incorrcetly defined. Therein lies the problem, the author did not expect you to do mixed C/C++ compilation. His method of ensuring correct linkage qualifiers is not very robust, but then again your use of mixed compilation is not a good idea (and no doubt not intentional).

      Any way it seems that almost all your problems stem from the mixed C/C++ compilation. Your second log still shows separate compilation of the modules you #include'ed. The only reason you get away with this is because tehy are compiled as C++ not C, so the symbols are different and do not conflict.

      I suggest that you revert to the original code - there was not much wrong with it. Currently you merely have one bad practice cancelling out another!. Re-create the project from scratch as an empty C project, and add the existing files to the project. Alternatively you can fix the compilation mode for each file separately from the Project->Project options->Files dialog. You must do this. See in the log you have invocations of both g++ and gcc - it should be one or the other but not both.

      Clifford

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.