Issue
I am trying to export a symbol to the kernel. But I am getting the below error. My linux version is 5.4.2,
/home/ram/checkout/drivers/char/i2c_sw_hw_common.c: At top level:
/home/ram/checkout/drivers/char/i2c_sw_hw_common.c:1031:14: error: conflicting types for ‘sfp_i2c_in32’
UInt32 sfp_i2c_in32(char_dev_t *dev,unsigned int I2cDevaddr, int alen, unsigned int offset,unsigned int I2cAddr,int Width, int AccessType)
^~~~~~~~~~~~
In file included from /home/ram/checkout/drivers/char/i2c_sw_hw_common.c:3:
/home/ram/checkout/drivers/char/i2c_sw_hw_common.h:123:8: note: previous declaration of ‘sfp_i2c_in32’ was here
UInt32 sfp_i2c_in32(char_dev_t *dev,unsigned int I2cDevaddr, int alen, unsigned int offset,unsigned int I2cAddr,int Width, int AccessType);
^~~~~~~~~~~~
/home/ram/checkout/drivers/char/i2c_sw_hw_common.c: In function ‘sfp_i2c_in32’:
/home/ram/checkout/drivers/char/i2c_sw_hw_common.c:1035:18: warning: unused variable ‘byte_count’ [-Wunused-variable]
unsigned int byte_count = 0 ;
^~~~~~~~~~
/home/ram/checkout/drivers/char/i2c_sw_hw_common.c: At top level:
/home/ram/checkout/drivers/char/i2c_sw_hw_common.c:1063:29: error: conflicting types for ‘sfp_i2c_in32’
EXPORT_SYMBOL_NOVERS(sfp_i2c_in32);
^~~~~~~
In file included from /home/ram/checkout/drivers/char/i2c_sw_hw_common.c:3:
/home/ram/checkout/drivers/char/i2c_sw_hw_common.h:123:8: note: previous declaration of ‘sfp_i2c_in32’ was here
UInt32 sfp_i2c_in32(char_dev_t *dev,unsigned int I2cDevaddr, int alen, unsigned int offset,unsigned int I2cAddr,int Width, int AccessType);
^~~~~~~~~~~~
cc1: some warnings being treated as errors
Here is my declaration, definition and export of this symbol.
i2c_sw_hw_common.c
UInt32 sfp_i2c_in32(char_dev_t *dev,unsigned int I2cDevaddr, int alen, unsigned int offset,unsigned int I2cAddr,int Width, int AccessType)
{
// code
}
EXPORT_SYMBOL(sfp_i2c_in32);
i2c_sw_hw_common.h
UInt32 sfp_i2c_in32(char_dev_t *dev,unsigned int I2cDevaddr, int alen, unsigned int offset,unsigned int I2cAddr,int Width, int AccessType);
Solution
The issue is with the use of user-defined data types. Instead of unsigned int
, I have used UInt32
, which is user-defined.
typedef unsigned long UInt32;
This usually does not create any problem as long as you have the same definition visible in both the header file and the source file.
But in my case, in the source file(.c), UInt32
got treated as a macro and expanded as unsigned int
after preprocessing is done.
But in the header file, UInt32
was still a user-defined datatype. So the compiler threw the above errors.
I got to know about this after examining the preprocessor stage output (use -save-temps
flag for this).
After the preprocessor stage, the declaration remained as,
UInt32 sfp_i2c_in32(char_dev_t *dev,unsigned int I2cDevaddr, int alen, unsigned int offset,unsigned int I2cAddr,int Width, int AccessType);
But the definition was changed to,
unsigned int sfp_i2c_in32(char_dev_t *dev,unsigned int I2cDevaddr, int alen, unsigned int offset,unsigned int I2cAddr,int Width, int AccessType)
{
// code
}
So, removed all the user-defined datatypes from my code and used only predefined ones.
The minimalistic example for above issue can be this,
// file.h
typedef unsigned long UInt32;
UInt32 f();
// file.c
#include "x.h"
#define UInt32 unsigned int
UInt32 f()
{
return 0;
}
Error you would get,
x.c:6:14: error: conflicting types for ‘f’
UInt32 f()
^
In file included from x.c:2:0:
x.h:3:8: note: previous declaration of ‘f’ was here
UInt32 f();
^
Answered By - ram914