LOL
This is a discussion on Can't Compile a code!!! I ran into "undefined reference to" error. within the Linux Programming forums, part of the Platform Specific Boards category; LOL...
LOL
hi
"makeArray" is a macro in the dstruct/src/Array.h file from the SRI sources. and replacing the file fixed it.
I changed the
and the new ones appears:Code:OBJ_READMATRIX= LHash.o Map.o zio.o Array.o File.o Vocab.o option.o ngram-count.o
I copy the entire LHash.cc and I colorized the important lines for the error:Vocab.o:Vocab.cc: .text$_ZN5LHashIjjE6removeEjRb[LHash<unsigned int, unsigned int>::remove(unsigned int, bool&)]+0xb): undefined reference to `LHash<unsigned int, unsigned int>::removedData'
Vocab.o:Vocab.cc: ).text$_ZN5LHashIjjE6removeEjRb[LHash<unsigned int, unsigned int>::remove(unsigned int, bool&)]+0x22): undefined reference to `LHash<unsigned int, unsigned int>::removedData'
Vocab.o:Vocab.cc: ).text$_ZN5LHashIjjE6removeEjRb[LHash<unsigned int, unsigned int>::remove(unsigned int, bool&)]+0x106): undefined reference to `LHash<unsigned int, unsigned int>::removedData'
Vocab.o:Vocab.cc: ).text$_ZN5LHashIjjE6removeEjRb[LHash<unsigned int, unsigned int>::remove(unsigned int, bool&)]+0x22b): undefined reference to `LHash<unsigned int, unsigned int>::removedData'
Code:/* * LHash.cc -- * Linear search hash table implementation * */ #ifndef _LHash_cc_ #define _LHash_cc_ #ifndef lint static char LHash_Copyright[] = "Copyright (c) 1995-2010 SRI International. All Rights Reserved."; static char LHash_RcsId[] = "@(#)$Header: /home/srilm/devel/dstruct/src/RCS/LHash.cc,v 1.53 2010/06/02 04:52:43 stolcke Exp $"; #endif #ifdef PRE_ISO_CXX # include <new.h> # include <iostream.h> #else # include <new> # include <iostream> using namespace std; #endif #include <stdlib.h> #include <string.h> #include <assert.h> #include "C:\cygwin\semanlm\include\srilm\LHash.h" #undef INSTANTIATE_LHASH #define INSTANTIATE_LHASH(KeyT, DataT) \ template <> DataT *LHash< KeyT, DataT >::removedData = 0; \ template class LHash< KeyT, DataT >; \ template class LHa........er< KeyT, DataT > #ifndef __GNUG__ template <class KeyT, class DataT> DataT *LHash<KeyT,DataT>::removedData = 0; #endif /* __GNUG__ */ #ifdef DEBUG template <class KeyT, class DataT> unsigned long LHash<KeyT,DataT>::collisionCount = 0; #endif const unsigned minHashBits = 3; /* minimum no. bits for hashing * tables smaller than this use linear * search to save space */ const float fillRatio = 0.8f; /* fill ration at which the table is * expanded and rehashed */ #define BODY(b) ((LHashBody<KeyT,DataT> *)b) /* * Dump the entire hash array to cerr. Unused slots are printed as "FREE". */ template <class KeyT, class DataT> void LHash<KeyT,DataT>::dump() const { if (body) { unsigned maxEntries = hashSize(BODY(body)->maxBits); unsigned i; for (i = 0; i < maxEntries; i++) { cerr << " " << i << ": "; if (Map_noKeyP(BODY(body)->data[i].key)) { cerr << "FREE"; } else { cerr << BODY(body)->data[i].key #ifdef DUMP_VALUES /* * Only certain types can be printed. */ << "->" << BODY(body)->data[i].value #endif /* DUMP_VALUES */ ; } } } else { cerr << "EMPTY"; } cerr << endl; } template <class KeyT, class DataT> void LHash<KeyT,DataT>::memStats(MemStats &stats) const { stats.total += sizeof(*this); if (body) { unsigned maxEntries = hashSize(BODY(body)->maxBits); stats.total += sizeof(*BODY(body)) + sizeof(BODY(body)->data[0]) * (maxEntries - 1); stats.wasted += sizeof(BODY(body)->data[0]) * (maxEntries - BODY(body)->nEntries); } } /* * Compute the actual minimum size required for a given number of entries */ static inline unsigned roundSize(unsigned size) { if (size < hashSize(minHashBits)) { return size; } else { return (unsigned)((size + 1)/ fillRatio); } } template <class KeyT, class DataT> void LHash<KeyT,DataT>::alloc(unsigned size) { unsigned maxBits, maxEntries; unsigned i; /* * round up to power of two */ maxBits = 0; while (hashSize(maxBits) < size) { assert(maxBits < LHash_maxBitLimit); maxBits++; } maxEntries = hashSize(maxBits); //cerr << "LHash::alloc: current " << (body ? BODY(body)->nEntries : 0) // << ", requested " << size // << ", allocating " << maxEntries << " (" << maxBits << ")\n"; body = (LHashBody<KeyT,DataT> *)malloc(sizeof(*BODY(body)) + (maxEntries - 1) * sizeof(BODY(body)->data[0])); assert(body != 0); BODY(body)->maxBits = maxBits; BODY(body)->nEntries = 0; for (i = 0; i < maxEntries; i++) { Map_noKey(BODY(body)->data[i].key); } //cerr << "memory for header = " << // ((void *)&(BODY(body)->data[0]) - (void *)BODY(body)) << endl; //cerr << "memory per entry = " << // ((void *)&(BODY(body)->data[3]) - (void *)&(BODY(body)->data[2])) << endl; } template <class KeyT, class DataT> LHash<KeyT,DataT>::LHash(unsigned size) : body(0) { if (size != 0) { /* * determine actual initial size */ alloc(roundSize(size)); } } template <class KeyT, class DataT> void LHash<KeyT,DataT>::clear(unsigned size) { if (body) { unsigned maxEntries = hashSize(BODY(body)->maxBits); unsigned i; for (i = 0; i < maxEntries; i++) { if (! Map_noKeyP(BODY(body)->data[i].key)) { Map_freeKey(BODY(body)->data[i].key); } } free(body); body = 0; } if (size != 0) { alloc(roundSize(size)); } } template <class KeyT, class DataT> void LHash<KeyT,DataT>::setsize(unsigned size) { if (body == 0 && size != 0) { alloc(roundSize(size)); } } template <class KeyT, class DataT> LHash<KeyT,DataT>::~LHash() { clear(0); } template <class KeyT, class DataT> LHash<KeyT,DataT>::LHash(const LHash<KeyT,DataT> &source) : body(0) { #ifdef DEBUG cerr << "warning: LHash copy constructor called\n"; #endif *this = source; } template <class KeyT, class DataT> LHash<KeyT,DataT> & LHash<KeyT,DataT>::operator= (const LHash<KeyT,DataT> &other) { #ifdef DEBUG cerr << "warning: LHash::operator= called\n"; #endif if (&other == this) { return *this; } /* * copy hash entries from old to new */ if (other.body) { unsigned maxEntries = hashSize(BODY(other.body)->maxBits); /* * ensure we have exactly the same size as source table */ clear(0); alloc(maxEntries); for (unsigned i = 0; i < maxEntries; i++) { KeyT thisKey = BODY(other.body)->data[i].key; if (!Map_noKeyP(thisKey)) { /* * Copy key */ BODY(body)->data[i].key = Map_copyKey(thisKey); /* * Initialize data, required for = operator */ new (&(BODY(body)->data[i].value)) DataT; /* * Copy data */ BODY(body)->data[i].value = BODY(other.body)->data[i].value; } } BODY(body)->nEntries = BODY(other.body)->nEntries; } else { clear(0); } return *this; } /* * Returns index into data array that has the key which is either * equal to key, or indicates the place where key would be placed if it * occurred in the array. */ template <class KeyT, class DataT> Boolean LHash<KeyT,DataT>::locate(KeyT key, unsigned &index) const { assert(!Map_noKeyP(key)); if (body) { unsigned maxBits = BODY(body)->maxBits; register MapEntry<KeyT,DataT> *data = BODY(body)->data; if (maxBits < minHashBits) { /* * Do a linear search */ unsigned nEntries = BODY(body)->nEntries; register unsigned i; for (i = 0; i < nEntries; i++) { if (LHash_equalKey(data[i].key, key)) { index = i; return true; } } index = i; return false; } else { /* * Do a hashed search */ unsigned hash = LHash_hashKey(key, maxBits); unsigned i; for (i = hash; ; i = (i + 1) & hashMask(maxBits)) { if (Map_noKeyP(data[i].key)) { index = i; return false; } else if (LHash_equalKey(data[i].key, key)) { index = i; return true; } #ifdef DEBUG collisionCount += 1; #endif } } } else { return false; } } template <class KeyT, class DataT> DataT * LHash<KeyT,DataT>::find(KeyT key, Boolean &foundP) const { unsigned index; if ((foundP = locate(key, index))) { return &(BODY(body)->data[index].value); } else { return 0; } } template <class KeyT, class DataT> KeyT LHash<KeyT,DataT>::getInternalKey(KeyT key, Boolean &foundP) const { unsigned index; static KeyT zeroKey; if ((foundP = locate(key, index))) { return BODY(body)->data[index].key; } else { return zeroKey; } } template <class KeyT, class DataT> DataT * LHash<KeyT,DataT>::insert(KeyT key, Boolean &foundP) { unsigned index; assert(!(Map_noKeyP(key))); /* * Make sure there is room for at least one entry */ if (body == 0) { alloc(1); } if ((foundP = locate(key, index))) { return &(BODY(body)->data[index].value); } else { unsigned maxEntries = hashSize(BODY(body)->maxBits); unsigned nEntries = BODY(body)->nEntries; /* * Rehash table if necessary */ unsigned minSize = roundSize(nEntries + 1); if (minSize > maxEntries) { LHashBody<KeyT,DataT> *oldBody = BODY(body); unsigned i; /* * Since LHash_maxEntriesLimit is a power of two minus 1 * we need to check this only when the array is enlarged */ assert(nEntries < LHash_maxEntriesLimit); alloc(minSize); BODY(body)->nEntries = nEntries; if (BODY(body)->maxBits < minHashBits) { /* * Just copy old entries to new storage, no reindexing * required. */ memcpy(BODY(body)->data, oldBody->data, sizeof(oldBody->data[0]) * nEntries); } else { /* * Rehash */ for (i = 0; i < maxEntries; i++) { KeyT key = oldBody->data[i].key; if (! Map_noKeyP(key)) { (void)locate(key, index); memcpy(&(BODY(body)->data[index]), &(oldBody->data[i]), sizeof(oldBody->data[0])); } } } free(oldBody); /* * Entries have been moved, so have to re-locate key */ (void)locate(key, index); } BODY(body)->data[index].key = Map_copyKey(key); /* * Initialize data to zero, but also call constructors, if any */ memset(&(BODY(body)->data[index].value), 0, sizeof(BODY(body)->data[index].value)); new (&(BODY(body)->data[index].value)) DataT; BODY(body)->nEntries++; return &(BODY(body)->data[index].value); } } template <class KeyT, class DataT> DataT * LHash<KeyT,DataT>::remove(KeyT key, Boolean &foundP) { unsigned index; /* * Allocate pseudo-static memory for removed objects (returned by * remove()). We cannot make this static because otherwise * the destructor for DataT would be called on it at program exit. */ if (removedData == 0) { removedData = (DataT *)malloc(sizeof(DataT)); assert(removedData != 0); } if ((foundP = locate(key, index))) { Map_freeKey(BODY(body)->data[index].key); Map_noKey(BODY(body)->data[index].key); memcpy(removedData, &BODY(body)->data[index].value, sizeof(DataT)); if (BODY(body)->maxBits < minHashBits) { /* * Linear search mode -- Just move all entries above the * the one removed to fill the gap. */ unsigned nEntries = BODY(body)->nEntries; memmove(&BODY(body)->data[index], &BODY(body)->data[index+1], (nEntries - index - 1) * sizeof(BODY(body)->data[0])); Map_noKey(BODY(body)->data[nEntries - 1].key); } else { /* * The entry after the one being deleted could actually * belong to a prior spot in the table, but was bounced forward due * to a collision. The invariant used in lookup is that * all locations between the hash index and the actual index are * filled. Hence we examine all entries between the deleted * position and the next free position as whether they need to * be moved backward. */ while (1) { unsigned newIndex; index = (index + 1) & hashMask(BODY(body)->maxBits); if (Map_noKeyP(BODY(body)->data[index].key)) { break; } /* * If find returns false that means the deletion has * introduced a hole in the table that would prevent * us from finding the next entry. Luckily, find * also tells us where the hole is. We move the * entry to its rightful place and continue filling * the hole created by this move. */ if (!locate(BODY(body)->data[index].key, newIndex)) { memcpy(&(BODY(body)->data[newIndex]), &(BODY(body)->data[index]), sizeof(BODY(body)->data[0])); Map_noKey(BODY(body)->data[index].key); } } } BODY(body)->nEntries--; return removedData; } else { return 0; } } #ifdef __GNUG__ static #endif int (*LHash_thisKeyCompare)(); /* used by LHa........er() to communicate * with compareIndex() */ #ifdef __GNUG__ static #endif void *LHash_thisBody; /* ditto */ template <class KeyT, class DataT> void LHa........er<KeyT,DataT>::sortKeys() { /* * Store keys away and sort them to the user's orders. */ unsigned maxEntries = hashSize(myLHashBody->maxBits); unsigned *sortedIndex = new unsigned[numEntries]; assert(sortedIndex != 0); unsigned i; unsigned j = 0; for (i = 0; i < maxEntries; i++) { if (!Map_noKeyP(myLHashBody->data[i].key)) { sortedIndex[j++] = i; } } assert(j == numEntries); /* * Due to the limitations of the qsort interface we have to * pass extra information to compareIndex in these global * variables - yuck. */ LHash_thisKeyCompare = (int(*)())sortFunction; LHash_thisBody = myLHashBody; qsort(sortedIndex, numEntries, sizeof(*sortedIndex), compareIndex); /* * Save the keys for enumeration. The reason we save the keys, * not the indices, is that indices may change during enumeration * due to deletions. */ sortedKeys = new KeyT[numEntries]; assert(sortedKeys != 0); for (i = 0; i < numEntries; i++) { sortedKeys[i] = myLHashBody->data[sortedIndex[i]].key; } delete [] sortedIndex; } template <class KeyT, class DataT> LHa........er<KeyT,DataT>::LHa........er(const LHash<KeyT,DataT> &lhash, int (*keyCompare)(KeyT, KeyT)) : myLHashBody(BODY(lhash.body)), current(0), numEntries(lhash.numEntries()), sortFunction(keyCompare) { /* * Note: we access the underlying LHash through the body pointer, * not the top-level LHash itself. This allows the top-level object * to be moved without affecting an ongoing iteration. * XXX: This only works because * - it is illegal to insert while iterating * - deletions don't cause reallocation of the data */ if (sortFunction && myLHashBody) { sortKeys(); } else { sortedKeys = 0; } } /* * This is the callback function passed to qsort for comparing array * entries. It is passed the indices into the data array, which are * compared according to the user-supplied function applied to the * keys found at those locations. */ template <class KeyT, class DataT> int LHa........er<KeyT,DataT>::compareIndex(const void *idx1, const void *idx2) { return (*(compFnType)LHash_thisKeyCompare) (BODY(LHash_thisBody)->data[*(unsigned *)idx1].key, BODY(LHash_thisBody)->data[*(unsigned *)idx2].key); } template <class KeyT, class DataT> LHa........er<KeyT,DataT>::~LHa........er() { delete [] sortedKeys; } template <class KeyT, class DataT> void LHa........er<KeyT,DataT>::init() { delete [] sortedKeys; current = 0; { /* * XXX: fake LHash object to access numEntries() */ LHash<KeyT,DataT> myLHash(0); myLHash.body = myLHashBody; numEntries = myLHash.numEntries(); myLHash.body = 0; } if (sortFunction && myLHashBody) { sortKeys(); } else { sortedKeys = 0; } } template <class KeyT, class DataT> DataT * LHa........er<KeyT,DataT>::next(KeyT &key) { if (myLHashBody == 0) { return 0; } else { unsigned index; if (sortedKeys) { /* * Sorted enumeration -- advance to next key in sorted list */ if (current == numEntries) { return 0; } /* * XXX: fake LHash object to access locate() */ LHash<KeyT,DataT> myLHash(0); myLHash.body = myLHashBody; myLHash.locate(sortedKeys[current++], index); myLHash.body = 0;; } else { /* * Detect deletions by comparing old and current number of * entries. * A legal deletion can only affect the current entry, so * adjust the current position to reflect the next entry was * moved. */ if (myLHashBody->nEntries != numEntries) { assert(myLHashBody->nEntries == numEntries - 1); numEntries --; current --; } /* * Random enumeration mode */ unsigned maxBits = myLHashBody->maxBits; if (maxBits < minHashBits) { /* * Linear search mode - advance one to the next entry */ if (current == numEntries) { return 0; } } else { unsigned maxEntries = hashSize(maxBits); while (current < maxEntries && Map_noKeyP(myLHashBody->data[current].key)) { current++; } if (current == maxEntries) { return 0; } } index = current ++; } key = myLHashBody->data[index].key; return &(myLHashBody->data[index].value); } } #undef BODY #endif /* _LHash_cc_ */
You're going to get these undefined references errors all the time UNTIL you put ALL the .o files on your list. If you are referencing something that appears in a different file, well then, it's not going to work if you decide to leave that file out. Here it's referencing a member variable of the class, so the compiler needs to make sure it has the definition of the class.
I don't get what you mean. would you explain more?
You said there are 18 .c files, each of which needs to be turned into an .o file. And yet:
So where are the other 10 .o files?Code:OBJ_READMATRIX= LHash.o Map.o zio.o Array.o File.o Vocab.o option.o ngram-count.o