0

I don't have much experience with C and am starting to use makefiles for my C programs. I'm trying to write a multi-target makefile in the simplest possible format, but I keep getting an error. I followed the template I found on a few pages, including this question, which work when I have only one .c and .h, but when I make a utils.h and utils.c file and try to run my program.c file with those dependencies, I keep getting an error:

ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [program] Error 1

I have a utils.h with the function decelerations and the libraries, a utils.c with the function definitions, and a program.c where my main is (and imports the utils.h library and a couple standard ones like time.h). I'm also linking the math.h library (hence the -lm flag). Here is the makefile I'm using (running on a mac) which gives the error above:

program: program.o

    gcc program.o -o program -lm


program.o: program.c utils.o

    gcc -c program.c -o utils.o

    
utils.o: utils.c utils.h

    gcc -c utils.c -o utils.o


clean: 

    @rm *.o program 2>/dev/null || true

I guess I'm doing something wrong in linking utils.o or compiling utils.c, but I can't figure out what. That's my guess because another program that has only a prog.h and a prog.c runs fine with the following makefile:

  prog: prog.o
          gcc prog.o -o prog -lm
  
  prog.o: prog.c prog.h
          gcc -c prog.c -o prog.o
  
  clean: 
          @rm prog.o prog 2>/dev/null || true

Would much appreciate some help, preferably kept as simple as possible (as I said, I'm an absolute beginner with makefiles and have no experience with bash or shell scripting).

nara
  • 176
  • 1
  • 7

1 Answers1

1
  • You have to link both object files compiled from program.c and utils.c.
  • It is bad to give the same name for both of compilation result of program.c and utils.c.

Try this:

# add dependency of utils.o
program: program.o utils.o

    # link utils.o
    gcc program.o utils.o -o program -lm


# you may mean utils.h, not utils.o
program.o: program.c utils.h

    # give another name to the compilation result
    gcc -c program.c -o program.o

utils.o: utils.c utils.h

    gcc -c utils.c -o utils.o


clean: 

    @rm *.o program 2>/dev/null || true
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • Thanks! That worked! So, if I add another target that utils depends on, say utils_utils.c and utils_utils.h, should I add the dependency and link of utils_utils to the utils.o: target only, or do I need to keep adding it to upper targets in the hierarchy ? (like utils.o: utils.c utils.h utils_utils.h program.o: program.c utils.h utils_utils.h and program: program.o utils.o utils_utils.o with gcc program.o utils.o utils_utils.o -o program -lm ) – nara Apr 24 '21 at 01:40
  • Linking should be done in linking, not compiling. You should add `utils_utils.o` to the rule that is generating the executable binary `program`. – MikeCAT Apr 24 '21 at 01:55