This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Linker problem L104 with a header file

I have a program which exists out of a few files. I have my main.c file, my own library .c and .h files, I have an I/O.h file which only contain #defines and lastly I have my register.h file for the uController. The register.h file is included in my own library.h file because the library needs to know most registers.

When I ported from sdcc to keil I experienced some difficulties and enlisted Keil's help. They made some minor modifications with those overcomplicated # statements. This helped me finishing my program. Now I am porting another program which uses a few registers and I am running against linker error L104 again and I can't get rid of it.

main.c includes librabry.h and library.h includes register.h

#ifndef AT89x51_H
#define AT89x51_H
/* BYTE addressable registers */
sfr P0 = 0x80;
sfr SP = 0x81;
sfr DPL = 0x82;
// many more


#ifdef _COMMUNICATION_FUNCTIONS

extern unsigned char xdata tpdoid = 0x8500;
extern unsigned char xdata tpdo0 = 0x8501;
extern unsigned char xdata tpdo1 = 0x8502;
extern unsigned char xdata tpdo2 = 0x8503;
extern unsigned char xdata tpdo3 = 0x8504;
extern unsigned char xdata tpdo4 = 0x8505;
extern unsigned char xdata tpdo5 = 0x8506;
extern unsigned char xdata tpdo6 = 0x8507;
extern unsigned char xdata tpdo7 = 0x8508;

extern unsigned char xdata rpdoid = 0x8510;
extern unsigned char xdata rpdo0 = 0x8511;
extern unsigned char xdata rpdo1 = 0x8512;
extern unsigned char xdata rpdo2 = 0x8513;
extern unsigned char xdata rpdo3 = 0x8514;
extern unsigned char xdata rpdo4 = 0x8515;
extern unsigned char xdata rpdo5 = 0x8516;
extern unsigned char xdata rpdo6 = 0x8517;
extern unsigned char xdata rpdo7 = 0x8518;

#else
unsigned char xdata tpdoid _at_ 0x8500;
unsigned char xdata tpdo0 _at_ 0x8501;
unsigned char xdata tpdo1 _at_ 0x8502;
unsigned char xdata tpdo2 _at_ 0x8503;
unsigned char xdata tpdo3 _at_ 0x8504;
unsigned char xdata tpdo4 _at_ 0x8505;
unsigned char xdata tpdo5 _at_ 0x8506;
unsigned char xdata tpdo6 _at_ 0x8507;
unsigned char xdata tpdo7 _at_ 0x8508;

unsigned char xdata rpdoid _at_ 0x8510;
unsigned char xdata rpdo0 _at_ 0x8511;
unsigned char xdata rpdo1 _at_ 0x8512;
unsigned char xdata rpdo2 _at_ 0x8513;
unsigned char xdata rpdo3 _at_ 0x8514;
unsigned char xdata rpdo4 _at_ 0x8515;
unsigned char xdata rpdo5 _at_ 0x8516;
unsigned char xdata rpdo6 _at_ 0x8517;
unsigned char xdata rpdo7 _at_ 0x8518;

#endif
sfr cogw = 0x94;
// many more


The Linker only complains about:

*** ERROR L104: MULTIPLE PUBLIC DEFINITIONS
    SYMBOL:  RPDO7
    MODULE:  .\Objects\preStresser.obj (PRESTRESSER)


Only the rpdo and tpdo give problems. If I out-comment the top ones (with extern) I get ' undefined identifier error in library.c and if I out-comment the bottem lines the same error appears in main.c. So I do need all of them. I did not think of this solution myself.

In SDCC I could simply include the register.h in main.c prior to including library.h like it should work IMHO. But unfortunately for me Keil is more complicated than that.

Why is my linker unhappy and how can I make it happy again?

Parents
  • "I always thought that including a file simply means that the pre processor gets the text of that file and folds it open on the spot of the #include."

    Yes, that is exactly what happens.

    But the file that you showed also contains conditional directives - so they also get processed.

    If you want to see exactly what's happened, look at the preprocessor output: http://www.keil.com/support/man/docs/c51/c51_preprint.htm

    "If that would be the case in Keil"

    It is the case in Keil - it is the behaviour defined by the 'C' standard.

    "I could simply include register.h before I include the library files"

    That is exactly the way to do it.

    "so I wouldn't have to these complicated things I am doing now"

    You don't have to do them. There is some other problem.

    "SDCC did exactly that. In my main.c I used to #include the register.h file prior to including the library file which used those definitions"

    Again, there is nothing specific to Keil that prevents you doing that.

    "Therefor I didnt have to include the register.h in the library file"

    And you still don't.

    "And there was no need for #ifndef, #ifdef, #else and #endif"

    That depends on what you're trying to achieve.
    If you want to have a single header that provides both definitions & declarations (which some people like to do) then you do need to have conditional directives.

    "So I perhaps was doing it wrong"

    Indeed.

    "In SDCC the declarations looked the exact same as the sfr registers"

    But these are all proprietary languages extensions - so they are (almost?) bound to be different between different compilers.

    "I am currently still puzzled in what I must declare/define where"

    Then you need to spend time studying the C51 manuals, looking at the C51 examples, etc, etc

    Porting from one compiler to another always requires a good understanding of both tools.

    "The main difference is the absense of '= 0x8000'"

    As noted in a previous reply, initialisations are not allowed on absolutely-located variables.

    "I need to have the extern statements be and remove the lines with _at_..."

    Yes - you should have only declarations in the header

    "...to both library.c as main.c"

    No!!

    Your program must contain only one definition of each variable!
    So it must be in etiher library.c or main.c - but certainly not both!

    This is standard 'C' - nothing specifically to do with Keil

    "and include register.h in both files?"

    Yes.

    "But that does not seem right"

    Why not?

Reply
  • "I always thought that including a file simply means that the pre processor gets the text of that file and folds it open on the spot of the #include."

    Yes, that is exactly what happens.

    But the file that you showed also contains conditional directives - so they also get processed.

    If you want to see exactly what's happened, look at the preprocessor output: http://www.keil.com/support/man/docs/c51/c51_preprint.htm

    "If that would be the case in Keil"

    It is the case in Keil - it is the behaviour defined by the 'C' standard.

    "I could simply include register.h before I include the library files"

    That is exactly the way to do it.

    "so I wouldn't have to these complicated things I am doing now"

    You don't have to do them. There is some other problem.

    "SDCC did exactly that. In my main.c I used to #include the register.h file prior to including the library file which used those definitions"

    Again, there is nothing specific to Keil that prevents you doing that.

    "Therefor I didnt have to include the register.h in the library file"

    And you still don't.

    "And there was no need for #ifndef, #ifdef, #else and #endif"

    That depends on what you're trying to achieve.
    If you want to have a single header that provides both definitions & declarations (which some people like to do) then you do need to have conditional directives.

    "So I perhaps was doing it wrong"

    Indeed.

    "In SDCC the declarations looked the exact same as the sfr registers"

    But these are all proprietary languages extensions - so they are (almost?) bound to be different between different compilers.

    "I am currently still puzzled in what I must declare/define where"

    Then you need to spend time studying the C51 manuals, looking at the C51 examples, etc, etc

    Porting from one compiler to another always requires a good understanding of both tools.

    "The main difference is the absense of '= 0x8000'"

    As noted in a previous reply, initialisations are not allowed on absolutely-located variables.

    "I need to have the extern statements be and remove the lines with _at_..."

    Yes - you should have only declarations in the header

    "...to both library.c as main.c"

    No!!

    Your program must contain only one definition of each variable!
    So it must be in etiher library.c or main.c - but certainly not both!

    This is standard 'C' - nothing specifically to do with Keil

    "and include register.h in both files?"

    Yes.

    "But that does not seem right"

    Why not?

Children
No data