Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

#including <alsa/asoundlib.h> and <sys/time.h> results in multiple definition conflict

Here is the minimal C program to reproduce:

#include <alsa/asoundlib.h>
#include <sys/time.h>

int main( void )
{
}

This will compile with gcc -c -o timealsa.o timealsa.c, but if you include the -std=c99 switch, you get a redefinition error:

In file included from /usr/include/sys/time.h:28:0,
                 from timealsa.c:3:
/usr/include/bits/time.h:30:8: error: redefinition of ‘struct timeval’
 struct timeval
        ^
In file included from /usr/include/alsa/asoundlib.h:49:0,
                 from timealsa.c:2:
/usr/include/alsa/global.h:138:8: note: originally defined here
 struct timeval {
        ^

How can I resolve this conflict while still using -std=c99?

like image 234
Lombard Avatar asked Sep 19 '15 19:09

Lombard


2 Answers

Since your question suggests you are using GLIBC's time.h there is a way to avoid this by telling it not to define timeval. Include asoundlib.h first then define _STRUCT_TIMEVAL. The one defined in asoundlib.h will be the one that gets used.

#include <alsa/asoundlib.h>
#ifndef _STRUCT_TIMEVAL
#  define _STRUCT_TIMEVAL
#endif
#include <sys/time.h>

int main( void )
{
}
like image 106
Michael Petch Avatar answered Nov 03 '22 22:11

Michael Petch


With C99 and later you can't have duplicate definitions of the same struct. The problem is that alsa/asoundlib.h includes alsa/global.h which contains this code:

/* for timeval and timespec */
#include <time.h>

...

#ifdef __GLIBC__
#if !defined(_POSIX_C_SOURCE) && !defined(_POSIX_SOURCE)
struct timeval {
        time_t          tv_sec;         /* seconds */
        long            tv_usec;        /* microseconds */
};

struct timespec {
        time_t          tv_sec;         /* seconds */
        long            tv_nsec;        /* nanoseconds */
};
#endif
#endif

So the Michael Petch's solution won't work - by the time you've included alsa/asoundlib.h it is already too late. The proper solution is to define _POSIX_C_SOURCE (_POSIX_SOURCE is obsolete). There's more information about these macros here and here.

For example you could try -D_POSIX_C_SOURCE=200809L. However, if you do that you'll get errors like this:

/usr/include/arm-linux-gnueabihf/sys/time.h:110:20: error: field ‘it_interval’ has incomplete type
     struct timeval it_interval;
                    ^
/usr/include/arm-linux-gnueabihf/sys/time.h:112:20: error: field ‘it_value’ has incomplete type
     struct timeval it_value;
                    ^
/usr/include/arm-linux-gnueabihf/sys/time.h:138:61: error: array type has incomplete element type
 extern int utimes (const char *__file, const struct timeval __tvp[2])
                                                             ^

This is all a big mess of old C code and macro madness. The only way I got it to work was to give up and use -std=gnu11.

like image 43
Timmmm Avatar answered Nov 03 '22 22:11

Timmmm