03/15/06, CISC181 What kind of error is this? > CC testComputeSplitTime5.cc Undefined first referenced symbol in file double computeSplitTime(const char*const) testComputeSplitTime5.o ld: fatal: Symbol referencing errors. No output written to a.out > (1) This is a l__________ing error. (2) It means that you have a function _____________ but you don't have a matching function ______________ Fill in the second two blanks with two of the following: prototype call definition Answer Key: (1) linking (2) call ... definition The same kind of error can occur if you have a file that contains only function definitions, but no main function, e.g.: > CC computeSplitTime.cc Undefined first referenced symbol in file main /opt/SUNWspro/prod/lib/crt1.o ld: fatal: Symbol referencing errors. No output written to a.out > The way to bring these two together is to separately compile, and then link the .o files Start with new fresh directory > ls 03.15.txt castAway csvFiles > mkdir workoutProject1 > change directory into that new directory > cd workoutProject1/ > The following Unix command copies three files that we need from the "sibling" directory csvFiles. By sibling, I mean that these directories... the current one, and the called csvFiles... both share a common parent. .. means parent directory . means current directory > cp ../csvFiles/readWorkoutData3.cc ../csvFiles/computeSplitTime.cc ../csvFiles/testComputeSplitTime5.cc . > ls computeSplitTime.cc readWorkoutData3.cc testComputeSplitTime5.cc > We also need workoutData.dat > cp ../csvFiles/workoutData.dat . > An ls command now gives us everything in the current directory: > ls computeSplitTime.cc readWorkoutData3.cc testComputeSplitTime5.cc workoutData.dat > We will now rename a few things > mv readWorkoutData3.cc readWorkoutData.cc > mv testComputeSplitTime5.cc testComputeSplitTime.cc > > ls computeSplitTime.cc readWorkoutData.cc testComputeSplitTime.cc workoutData.dat > Next step, is to create a Makefile to compile all this code and test it. We use the command "emacs Makefile" We start with a kind of very "genric empty Makefile" *********************************************************** # Makefile for workoutProject1 # P. Conrad for CISC181, 03/15/06 # A project to show how to read a CSV file into an array of structs # also to show how to write a Makefile from scratch # the BINARIES variable is generally a list of the executable programs # it is typically a list of the files that have a main() function in them BINARIES = readWorkoutData testComputeSplitTime all: ${BINARIES} clean: /bin/rm -f ${BINARIES} *.o core a.out *********************************************************** The words all and clean are followed by colons, and are in column 1. That means they are called "targets" in the Makefile For comments, in a Makefile you use # ... everything after the # is a comment If I want to declare a variable, I use ALL CAPITALS and I use an assignment statment with no ; at the end. For instance: BINARIES = readWorkoutData testComputeSplitTime Typically a variable has a value that is a string, or a list of filenames To "use" the value of a variable, you put a $ in front of it, and put the variable name in either { } or ( ) e.g. ${BINARIES} or $(BINARIES) Now readWorkoutData needs to be a combination of readWorkoutData.o and computeSplitTime.o So we have to specify that in the Makefile readWorkoutData: readWorkoutData.o computeSplitTime.o ${CCC} -o readWorkoutData readWorkoutData.o computeSplitTime.o cat -vt is how you can check for tabs in your Makefile So, we find a problem: > make clean /bin/rm -f readWorkoutData testComputeSplitTime *.o core > make CC -c readWorkoutData.cc CC -c computeSplitTime.cc CC -o readWorkoutData readWorkoutData.o computeSplitTime.o Undefined first referenced symbol in file double computeSplitTime(char*) readWorkoutData.o ld: fatal: Symbol referencing errors. No output written to readWorkoutData *** Error code 1 make: Fatal error: Command failed for target `readWorkoutData' > How to find the source of this problem... (1) The function call is in readWorkoutData.o That means we can find the function call in what .cc file? Answer: readWorkoutData.cc (2) grep computeSplitTime *.cc tells us where each occurence of computeSplitTime lives in all of the .cc files > grep computeSplitTime *.cc computeSplitTime.cc:// computeSplitTime.cc computeSplitTime.cc:// separately compiled computeSplitTime() function computeSplitTime.cc:double computeSplitTime(const char * const splitTimePtr) readWorkoutData.cc:double computeSplitTime(char * splitTimePtr); readWorkoutData.cc: workout[i].splitTimeSeconds = computeSplitTime(splitTimePtr); testComputeSplitTime.cc:// write test cases for the computeSplitTime function testComputeSplitTime.cc:// split out the computeSplitTime function to a separate file testComputeSplitTime.cc:double computeSplitTime(const char * const splitTimePtr); testComputeSplitTime.cc: double result = computeSplitTime(splitTimePtr); >