[comp.lang.c] TLINK errors

ldh@hcx1.SSD.HARRIS.COM (02/02/89)

Here's one for the UNIX gurus who also know something about TurboC ...

Have a modularized program lint/cc do not object to the various modules ... TC2
on the other hand does.

basically:

header.h:
#include <stdio.h>
#include <       >  		(a bunch of includes)

int a,b,c,d,e,f,g,h;
float i,j,k,l,m,n,o,p;
char q,r,s,t,u,v;
struct 				(a few)

#define ABC	abc 		(a few)

main.c:
#include "header.h"
main()
{
/* some program */
}

module_a.c:
#include "header.h"
function abc()
{
}

module_b.c
#include "header.h"
function def()
{
}

When invoked as follows, the TurboC 2.0 linker has a 2 major objections:
    tlink \tc2\lib\c0m main module_a module_b,prog,prog,,\tc2\lib\cm


1) variables defined in header.h get linker error messages as follows:
Error: _A defined in module MAIN.C is duplicated in module MODULE_A.C
Error: _A defined in module MAIN.C is duplicated in module MODULE_B.C

2) Certain basic stuff ends up being "undefined"
Undefined symbol '_FOPEN' in module MAIN.C
Undefined symbol '_PRINTF' in module MAIN.C

What is going on?!  This is the first time I have tried anything modularized on
TC2 ... 

Any assistance would be greatly appreciated

Leo Hinds		ldh@hdw.harris.com

mark@jhereg.Jhereg.MN.ORG (Mark H. Colburn) (02/03/89)

In article <44100021@hcx1> ldh@hcx1.SSD.HARRIS.COM writes:
>Have a modularized program lint/cc do not object to the various modules ... TC2
>on the other hand does.
>
>basically:
>
>header.h:
>#include <stdio.h>
>#include <       >  		(a bunch of includes)
>
>int a,b,c,d,e,f,g,h;
>float i,j,k,l,m,n,o,p;
>char q,r,s,t,u,v;

Each of these declarations reserve a slot of memory for the variable being
declared.  The amount of memory, obviously depends on the type of the
declaration.  You later include this file into mutliple compilation units
(modules).  The result is:

	main.c:
	int a,b,c,d....;

	module_a:
	int a,b,c,d....;

Which saves slot of memory for "int a,b..." in both main.c and module_a.c.
When you try to link the programs together, the linker complains.  What you
should have, if you want a,b,c,d, etc. to be global variables is:

	main.c:
	int a,b,c,d...;

	module_a:
	extern int a,b,c,d....;

The fact the your unix compiler/linker does not catch this error is
actually just sloppy play on your compiler vendors part.  Multiple
declarations of this sort usually indicate a bug in the program somehere.
If the linker does not complain, they can be very difficult to track down.

Hope that this helps.
-- 
Mark H. Colburn                  "Look into a child's eye;
Minnetech Consulting, Inc.        there's no hate and there's no lie;
mark@jhereg.mn.org                there's no black and there's no white."

maart@cs.vu.nl (Maarten Litmaath) (02/03/89)

ldh@hcx1.SSD.HARRIS.COM writes:
\header.h:
\#include <stdio.h>
\#include <       >  		(a bunch of includes)

\int a,b,c,d,e,f,g,h;
\float i,j,k,l,m,n,o,p;
\char q,r,s,t,u,v;

Aaaaaaaaargh! A header file should NEVER contain variable DEFINITIONS!
It should only contain `#define's and variable DECLARATIONS.
So:
	extern	int	a, ...;
	extern	float	i, ...;
	extern	char	q, ...;

The definitions are handled in an accompanying file `header.c'.
A nice solution to prevent redundancy (and error-proneness):

	#ifndef	HEADER_H
	#define		HEADER_H

	#ifndef	EXTERN
	#define		EXTERN		extern
	#else	EXTERN
	#define		INIT
	#endif	!EXTERN

	EXTERN	int	a, ...;
	EXTERN	float	i, ...;
	EXTERN	char	q[]
	#ifdef	INIT
			= "hey babe!"
	#endif	INIT
			;

	#endif	!HEADER_H

In `foo.c':

	#include	"header.h"

In `header.c':

	#define		EXTERN
	#include	"header.h"
-- 
 "Does she play, er, tennis?          |Maarten Litmaath @ VU Amsterdam:
             Wink wink, notch notch!" |maart@cs.vu.nl, mcvax!botter!maart

bkbarret@sactoh0.UUCP (Brent K. Barrett) (02/03/89)

In article <44100021@hcx1>, ldh@hcx1.SSD.HARRIS.COM writes:
> 
> Here's one for the UNIX gurus who also know something about TurboC ...
> 
> Have a modularized program lint/cc do not object to the various modules ... TC2
> on the other hand does.
> 
 [ Chomp! ]j
> When invoked as follows, the TurboC 2.0 linker has a 2 major objections:
>     tlink \tc2\lib\c0m main module_a module_b,prog,prog,,\tc2\lib\cm
> 
> 
> 1) variables defined in header.h get linker error messages as follows:
> Error: _A defined in module MAIN.C is duplicated in module MODULE_A.C
> Error: _A defined in module MAIN.C is duplicated in module MODULE_B.C
> 
> 2) Certain basic stuff ends up being "undefined"
> Undefined symbol '_FOPEN' in module MAIN.C
> Undefined symbol '_PRINTF' in module MAIN.C
> 
> What is going on?!  This is the first time I have tried anything modularized on
> TC2 ... 
 
 Turbo C allows global variables to be declared only ONCE. Every
other time they are included in a module, they must be declared as
"extern"als.  Do the following to solve your problem:
 
 1) Place all your variable declarations into your main.c file as
is, then create a file called "extern.h" that lists the same
variable declarations prefixed by "extern."
  e.g.:
 
 float j;

    becomes:

 extern float j;
 
 2) simply #include "extern.h" in all your modules except main.c.

 I'm no Unix guru, but that will solve your TC problems.

-- 
 "Somebody help me! I'm trapped in this computer!"
  
 Brent Barrett ..pacbell!sactoh0!bkbarret GEMAIL: B.K.BARRETT

ldh@hcx1.SSD.HARRIS.COM (02/03/89)

Thanks to all that responded ... I had infact done as most suggested (use the
extern) ... someone also suggested the use of "static" ... the main concern I
had there was whether TurboC was right or the UNIX cc/lint was, and therefore
who should I trust in the future.

In my linking problem, someone suggested that I include \lib\mathX ... but the
linker errors involved basics like _printf ... that one still is a problem ...
any suggestions will still be greatly appreciated.

Thanks :-)

Leo Hinds		ldh@hdw.harris.com

swh@hpsmtc1.HP.COM (Steve Harrold) (02/03/89)

Re: TLINK vs lint

Try using the /c switch on the TLINK command line.  This forces the
linker to honor mixed case symbols.  As you've posted it, all symbols
are forced to uppercase with the result that your program's reference
to "fopen" got translated to a reference to "FOPEN" which got translated to
a reference to "_FOPEN" which is not present in the libraries.  ("_fopen" is).

--
---------------------
Steve Harrold			...hplabs!hpsmtc1!swh
				HPG200/13
				(408) 447-5580
---------------------

chris@mimsy.UUCP (Chris Torek) (02/06/89)

[re def/ref vs common, where the `extern' in
	foo.c: int a;
	bar.c: /* extern */ int a;
matters]

In article <508@jhereg.Jhereg.MN.ORG> mark@jhereg.Jhereg.MN.ORG
(Mark H. Colburn) writes:
>The fact the your unix compiler/linker does not catch this error is
>actually just sloppy play on your compiler vendors part.  Multiple
>declarations of this sort usually indicate a bug in the program somehere.

Hardly.

The Unix compilers and linkers use the `common model', in which
a declaration without `extern' and without an initial value compiles
to a FORTRAN-common-style definition, such as

		.comm	_a,4

for

	int a;

(the 4 here is the size of `a' in bytes).  Other compilers use the more
restrictive `def/ref model':

	_a:	.long	0

for `int a' (and `int a = 0') and

		.extern	_a

for `extern int a'.  The def/ref model *can* catch bugs like this one:

	foo.c: int status;
	bar.c: struct { char *msg; int code; } status;

but I prefer the common model.  Lint catches the above bug, and the
def/ref compiler does *not* catch the bug if one writes instead

	foo.c: int status;
	bar.c: extern struct { char *msg; int code; } status;

or (if extern declarations carry size information but
sizeof(int)==sizeof(char *))

	foo.c: int status;
	bar.c: extern char *status;

so one must run lint anyway.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

ldh@hcx1.SSD.HARRIS.COM (02/08/89)

Thanks to all that responded to my querries ...

Someone suggested that I should try the /c (case sensitive link) in the tlink
run ... that changed the "undefined _FOPEN" to "undefined _fopen" ...

Another suggestion was "why mess with TLINK ... let TCC figure it out" ...sure
enough, by now doing

TCC -eoutput $(OBJFILES) will now correctly invoke TLINK and I get an executablethat I can actually run ...

Thanks to all that responded !

Leo Hinds