IDE: MPLAB X v2.15
CC: XC8 v1.32
Target device: PIC18f45k20
I have a header file reg.h
, which contains a variable
static const int aaasdf = 3;
That header has proper include guards at the beginning:
#ifndef PRJ_REG_H
#define PRJ_REG_H
And at the end:
#endif
If I have that same variable on any other header file, it compiles fine, but when that variable is in this particular file, it gives me error: (845) symbol "reg@aaasdf" defined more than once
But if I comment that variable, it doesn't exist anymore, and it complains because I need it in some .c file.
The strange name is just for testing, to be sure that there isn't any other variable with the same name.
What else can I do to debug this?
EDIT:
It does it for any static const
variable, (I'll test tomorrow for only static
, const
or extern const
), that I create in that file, but there are also enum
s, and static inline
functions, and none of them gives me the repeated symbol error.
EDIT:
I think it's the compiler that is broken:
I removed everything from the header and also the source files. Now main is an infinite loop, and all is like that.
The headers are empty but for the variable triggering the error.
No header of mine includes any other header of mine.
What triggers the error:
Any header that is included in many source files, and contains a static const
variable of any type. What I mean by many is that if I include the header only in its source file and another file, it doesn't trigger the error, but if it is included in 2 source files that aren't its source file, it triggers the error.
EDIT:
As requested, here is a MCV example of what I want (not the compile error):
// reg.h
enum Reg_OSCCON_IRCF_Values {
REG_OSCCON_IRCF_FREQ_31_KHZ = 0x0u,
REG_OSCCON_IRCF_FREQ_250_KHZ = 0x1u,
REG_OSCCON_IRCF_FREQ_500_KHZ = 0x2u,
REG_OSCCON_IRCF_FREQ_1_MHZ = 0x3u,
REG_OSCCON_IRCF_FREQ_2_MHZ = 0x4u,
REG_OSCCON_IRCF_FREQ_4_MHZ = 0x5u,
REG_OSCCON_IRCF_FREQ_8_MHZ = 0x6u,
REG_OSCCON_IRCF_FREQ_16_MHZ = 0x7u
};
#define REG_OSCCON_IRCF_FREQ ((const uint32_t [8]){ \
31000u, \
250000u, \
500000u, \
1000000u, \
2000000u, \
4000000u, \
8000000u, \
16000000u \
})
static inline void reg_field_set(volatile uint8_t *reg,
uint8_t mask, uint8_t posn, uint8_t val)
{
*reg = (*reg & ~mask) | ((val << posn) & mask);
}
static inline void reg_OSCCON_IRCF_set(uint8_t val)
{
reg_field_set(&OSCCON, _OSCCON_IRCF_MASK, _OSCCON_IRCF_POSN, val);
}
// pwm.c
#include "reg.h"
extern uint32_t sys_freq;
int foo(/**/)
{
static const uint32_t freq_min =
REG_OSCCON_IRCF_FREQ[REG_OSCCON_IRCF_FREQ_16_MHZ] /
(UINT8_MAX * 4 *
REG_T2CON_T2CKPS_PRESCALER[REG_T2CON_T2CKPS_PRESCALER_1]);
reg_OSCCON_IRCF_set(REG_OSCCON_IRCF_FREQ_16_MHZ);
sys_freq = REG_OSCCON_IRCF_FREQ[REG_OSCCON_IRCF_FREQ_16_MHZ];
// ...
}
Option 1: As showed above, using a macro that expands to a const
compound array literal, where I can access any of its elements (either at
compile time or at run time). Need C99
, which I don't have. EDIT: const
compound literals may or may not be constant expressions (Initialize static variable with element of const compound literal), and therefore may or may not be valid as initializers for static
variables.
Option 2: Changing the macro to a static const
array.
Pros: don't need C99
.
Cons: Can NOT initialize a static
variable. The compiler seems broken and
doesn't allow me to do that.
Option 3: Magic numbers.
Pros: Don't need C99
. Can initialize a
static
variable.
Cons: Magic numbers.
Option 4: A lot of macros (for each of the arrays, because it's not only
this one!).
Pros: Don't need C99
.
Cons: Polluting global namespace.
Definitely the XC8
compiler is broken.
Today similar errors appeared when using static inline
functions. I've googled about it, and it seems the compiler isn't very good with that kind of code.