charliehorse55
charliehorse55

Reputation: 1990

GCC complains about missing references to functions in the same file

Running along the makefile, I get to this:

cc client.o MurmurHash3.o libstorage.a -Wall -lreadline -pthread  -o client
MurmurHash3.o: In function `MurmurHash3_x64_128':
/home/evantandersen/mount/src/MurmurHash3.c:59: undefined reference to `rotl64'
/home/evantandersen/mount/src/MurmurHash3.c:106: undefined reference to `fmix'

And, MurmurHash3.c:

inline uint64_t rotl64 ( uint64_t x, int8_t r )
{
  return (x << r) | (x >> (64 - r));
}

//-----------------------------------------------------------------------------
// Finalization mix - force all bits of a hash block to avalanche

inline uint64_t fmix ( uint64_t k )
{
  k ^= k >> 33;
  k *= 0xff51afd7ed558ccd;
  k ^= k >> 33;
  k *= 0xc4ceb9fe1a85ec53;
  k ^= k >> 33;

  return k;
}

//-----------------------------------------------------------------------------

void MurmurHash3_x64_128 ( const void * key, const int len,
                           const uint32_t seed, void * out )
{

  const uint8_t * data = (const uint8_t*)key;
  const int nblocks = len / 16;

  uint64_t h1 = seed;
  uint64_t h2 = seed;

  const uint64_t c1 = 0x87c37b91114253d5;
  const uint64_t c2 = 0x4cf5ad432745937f;

  //----------
  // body

  const uint64_t * blocks = (const uint64_t *)(data);

  for(int i = 0; i < nblocks; i++)
  {
    uint64_t k1 = blocks[i*2+0];
    uint64_t k2 = blocks[i*2+1];

    k1 *= c1; k1  = rotl64(k1,31); k1 *= c2; h1 ^= k1;

    h1 = rotl64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;

    k2 *= c2; k2  = rotl64(k2,33); k2 *= c1; h2 ^= k2;

    h2 = rotl64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
  }

  //----------
  // tail

  const uint8_t * tail = (const uint8_t*)(data + nblocks*16);

  uint64_t k1 = 0;
  uint64_t k2 = 0;

  switch(len & 15)
  {
  case 15: k2 ^= ((uint64_t)tail[14]) << 48;
  case 14: k2 ^= ((uint64_t)tail[13]) << 40;
  case 13: k2 ^= ((uint64_t)tail[12]) << 32;
  case 12: k2 ^= ((uint64_t)tail[11]) << 24;
  case 11: k2 ^= ((uint64_t)tail[10]) << 16;
  case 10: k2 ^= ((uint64_t)tail[ 9]) << 8;
  case  9: k2 ^= ((uint64_t)tail[ 8]) << 0;
           k2 *= c2; k2  = rotl64(k2,33); k2 *= c1; h2 ^= k2;

  case  8: k1 ^= ((uint64_t)tail[ 7]) << 56;
  case  7: k1 ^= ((uint64_t)tail[ 6]) << 48;
  case  6: k1 ^= ((uint64_t)tail[ 5]) << 40;
  case  5: k1 ^= ((uint64_t)tail[ 4]) << 32;
  case  4: k1 ^= ((uint64_t)tail[ 3]) << 24;
  case  3: k1 ^= ((int64_t)tail[ 2]) << 16;
  case  2: k1 ^= ((uint64_t)tail[ 1]) << 8;
  case  1: k1 ^= ((uint64_t)tail[ 0]) << 0;
           k1 *= c1; k1  = rotl64(k1,31); k1 *= c2; h1 ^= k1;
  };

  //----------
  // finalization

  h1 ^= len; h2 ^= len;

  h1 += h2;
  h2 += h1;

  h1 = fmix(h1);
  h2 = fmix(h2);

  h1 += h2;
  h2 += h1;

  ((uint64_t*)out)[0] = h1;
  ((uint64_t*)out)[1] = h2;

}

Both rotl64 and fmix are defined in the same file AND above the function MurmurHash3_x64_128.

Upvotes: 3

Views: 811

Answers (2)

Jonathan Wakely
Jonathan Wakely

Reputation: 171263

If you're compiling as C99 then the compiler doesn't have to use an inline function definition, but GCC will when optimising. When not optimising it assumes there is a normal extern definition somewhere in the program, and that's what it tries to link to.

By defining it extern inline you make it the extern definition, so it will be used when not optimised, by calls in the same or different translation units.

By defining it static inline you make it a static definition, so it will be used when not optimised, by calls in the same translation unit only. That inline definition cannot be used to resolve calls in other translation units.

See http://www.greenend.org.uk/rjk/tech/inline.html for more details.

Upvotes: 5

charliehorse55
charliehorse55

Reputation: 1990

For some reason, changing the definitions from

inline type name(parameters)

to

inline static type name(paramaters)

Solved the problem. Not sure if this is a compiler bug, I'd have to read the C standard.

EDIT: gcc v4.6.3, GNU ld v2.22

Turning on optimization solves the error as well (without adding the static keyword), so I'm not entirely sure what's going on.

Upvotes: 0

Related Questions