Tuesday, January 4, 2022

[SOLVED] EXPORT_SYMBOL macro is giving conflicting types error

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