Thread: C programming Makefile.

  1. #1
    Registered User
    Join Date
    Jan 2017
    Posts
    19

    C programming Makefile.

    Hey guys my first help thread. Hopefully it's on topic. Basically I'm reading Head First C and coding along. I'm currently at a Makefile exercise for a simple calorie calculator output. Heres the code.

    hfcal.h:
    Code:
    void display(float weight, float distance, float coeff);
    hfcal.c:
    Code:
    #include <stdio.h>
    #include <hfcal.h>
    
    void display(float weight, float distance, float coeff)
    {
        printf("Weight: %3.2F\nDistance: %3.2F\nCalories: %3.2F\n",weight,distance,coeff * weight * distance);
    }

    test.c:
    Code:
    #include <stdio.h>
    #include <hfcal.h>
    
    int main()
    {
        display(115.23,3.2,0.79);
        return 0;
    
    }
    Makefile:
    Code:
    hfcal.o: hfcal.c hfcal.h
        gcc -I./includes -c hfcal.c -o hfcal.o 
    treadmill.o: test.c
        gcc -I./includes -c test.c -o treadmill.o
    libcal.a: hfcal.o
        ar -rcs ./libs/libcal.a hfcal.o
    tread_mill: hfcal.o libcal.a
        gcc treadmill.o -L./libs -lcal -o tread_mill
    Current directory:
    Code:
    .:
    hfcal.c  includes  libs  Makefile  test.c
    
    ./includes:
    hfcal.h  hfcal.o
    
    ./libs:
    libcal.a
    I get the error "make: *** No rule to make target 'hfcal.h', needed by 'hfcal.o'. Stop."
    From a little googling I figure that i'm some how using the "gcc -I" dir option incorrectly, but the Makefile code is literally the answer from the book. I'm new to programming, and trying to soak up as much as possible. So any advice is appreciated.

  2. #2
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    You're telling gcc where to find the include files but you're not letting make in on the secret.
    Try:
    Code:
    hfcal.o: hfcal.c includes/hfcal.h
    It should also be noted that the tread_mill rule should go first (making it the "default rule"). Presumably that's how the book did it. Order is important.

    And libcal.a needs to be libs/libcal.a everywhere.

    And of course the indentations must be actual tab characters (not just spaces).
    Last edited by algorism; 02-19-2017 at 10:36 PM.

  3. #3
    Registered User
    Join Date
    Jan 2017
    Posts
    19
    Thanks algorism for the reply! Could you expand on the tread_mill being first a bit. I'm just assuming you mean?
    Code:
    gcc -o tread_mill -L./libs/libcal.a treadmill.o
    Also my Makefile now looks like:
    Code:
    hfcal.o: hfcal.c includes/hfcal.h
        gcc -I./includes -c hfcal.c
    treadmill.o: test.c includes/hfcal.h
        gcc -I./includes -c test.c -o treadmill.o
    libcal.a: hfcal.o
        ar -rcs ./libs/libcal.a hfcal.o
    tread_mill: treadmill.o libs/libcal.a
        gcc -o tread_mill -L./libs/libcal.a treadmill.o
    which seems to build everything up to libcal.a. Making tread_mill throws an error stating:
    Code:
    gcc -o tread_mill -L./libs/libcal.a treadmill.o
    treadmill.o: In function `main':
    test.c:(.text+0x1d): undefined reference to `display'
    collect2: error: ld returned 1 exit status
    Makefile:8: recipe for target 'tread_mill' failed
    make: *** [tread_mill] Error 1
    Did I not link the program properly? How's display undefined? I thought I linked it in hcal.o, treadmill.o through the header and "include <hfcal.h>"?
    I checked the libcal.a with the nm command and there is a display function inside. After this book i'am definetly going through the GNU make manual -.-....
    Last edited by Laerehte; 02-20-2017 at 09:49 PM.

  4. #4
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Try this (ensuring that there are real tabs, which seem to be replaced with spaces here). Also make sure you delete libcal.a and the .o files first.
    Code:
    tread_mill: treadmill.o libs/libcal.a
        gcc -o tread_mill -L./libs treadmill.o -lcal
    hfcal.o: hfcal.c includes/hfcal.h
        gcc -I./includes -c hfcal.c
    treadmill.o: test.c includes/hfcal.h
        gcc -I./includes -c test.c -o treadmill.o
    libs/libcal.a: hfcal.o
        ar -rcs ./libs/libcal.a hfcal.o
    By putting tread_mill rule first, when you just say "make" it will build that program. It defaults to the first one. The way you have it, I assume you need to say "make tread_mill".

    The -L switch should just be -L./libs (without the libcal.a). And you need the -l switch, -lcal

    I'm also assuming that libcal.a needs to be libs/libcal.a everywhere, including the target name (which I changed above). I'm no expert, though.
    Last edited by algorism; 02-20-2017 at 10:08 PM.

  5. #5
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    Instead of
    Code:
    gcc -o tread_mill -L./libs/libcal.a treadmill.o
    I would guess this is more correct.
    Code:
    gcc -o tread_mill treadmill.o -L./libs/libcal.a
    But, I still question this part "-L./libs/libcal.a";
    I think it would more likely be "-l./libs/libcal.a".

    An -L is normally followed by a folder.
    A -l (lower case L) is followed by a library.

    Tim S.
    "...a computer is a stupid machine with the ability to do incredibly smart things, while computer programmers are smart people with the ability to do incredibly stupid things. They are,in short, a perfect match.." Bill Bryson

  6. #6
    Registered User
    Join Date
    Jan 2017
    Posts
    19
    Wow thanks for the replies guys! I had no idea that you had to use the -l (lib) switch in the recipe with the -L (folder). I thought having libs/libcal.a in the prerequisites was enough. Guess not! I also tried the -l./libs/libcal.a (and many variations). They still gave me the same error as -L./libs/libcal.a. Thanks again for the help!

  7. #7
    Registered User
    Join Date
    Jan 2017
    Posts
    19
    Just for fun I fiddled around with the Makefile and options to see what works/doesn't with different prerequisites/recipe combinations. It seems that if your' Makefile is in a different directory it can't tell if the file/files it's compiling are up to date. Here's a little tinker on the Makefile to output the *.o files into an obj folder.
    Code:
    tread_mill: treadmill.o libs/libcal.a
        gcc -o tread_mill ./obj/treadmill.o -L./libs -lcal
    hfcal.o: hfcal.c includes/hfcal.h
        gcc -c hfcal.c -o ./obj/hfcal.o -I./includes
    treadmill.o: test.c includes/hfcal.h
        gcc -c test.c -o ./obj/treadmill.o -I./includes
    libcal.a: hfcal.o
        ar -rcs ./libs/libcal.a ./obj/hfcal.o
    Tested and works for me, but like i said if i run "make hfcal.o" it will just keep re-compiling instead of saying "hfcal.o is up to date.".

  8. #8
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by Laerehte View Post
    Tested and works for me, but like i said if i run "make hfcal.o" it will just keep re-compiling instead of saying "hfcal.o is up to date.".
    In that case it doesn't work since that's the whole point of a makefile, to not rebuild something if it's not necessary.
    The reason it keeps rebuilding it is because the recipe doesn't actually make the target file. I.e., hfcal.o is not obj/hfcal.o.

    Try this:
    Code:
    PROG = tread_mill
    INCS = includes
    LIBS = libs
    OBJS = obj
    
    $(PROG): $(OBJS)/treadmill.o $(LIBS)/libcal.a
        gcc -o $@ $< -L$(LIBS) -lcal
    $(OBJS)/hfcal.o: hfcal.c $(INCS)/hfcal.h
        gcc -o $@ -I$(INCS) -c $<
    $(OBJS)/treadmill.o: test.c
        gcc -o $@ -I$(INCS) -c $<
    $(LIBS)/libcal.a: $(OBJS)/hfcal.o
        ar -rcs $@ $<
    
    .PHONY: clean
    clean:
        rm -f $(LIBS)/*.a
        rm -f $(OBJS)/*.o
        rm -f $(PROG)
    I've used the automatic variables $@ (target filename) and $< (first prerequisite filename). I've also given the program and the directories variable names. And "make clean" will delete the object files, the library file, and the executable (normally a clean command wouldn't delete the executable!).

    Once you get used to it it's actually simpler with the variables.

    To make hfcal.o you need to say "make obj/hfcal.o".
    Last edited by algorism; 02-21-2017 at 10:06 PM.

  9. #9
    Registered User
    Join Date
    Jan 2017
    Posts
    19
    Reading the code you posted is actually a lot easier then what I had worked on algorism .I also really like that clean target. It saved my fingers a lot of typing . I re-configured the Makefile to use the folder/filename last night (sadly only have an hour or so a night to tinker/read/program). Thanks for the explanations guys they've cleared up simple makefiles much more than the book i'am reading. I know I should use variables but just for learning sake this is the Makefile:
    Code:
    tread_mill: obj/treadmill.o libs/libcal.a
        gcc -o tread_mill ./obj/treadmill.o -L./libs -lcal
    obj/hfcal.o: hfcal.c includes/hfcal.h
        gcc  -I./includes -c hfcal.c -o ./obj/hfcal.o
    obj/treadmill.o: test.c includes/hfcal.h
        gcc -c test.c -o ./obj/treadmill.o -I./includes
    libs/libcal.a: obj/hfcal.o
        ar -rcs ./libs/libcal.a ./obj/hfcal.o
    clean:
        rm -f ./libs/*.a
        rm -f ./obj/*.o

  10. #10
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Just to confuse you a little, here's another possibility that will compile your program using "implicit rules". The object files are not in their own directory, though. I also had to change the goal from tread_mill to treadmill, and to use it you have to rename test.c to treadmill.c.
    Code:
    prog = treadmill
    libdir = libs/
    incdir = includes/
    
    # These are special variables used by the implicit rules
    CC = gcc
    CFLAGS = -I$(incdir)
    LDFLAGS = -L$(libdir)
    LDLIBS = -lcal
    ARFLAGS = -rcsU
    
    $(prog): $(prog).o $(libdir)libcal.a(hfcal.o)
    hfcal.o: $(incdir)hfcal.h
    $(libdir)libcal.a(hfcal.o): hfcal.o
    
    .PHONY: clean
    clean:
        -rm -f $(libdir)*.a *.o $(prog)
    Last edited by algorism; 02-22-2017 at 09:37 PM.

  11. #11
    Registered User
    Join Date
    Jan 2017
    Posts
    19
    I'll have to do a little more reading in the make manual to understand that :P.

  12. #12
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    Quote Originally Posted by Laerehte View Post
    I'll have to do a little more reading in the make manual to understand that :P.
    The basic idea is that make can create the recipes automatically from built-in "pattern rules" and using the special variables CC, CFLAGS, etc.

    The other little wrinkle is that we can refer to a single object file in a library like this: libcal.a(hfcal.o)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 2
    Last Post: 12-23-2015, 04:11 PM
  2. Makefile help
    By swappo in forum C Programming
    Replies: 17
    Last Post: 11-19-2008, 10:11 AM
  3. difference makefile makefile.am makefile.in
    By Bargi in forum Linux Programming
    Replies: 7
    Last Post: 10-28-2007, 02:08 PM
  4. help with makefile
    By ICool in forum C Programming
    Replies: 31
    Last Post: 10-22-2007, 10:03 AM
  5. makefile
    By natasha_adams in forum C Programming
    Replies: 1
    Last Post: 01-16-2006, 02:26 PM

Tags for this Thread