PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 1/13 TITLE : Understanding "Undefined Symbol" Error Messages. One of the most common error messages seen by developers using a C or C++ compiler is "undefined symbol." This document provides a general description of what causes undefined symbol error messages, as well as instructions on solving specific undefined symbol errors. UNDEFINED SYMBOL AT COMPILE TIME An undefined symbol at compile time indicates that the named identifier was used in the named source file, but had no definition in the source file. This is usually caused by a misspelled identifier name, or missing declaration of the identifier used. EXAMPLE 1: int main(void) { test = 1; return 0; } The code shown for example one will cause an undefined symbol error message to be displayed because the variable "test" has not been declared in either a header file which has been included or in the actual code itself. EXAMPLE 2: int main(void) { int test; Test = 1; return 0; } The code shown for example one will cause an undefined symbol error message to be displayed because when the variable "test" was used it was misspelled. The misspelling was a capital 't' instead of a lower case 't'. EXAMPLE 3: int main(void) { int test; PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 2/13 TITLE : Understanding "Undefined Symbol" Error Messages. test = 1; return 0; } The code shown in example three has no errors and is an example of what must be done to resolve an undefined symbol error message. In the example here we simply made sure we have a definition for the integer test and that we spelled it the same at the time we used it. It's that simple! UNDEFINED SYMBOL AT LINK TIME When linking multi-file projects, the linker must resolve all references to functions and global variables shared between modules. When these references cannot be resolved, the linker generates an "undefined symbol" error message. This means that after searching all of the object files and libraries which are included in the link, the linker was unable to find a declaration for the identifier you were using. This can be caused by: forgetting to include a needed object module or library in your link (project file, response file, or command line). misspelling the name of the undefined symbol either where it was used or where it was declared. in the case of global variables, all may have been declared "extern". mixing C++ with C or Assembly modules, you may have forgotten to use extern "C" to disable name mangling. See the specific entry on this subject elsewhere in this document or consult the helpme!.doc file included with the product. one of your modules may have Generate Underbars turned OFF. If all else fails, TDUMP.EXE both object modules and note any difference between symbols. This will usually trigger an insight sufficient to resolve the problem. For more PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 3/13 TITLE : Understanding "Undefined Symbol" Error Messages. information on using TDUMP to resolve undefined symbol errors see the "Getting a Closer Look" section in this document. COMMON UNDEFINED SYMBOL ERRORS The following list provides solutions to some of the more common causes of undefined symbol errors: UNDEFINED SYMBOL WHEN LINKING A BORLAND EXAMPLE: Almost all of the Borland's examples come with project files. You must use the project file when building the example to ensure that all necessary modules linked and all necessary settings are defined. UNDEFINED SYMBOL WHEN TLINKING FROM DOS COMMAND LINE The TLINK command line must have the libraries in the following order ( GRAPHICS.LIB + + EMU.LIB + MATH (S,T,C,M,L - for model) + C (S,T,C,M,L - for model) UNDEFINED SYMBOL LINKING C/C++ AND ASSEMBLY MODULES There are several sources of undefined symbol errors when trying to link assembly with C or C++ modules: The Turbo Assembler generates all upper-case symbols unless you specify /ml or /mx on the assembly command line. Since C modules are, by default, case sensitive, failing to do this will result in undefined symbols for all symbols that are not completely upper case in the C module(s). The symbols in the assembly file being referenced from a C module must be declared using a PUBLIC directive. TLINK will not consider symbols that are not declared PUBLIC in an attempt to resolve and undefined symbol condition. All symbols in the assembly module that are referenced in the C module must be prototyped/declared as extern in the C module otherwise the compiler will generate undefined symbol errors for such symbols. PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 4/13 TITLE : Understanding "Undefined Symbol" Error Messages. All symbols in the assembly module that will be referenced from a C module must have a underscore prefix. This naming convention must be used in the assembly module. You can do this explicitly (_symbol) or you can use: .model , C to specify this implicitly for all symbols. IMPORTANT NOTE: If you put underscores in front of your assembly routines and also specify the .model , C directive, however, the public symbol will be generated with two underscores; consequently an undefined symbol error will be generated. If all else fails, TDUMP both object modules and note any difference between symbols. This will usually trigger an insight sufficient to resolve the problem. For more information on using TDUMP to resolve undefined symbol errors see the "Getting a Closer Look" section in this document. UNDEFINED SYMBOL LINKING C++ WITH C OR ASSEMBLY MODULES C++ is a strongly typed language. In order to support type-safe linkage (as well as function overloading), Borland C++ must attach information to the symbols generated for function names and variables. When this is done, the symbol will no longer match the standard C style function name. In order to link correctly with C or assembly modules, the compiler must be notified that the symbol is to be in the standard C style (non-encoded) rather than employing C++ name-mangling (encoded). This is done by prototyping the function as type extern "C". Here is a quick example: extern "C" int normal_c_func( float, int, char ); For an additional example, you may want to look at the PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 5/13 TITLE : Understanding "Undefined Symbol" Error Messages. header files which came with the product. One such header file is stdio.h. UNDEFINED SYMBOL: '_main' IN MODULE C0.ASM Every C program must contain a function called main(). This is the first function executed in your program. The function name must be all in lower case. If your program does not have one, create one. If you are using multiple source files, the file that contains the function main() must be one of the files listed in the project. Note that an underscore character '_' is prepended to all external Turbo C++ symbols. In addition to an absent, misspelled or mis-cased symbol main, there are two additional common causes: The "generate underbars" option is disabled. The Pascal calling Convention rather than the C calling convention is selected. UNDEFINED SYMBOL LINKING A DLL It is relatively simple to link a DLL to your source: create a .LIB for the DLL using Borland's implib utility include the LIB in your project if using the IDE or in your link if using the command-line compiler or linker. turn case sensitive link ON turn case sensitive exports ON The issues of linking C++ with C, assembly, or any other language still apply. See the sections on linking C++, C, and assembly in this document. If the link still fails, the techniques in the section PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 6/13 TITLE : Understanding "Undefined Symbol" Error Messages. "Getting A Closer Look" should help you resolve the problem. UNDEFINED SYMBOL: A PSEUDO REGISTER (ie. _AX) Pseudo registers are only allowed in the Turbo C++ and ANSI modes of the compiler. You can change this setting in the Options | Compiler | Source menu. UNDEFINED SYMBOL: 'FIWRQQ' Your program uses floating point routines directly (or indirectly) and you have NONE selected for floating point. OR, you are using TLINK and have forgotten to include EMU.LIB or FP87.LIB on the command line. UNDEFINED SYMBOL: AN IOSTREAM CLASS MEMBER If you are using the Integrated Development Environment simply turn off Options | Compiler | Code Generation | Unsigned Characters. If you are using the command line compiler simply remove the '-K' option. UNDEFINED SYMBOL: 'abort()' The sole purpose of abort is to print the error message "Abnormal Program Termination" and exit the program with an error code of 3. This function is located in the startup code C0.ASM. Linker errors indicating that abort() is an undefined symbol are only possible if the standard startup code is not being linked into a project. Although this is not common is routine C/C++ development exercises, it is to be expected when linking in code written other languages such Microsoft Fortran, and Clipper and in cases where embedded systems are being developed. PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 7/13 TITLE : Understanding "Undefined Symbol" Error Messages. To resolve the undefined symbol, extract the abort() function from the startup code and make a separate object out of it to be linked into the project. UNDEFINED SYMBOL: '_exitclean()' There is a function called _exitclean which is new to Turbo C++. Users moving from Turbo C 2.0 to Turbo C++ may encounter _exitclean() as an undefined symbol at link time. _exitclean() is defined in the Turbo C++ startup code. Users creating embedded system (rommable code), who do not use the standard Turbo C++ startup code, are likely to encounter _exitclean() as an undefined symbol. These users can strip the function from the C0.ASM file and create a separate .OBJ file which can be linked. Another option would be to purchase the TC++ RTL source and make the necessary adjustments. UNDEFINED SYMBOL: LLSH or SCOPY or FMUL or FDIV The helper functions have changed their names from Turbo C 2.0 to Turbo C++. This can lead to many undefined symbol issues. When LLSH or SCOPY or FMUL or FDIV (note no underscores here) appear as undefined symbols at link time, it is likely that an object module or library has code generated a call to some helper function from the Turbo C 2.0 libraries. The solution is to simply recompile all objects from source. You can do this by choosing Compile | BuildAll from the menu in the Integrated Development Environment. UNDEFINED SYMBOL: STATIC POINTER TO A CLASS MEMBER FUNCTION Any static member of a class must be initialized otherwise that static member generates an undefined symbol error. The following is an example of how to initialize a static pointer to class member function of a class is initialized: // When testing static member initialization, you must PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 8/13 TITLE : Understanding "Undefined Symbol" Error Messages. // declare an instance of the class in a main function; // otherwise, the linker has no reference which it must // try to resolve, and the undefined symbol error will // not be seen - thus you won't know that your // initialization was in error. #include // used to allow global initialization of static member // pointer typedef void (*fptr)(); // declare class containing static members class First { public: static fptr statptr; }; // initialize static members of class First fptr First::statptr = NULL; int main(void) { First fVar; if (fVar.statptr == NULL) cout << "fVar.statptr is NULL: " << fVar.statptr << endl; return 0; } // end of main() UNDEFINED SYMBOL: '_WSPRINTF' Turn off the "Case-sensitive exports" and "Case- sensitive link" options. If you are using the command linker, don't use the /c switch. If you are invoking the linker from the BCC(x) command line, use the -lc- switch. If you are using the IDE, go to the linker options dialog box and turn off the case sensitivity switch. PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 9/13 TITLE : Understanding "Undefined Symbol" Error Messages. UNDEFINED SYMBOL: 'fidrqq' You will get undefined symbol fidrqq when using the Integrated Development Environment if you have the Options | Compiler | Code Generation | More | Floating Point Option set to NONE and you are using floating point arithmetic in your program. In order to best solve this problem you must set the IDE option for Floating Point to either the emulation choice or to the 80x87 choice. Note that if you choose an 80x87 setting the application generated by the compiler will require an 80x87 chip to be present at run-time. Use this setting only when truly appropriate. UNDEFINED SYMBOL IN WINDOWS.H Make sure you are using the windows.h file that came with Borland C++, NOT the windows.h that came with the Microsoft Windows SDK. If you include the Microsoft windows.h file you will get many undefined symbols including WINMAIN in caps and translatemessage in lower case. Use our windows.h file instead of Microsoft's when you are using our compiler. UNDEFINED SYMBOL USING TCLASDLL.LIB To use the DLL version of the container class library you must do ALL of the following: use the large memory model use Smart Callbacks turn case sensitive link ON turn case sensitive exports ON use the DLL version of the RTL define _CLASSDLL UNDEFINED SYMBOL USING SELECTORS PROVIDED BY WINDOWS If you are using _C000h or other selectors provided by PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 10/13 TITLE : Understanding "Undefined Symbol" Error Messages. Windows and they are coming up as undefined symbols, perhaps you are compiling in C++ mode and forgot to extern "C" them. Programming in C: extern WORD _C000h Programming in C++: extern "C" WORD _C000h UNDEFINED SYMBOL: 'ChangeSelector' The Windows API function ChangeSelector() has the wrong name in KERNEL.EXE for Windows 3.0, and therefore in IMPORT.LIB. The name given to this function (this is NOT a joke) is PrestoChangoSelector(). Use PrestoChangoSelector() in your program in place of ChangeSelector() and all will be well. UNDEFINED SYMBOLS USING THE OBJECTWINDOWS LIBRARY (OWL) If you get the undefined symbols TApplication(unsigned char far *, unsigned int, unsigned int, unsigned char far *, int ) and TWindow::TWindow(TWindowsObject near *, unsigned char far *, TModule near *) and are using the DLL versions of OWL and the Class Library, you must define _CLASSDLL in Options | Compiler | Code Generation | defines combo box. It could be because you have forced unsigned characters. The functions in the .lib take signed characters and thus if you compile to use unsigned characters, the symbols will not match. Using the Integrated Development Environment be sure PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 11/13 TITLE : Understanding "Undefined Symbol" Error Messages. to turn off Options | Compiler | Code Generation | Unsigned Characters. If you are using the command line compiler be sure to remove the -K option to solve this problem. UNDEFINED SYMBOL: 'Object::new(unsigned int)' You forgot to link with the TCLASDLL.LIB file where it is defined! Basically the problem is that you are mixing both STATIC and DYNAMIC LINK libraries into the application. You must use only one or the other. If you are working in the IDE, change the LINKER options section for libraries. If you are using the dynamic link library, remember to set _CLASSDLL and Build All. If you are using the command line compiler and linker, just be sure to specify the correct set of library files. For specific information on the "correct set of library files" please see the documentation included with the product as library names tend to change from version to version. GETTING A CLOSER LOOK Borland provides tools that you can use to determine exactly what the linker is seeing when it is trying to match symbols: TDUMP and IMPDEF. This section provides some simple techniques for using these utilities to resolve undefined symbol errors. USING TDUMP TO RESOLVE UNDEFINED SYMBOLS TDUMP can be used to list the symbols in a .OBJ or a static .LIB that the linker is having trouble matching. First, TDUMP the module that is trying to reference the symbol. For example, if main.cpp is trying to PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 12/13 TITLE : Understanding "Undefined Symbol" Error Messages. access a function, myfunc() in myfuncs.cpp and is getting "Undefined symbol myfunc() in module main.cpp", tdump -m -oiEXTDEF main.obj > main.ext Then, TDUMP the module in which the symbol is defined. tdump -m -oiPUBDEF myfuncs.obj > myfunc.pub Using a text editor find the symbol associated with the error in each file. If they are not the same, then you have verified that the linker is correct in generating the error. You must check your code and verify that the compiler is seeing the same declaration for the symbol when each module is being compiled. You can use TDUMP to look at a static .LIB the same way you look at a .OBJ. tdump -m -oiPUBDEF mystatic.lib > mystatic.pub To use TDUMP with an implib, tdump -m -oiTHEADR mydll.lib > mydll.pub You can also use IMPDEF to view the symbols exported by a DLL. USING IMPDEF TO RESOLVE UNDEFINED SYMBOLS IN A DLL If you are trying to link a Borland generated DLL with another language or product and are getting undefined symbol errors, you should verify that the names or the ordinals that are being exported by the DLL are the same as your application expects. This can be done by generating a .DEF file with the utility IMPDEF. For example, to create a .DEF file for MY.DLL, impdef my.def my.dll PRODUCT : Borland C++ NUMBER : 864 VERSION : ALL OS : ALL DATE : October 19, 1993 PAGE : 13/13 TITLE : Understanding "Undefined Symbol" Error Messages. The .DEF file will have the exported symbol name and its ordinal number. Remember that C++ mangles names. Your application must expect the mangled symbol name to call the function in the DLL properly. This can be a problem if the application automatically uppercases the symbol name before trying to call the function. If this is so, you must change the declaration of the function and re-build your DLL. DISCLAIMER: You have the right to use this technical information subject to the terms of the No-Nonsense License Statement that you received with the Borland product to which this information pertains.