organise code in multiple files wlalink

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
organise code in multiple files wlalink
by on (#228709)
Hello,

I try to develop on SNES with PVSNESLIB and as long as i use a single code file, everything compile correctly.
I would like to organise my code in multiple file but i didn't find a way to compile it.

For example, i have 3 files :

SimpleSprite.h

Code:
#ifndef SIMPLESPRITE_H
#define SIMPLESPRITE_H
   unsigned char test;
   void SimpleSpriteInit();
#endif


Simpleprite.c :

Code:
#include "SimpleSprite.h"

void SimpleSpriteInit()
{
   test = 'a';
}

main.c :

Code:
#include "SimpleSprite.h"

#include <snes.h>

extern char gfxpsrite, gfxpsrite_end;
extern char palsprite, palsprite_end;


int main(void) {
   SimpleSpriteInit(); // ERROR HERE
   consoleInit();
   oamInitGfxSet(&gfxpsrite, (&gfxpsrite_end-&gfxpsrite), &palsprite, (&palsprite_end-&palsprite), 0, 0x0000, OBJ_SIZE32);

   oamSet(0,  100, 100, 3, 0, 0, 0, 0);
   oamSetEx(0, OBJ_SMALL, OBJ_SHOW);
   
   setMode(BG_MODE1,0); bgSetDisable(0); bgSetDisable(1); bgSetDisable(2);
   setScreenOn();
   
   while(1) {
      WaitForVBlank();
   }
   return 0;
}


This code produce an error when SimpleSpriteInit() is called :

SimpleSprite.obj:SimpleSprite.asm:40: FIX_LABELS: Label "test" was defined more than once.
mn test islsl 0 islfl 0


Here is the file of wla that produce it :
https://github.com/optixx/snes-sdk/blob ... nk/write.c

Do you have informations about that and how can i solve it ?

Thanks in advance for you help.
Re: organise code in multiple files wlalink
by on (#228721)
This is not a wlalink problem but a C problem: you have defined a variable in a header a file and everytime you will include it in another C file, it will try to define a new "test" variable, thus the error "was defined more than once'.

What you should do is define the variable in one C file then if you need to share it, just "extern" it in the file you need to use it. This is what I do in my C project for the nes.
Re: organise code in multiple files wlalink
by on (#228723)
Banshaku wrote:
This is not a wlalink problem but a C problem: you have defined a variable in a header a file and everytime you will include it in another C file, it will try to define a new "test" variable, thus the error "was defined more than once'.

What you should do is define the variable in one C file then if you need to share it, just "extern" it in the file you need to use it. This is what I do in my C project for the nes.

Shouldn't their #ifndef strategy prevent this, though?

Code:
#ifndef SIMPLESPRITE_H
#define SIMPLESPRITE_H
   unsigned char test;
   void SimpleSpriteInit();
#endif

The first time this header file is included, it checks if SIMPLESPRITE_H is defined. It's not, so it defines it and then declares test and SimpleSpriteInit().

The second time it's included, it checks if SIMPLESPRITE_H is defined. This time, it is, so everything between #ifndef and #endif is skipped.
Re: organise code in multiple files wlalink
by on (#228725)
That's a good question, this is what include guards should do and didn't think much that far when answering since it was my reflex that include = multiple declaration ^^;;;

I think you are right and it shouldn't have cause the issue but I don't know if it good practice to define variables in header but I guess if it makes it easier and you don't have to use extern then it could be one way.
Re: organise code in multiple files wlalink
by on (#228726)
I was under the impression that multiple extern declarations of the same thing were allowed, even within one translation unit,* so long as they're identical.


* A translation unit is what you get after the preprocessor has finished handling things like #include and #define.
Re: organise code in multiple files wlalink
by on (#228728)
The placement of variables is being done, IMO, incorrectly in that code. I see this attempted quite often in C code, resulting in an absolute mess of include nonsense that makes no sense. I don't think this concept/issue/matter is taught well (either socially or in CS courses), which is why it's prevalent.

You are quite welcome to declare your functions in an .h file (ex. void SimpleSpriteInit();); this can be used as a form of prototyping and is encouraged. Just be careful.

Your variables, however, need to be declared in the .c file where they're used.

If you have use of global variables, such as unsigned char test;, then this variable declaration should be within what you call main.c.

Then, within what you call SimpleSprite.h, you can have extern unsigned char test;. Any other .c file that has #include "SimpleSprite.h" will then be able to access the global variable called test.

You can also safely #include "SimpleSprite.h" in your main.c without worrying about "double declarations" for test or anything of this sort.

If you want to see an example of how to do this, look at my bsdhwmon code. Specifically, look at f_verbose -- see main.c for its declaration, global.h for its extern and the related VERBOSE() macro that uses it, and all other *.c files that use VERBOSE() (the latter is why it needs to be extern). I could have simply written extern int f_verbose; in every .c file that needed it, but I chose to use a kind of "global macro" that any .c program could use, which references that variable, hence the extern. The linker takes care of the rest.

The short version: do not declare global variables in .h files. Declare the variable within your "main" file, then use extern in other places (either .c files, or an .h file that .c files include).

You can declare typedefs, structs, etc. in .h files of this sort with general safety, though you may need to use an #ifndef/#define approach depending on what it is you're defining.
Re: organise code in multiple files wlalink
by on (#228737)
So I was right to some degree (my gut feeling told me that variables shouldn't be there but I didn't make C in years so I tend to forget things). As for declaring global in main, I wasn't aware of that but when you think about it, it make sense because it's the entry point of the program and any global should be easy to find, thus putting them in that file.

I think I may have done that indirectly without thinking but one of the other "almost" global (i.e. I decided later that it could be used in other modules) was not there. I will refactor my own code a little bit then.

Maybe for the H file, another way to see it is that it define the prototype of what is accessible in the unit (except for inline functions) so definition, like variables, shoudn't be there (does it make sense? ^^;;).
Re: organise code in multiple files wlalink
by on (#228740)
Thank you for your explanations, it solve my problems !

Have a nice day !