trivial borland c++ linker error (with SDL)

Started by
13 comments, last by Gaal Dormick 18 years, 12 months ago
Error: Unresolved external '_SDL_GetError' referenced from C:\DOCUMENTS AND SETTINGS\DDONNELLY\DESKTOP\SDL\SDL_WIN32_MAIN.OBJ I'm using Borland C++ 5.5 command line tools and I'm trying to do SDL. The instructions for linking with SDL are right here in the FAQ: SDL with Borland C++ I've made an import library with implib as said and I've tried other combinations of -a (names with underscore) and -c (case sensitive). I've put SDL.lib in c:\borland\lib and i've also deleted SDL_main.lib since we have to care for that our selves with SDL_main.c (or in my case SDL_win32_main.c). The SDL header files are in c:\borland\include\SDL. I've done all of what I think is needed and my build environment looks like: (where > denotes what I actually enter) > bcc32.exe -I%B_INC% -L%B_LIB% -c -tW -DWIN32 test1.cpp SDL_win32_main.c B_INC = c:\borland\bcc55\include B_LIB = c:\borland\bcc55\lib > ilink32.exe -Lc:\borland\bcc55\lib -aa -Tpe -c sdl.lib import32.lib c0w32.obj cw32.lib test1.obj SDL_win32_main.obj (-Lc:\borland\bcc55\lib seems to be sufficient for object files as well) The order of the files in the above commands doesn't seem to matter(switching SDL_win32_main.c with test1.cpp and putting the object files both ahead and before the other import libs didn't matter. the output of ilink32 is: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland Error: Unresolved external '_SDL_GetError' referenced from C:\DOCUMENTS AND SETTINGS\DDONNELLY\DESKTOP\SDL\SDL_WIN32_MAIN.OBJ test1.cpp is nothing special:

#include <stdlib.h>
#include <SDL/SDL.h>

SDL_Surface *screen;

void render();

int main(int argc, char *argv[])
{
   if(SDL_Init(SDL_INIT_VIDEO) < 0)
   {
      fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
      exit(1);
   }

   // register SDL_quit to be called at exit, so things are cleaned up
   atexit(SDL_Quit);

   // create 640x480 with 32-bit pxls
   screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);

   // return error on fail
   if(screen == NULL)
   {
      fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
      exit(1);
   }

   // main loop
   while(1)
   {
      render();

      SDL_Event event;

      while(SDL_PollEvent(&event))
      {
         switch(event.type)
         {
            case SDL_KEYUP:
               if(event.key.keysym.sym == SDLK_ESCAPE)
                  return 0;
               break;
            case SDL_QUIT:
               return 0;
            default:
               break;
         }
      }
   }

   // return 0;      // unreachable
}

void render()
{
   // lock surface if need be
   if(SDL_MUSTLOCK(screen))
      if(SDL_LockSurface(screen) < 0)
         return;            // couldn't lock

   // time in millis
   int tick = SDL_GetTicks();

   int i, j, yofs, ofs;

   // draw screen;
   yofs = 0;
   for(i=0; i<480; i++)
   {
      for(j=0,ofs=yofs; j<640; j++,ofs++)
      {
         ((unsigned int*)screen->pixels)[ofs] = i*i + j*j + tick;
      }
      yofs += screen->pitch /4;
   }

   // unlock if need be
   if(SDL_MUSTLOCK(screen))
      SDL_UnlockSurface(screen);

   // tell SDL to update screen
   SDL_UpdateRect(screen,0,0,640,480);
}



SDL_win32_main.c might help:

/*
    SDL_main.c, placed in the public domain by Sam Lantinga  4/13/98

    The WinMain function -- calls your program's main() function
*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#include <windows.h>
#include <malloc.h>         /* For _alloca() */

#ifdef _WIN32_WCE
# define DIR_SEPERATOR TEXT("\\")
# undef _getcwd
# define _getcwd(str,len)   wcscpy(str,TEXT(""))
# define setbuf(f,b)
# define setvbuf(w,x,y,z)
# define fopen      _wfopen
# define freopen   _wfreopen
# define remove(x)   DeleteFile(x)
# define strcat      wcscat
#else
# define DIR_SEPERATOR TEXT("/")
# include <direct.h>
#endif

/* Include the SDL main definition header */
#include "SDL\SDL.h"
#include "SDL\SDL_main.h"

#ifdef main
# ifndef _WIN32_WCE_EMULATION
#  undef main
# endif /* _WIN32_WCE_EMULATION */
#endif /* main */

/* The standard output files */
#define STDOUT_FILE   TEXT("stdout.txt")
#define STDERR_FILE   TEXT("stderr.txt")

#ifndef NO_STDIO_REDIRECT
# ifdef _WIN32_WCE
  static wchar_t stdoutPath[MAX_PATH];
  static wchar_t stderrPath[MAX_PATH];
# else
  static char stdoutPath[MAX_PATH];
  static char stderrPath[MAX_PATH];
# endif
#endif

#if defined(_WIN32_WCE) && _WIN32_WCE < 300
/* seems to be undefined in Win CE although in online help */
#define isspace(a) (((CHAR)a == ' ') || ((CHAR)a == '\t'))

/* seems to be undefined in Win CE although in online help */
char *strrchr(char *str, int c)
{
   char *p;

   /* Skip to the end of the string */
   p=str;
   while (*p)
      p++;

   /* Look for the given character */
   while ( (p >= str) && (*p != (CHAR)c) )
      p--;

   /* Return NULL if character not found */
   if ( p < str ) {
      p = NULL;
   }
   return p;
}
#endif /* _WIN32_WCE < 300 */

/* Parse a command line buffer into arguments */
static int ParseCommandLine(char *cmdline, char **argv)
{
   char *bufp;
   int argc;

   argc = 0;
   for ( bufp = cmdline; *bufp; ) {
      /* Skip leading whitespace */
      while ( isspace(*bufp) ) {
         ++bufp;
      }
      /* Skip over argument */
      if ( *bufp == '"' ) {
         ++bufp;
         if ( *bufp ) {
            if ( argv ) {
               argv[argc] = bufp;
            }
            ++argc;
         }
         /* Skip over word */
         while ( *bufp && (*bufp != '"') ) {
            ++bufp;
         }
      } else {
         if ( *bufp ) {
            if ( argv ) {
               argv[argc] = bufp;
            }
            ++argc;
         }
         /* Skip over word */
         while ( *bufp && ! isspace(*bufp) ) {
            ++bufp;
         }
      }
      if ( *bufp ) {
         if ( argv ) {
            *bufp = '\0';
         }
         ++bufp;
      }
   }
   if ( argv ) {
      argv[argc] = NULL;
   }
   return(argc);
}

/* Show an error message */
static void ShowError(const char *title, const char *message)
{
/* If USE_MESSAGEBOX is defined, you need to link with user32.lib */
#ifdef USE_MESSAGEBOX
   MessageBox(NULL, message, title, MB_ICONEXCLAMATION|MB_OK);
#else
   fprintf(stderr, "%s: %s\n", title, message);
#endif
}

/* Pop up an out of memory message, returns to Windows */
static BOOL OutOfMemory(void)
{
   ShowError("Fatal Error", "Out of memory - aborting");
   return FALSE;
}

/* Remove the output files if there was no output written */
static void __cdecl cleanup_output(void)
{
#ifndef NO_STDIO_REDIRECT
   FILE *file;
   int empty;
#endif

   /* Flush the output in case anything is queued */
   fclose(stdout);
   fclose(stderr);

#ifndef NO_STDIO_REDIRECT
   /* See if the files have any output in them */
   if ( stdoutPath[0] ) {
      file = fopen(stdoutPath, TEXT("rb"));
      if ( file ) {
         empty = (fgetc(file) == EOF) ? 1 : 0;
         fclose(file);
         if ( empty ) {
            remove(stdoutPath);
         }
      }
   }
   if ( stderrPath[0] ) {
      file = fopen(stderrPath, TEXT("rb"));
      if ( file ) {
         empty = (fgetc(file) == EOF) ? 1 : 0;
         fclose(file);
         if ( empty ) {
            remove(stderrPath);
         }
      }
   }
#endif
}

#if defined(_MSC_VER) && !defined(_WIN32_WCE)
/* The VC++ compiler needs main defined */
#define console_main main
#endif

/* This is where execution begins [console apps] */
int console_main(int argc, char *argv[])
{
   int n;
   char *bufp, *appname;

   /* Get the class name from argv[0] */
   appname = argv[0];
   if ( (bufp=strrchr(argv[0], '\\')) != NULL ) {
      appname = bufp+1;
   } else
   if ( (bufp=strrchr(argv[0], '/')) != NULL ) {
      appname = bufp+1;
   }

   if ( (bufp=strrchr(appname, '.')) == NULL )
      n = strlen(appname);
   else
      n = (bufp-appname);

   bufp = (char *)alloca(n+1);
   if ( bufp == NULL ) {
      return OutOfMemory();
   }
   strncpy(bufp, appname, n);
   bufp[n] = '\0';
   appname = bufp;

   /* Load SDL dynamic link library */
   if ( SDL_Init(SDL_INIT_NOPARACHUTE) < 0 ) {
      ShowError("WinMain() error", SDL_GetError());
      return(FALSE);
   }
   atexit(cleanup_output);
   atexit(SDL_Quit);

#ifndef DISABLE_VIDEO
#if 0
   /* Create and register our class *
      DJM: If we do this here, the user nevers gets a chance to
      putenv(SDL_WINDOWID).  This is already called later by
      the (DIB|DX5)_CreateWindow function, so it should be
      safe to comment it out here.
   if ( SDL_RegisterApp(appname, CS_BYTEALIGNCLIENT,
                        GetModuleHandle(NULL)) < 0 ) {
      ShowError("WinMain() error", SDL_GetError());
      exit(1);
   }*/
#else
   /* Sam:
      We still need to pass in the application handle so that
      DirectInput will initialize properly when SDL_RegisterApp()
      is called later in the video initialization.
    */
   SDL_SetModuleHandle(GetModuleHandle(NULL));
#endif /* 0 */
#endif /* !DISABLE_VIDEO */

   /* Run the application main() code */
   SDL_main(argc, argv);

   /* Exit cleanly, calling atexit() functions */
   exit(0);

   /* Hush little compiler, don't you cry... */
   return(0);
}

/* This is where execution begins [windowed apps] */
#ifdef _WIN32_WCE
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPWSTR szCmdLine, int sw)
#else
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
#endif
{
   HINSTANCE handle;
   char **argv;
   int argc;
   char *cmdline;
#ifdef _WIN32_WCE
   wchar_t *bufp;
   int nLen;
#else
   char *bufp;
#endif
#ifndef NO_STDIO_REDIRECT
   FILE *newfp;
#endif

   /* Start up DDHELP.EXE before opening any files, so DDHELP doesn't
      keep them open.  This is a hack.. hopefully it will be fixed
      someday.  DDHELP.EXE starts up the first time DDRAW.DLL is loaded.
    */
   handle = LoadLibrary(TEXT("DDRAW.DLL"));
   if ( handle != NULL ) {
      FreeLibrary(handle);
   }

#ifndef NO_STDIO_REDIRECT
   _getcwd( stdoutPath, sizeof( stdoutPath ) );
   strcat( stdoutPath, DIR_SEPERATOR STDOUT_FILE );

   /* Redirect standard input and standard output */
   newfp = freopen(stdoutPath, TEXT("w"), stdout);

#ifndef _WIN32_WCE
   if ( newfp == NULL ) {   /* This happens on NT */
#if !defined(stdout)
      stdout = fopen(stdoutPath, TEXT("w"));
#else
      newfp = fopen(stdoutPath, TEXT("w"));
      if ( newfp ) {
         *stdout = *newfp;
      }
#endif
   }
#endif /* _WIN32_WCE */

   _getcwd( stderrPath, sizeof( stderrPath ) );
   strcat( stderrPath, DIR_SEPERATOR STDERR_FILE );

   newfp = freopen(stderrPath, TEXT("w"), stderr);
#ifndef _WIN32_WCE
   if ( newfp == NULL ) {   /* This happens on NT */
#if !defined(stderr)
      stderr = fopen(stderrPath, TEXT("w"));
#else
      newfp = fopen(stderrPath, TEXT("w"));
      if ( newfp ) {
         *stderr = *newfp;
      }
#endif
   }
#endif /* _WIN32_WCE */

   setvbuf(stdout, NULL, _IOLBF, BUFSIZ);   /* Line buffered */
   setbuf(stderr, NULL);         /* No buffering */
#endif /* !NO_STDIO_REDIRECT */

#ifdef _WIN32_WCE
   nLen = wcslen(szCmdLine)+128+1;
   bufp = (wchar_t *)alloca(nLen*2);
   wcscpy (bufp, TEXT("\""));
   GetModuleFileName(NULL, bufp+1, 128-3);
   wcscpy (bufp+wcslen(bufp), TEXT("\" "));
   wcsncpy(bufp+wcslen(bufp), szCmdLine,nLen-wcslen(bufp));
   nLen = wcslen(bufp)+1;
   cmdline = (char *)alloca(nLen);
   if ( cmdline == NULL ) {
      return OutOfMemory();
   }
   WideCharToMultiByte(CP_ACP, 0, bufp, -1, cmdline, nLen, NULL, NULL);
#else
   /* Grab the command line (use alloca() on Windows) */
   bufp = GetCommandLine();
   cmdline = (char *)alloca(strlen(bufp)+1);
   if ( cmdline == NULL ) {
      return OutOfMemory();
   }
   strcpy(cmdline, bufp);
#endif

   /* Parse it into argv and argc */
   argc = ParseCommandLine(cmdline, NULL);
   argv = (char **)alloca((argc+1)*(sizeof *argv));
   if ( argv == NULL ) {
      return OutOfMemory();
   }
   ParseCommandLine(cmdline, argv);

   /* Run the main program (after a little SDL initialization) */
   return(console_main(argc, argv));
}


[Edited by - Gaal Dormick on April 26, 2005 8:53:18 PM]
Advertisement
*bump*
Okay, first off, where are your commas in the call to ilink32?

Second, it says that for 1.2.5 and newer you should look at Borland.html in the source, does it say the same thing as the instructions you linked to?

Third, aw screw it, the problems I see should be unrelated to your error, so let me look back in time through my files(I quit using SDL, I now use glfw, http://glfw.sourceforge.net/ and have found it to be the most easily compiled and most easily thing used ever).

http://home.earthlink.net/~aaron_ogden/sdl.mak
Here's a file to help you out, it's the one I used to use, minus references to personal projects. Note that I have not really edited it all that much so while it sounds like I'm giving advice, I just happen to write everything as if I myself don't know how to use them since I often go weeks without modifying documents.

Fourth, bcc32.cfg and ilink32.cfg are your friends, use them, ask me how if you don't know.
What I linked to says this about Borland.html in the SDL source:
Quote:
Martin Bickel writes:
For both Watcom C/C++ and Borland C/C++ the compiler option that makes enums having the size of an int must be enabled. This is "-b" for Borland C/C++ and "-ei" for Watcom C/C++ (v11).


I assumed that this wouldn't apply to me with my simple test, but I'll enable those options and try it again.

That wasn't the problem. I'll look into GLFW, looks promising, but I still need to find a solution to this problem. If I don't in a week I'll switch to the free VC++ compiler + SDL.
Does no one use Borland C++ any more? [tears]
Changing to BuilderX now, its better.
OpenGl + C++
Quote:Original post by RolandofGilead
Okay, first off, where are your commas in the call to ilink32?

To see what I mean, just type in ilink32 in the console and look at the line that starts with "Syntax: ILINK32..."

sdl.mak
clickified for your convenience, just try it, instructions are within
Okay, I'm going to see what you mean, but in that sdl.mak you linked to, why are their extra commas given: "....,,....,,"?
Quote:
Link the.obj files together using ILINK32 with the following options:
-aa (Create windows app, sounds redundant, but...)
-Tpe (Target = windows exe)
-c (case sensitive linking, may be the default...)
and the following additional files (order is important)

* sdl.lib (created in step 1)
* import32.lib
* c0w32.obj
* cw32.lib


Okay, it says "order is important" and then lists the files. So I just assumed we're all reading from top to bottom. But this might not be the case, so I'm going to try grouping them by type as ilink32 usage requires. Please inform me of any pitfalls I am going to encounter :D

edit: okay, I see the order matches what you have in sdl.make, and they're all grouped within the libfiles commas. What makes c0w32.obj a "lib" file instead of an "obj" file which I assumed from its extension?
I'm using this:
ilink32.exe -Lc:\borland\bcc55\lib -aa -Tpe -c SDL_win32_main.obj %1.obj, %1.exe,, sdl.lib import32.lib c0w32.obj cw32.lib,,

getting the exact same error.

This topic is closed to new replies.

Advertisement