148

I have three files: program.c, program.h and headers.h.

program.c includes program.h and headers.h.

I need to compile this on Linux using gcc compiler. I'm not sure how to do this. Netbeans created one for me, but it's empty.

nbro
  • 15,395
  • 32
  • 113
  • 196
user69514
  • 26,935
  • 59
  • 154
  • 188
  • 1
    There is an extremely elegant (and well documented) solution at https://spin.atomicobject.com/2016/08/26/makefile-c-projects/. – Casey May 03 '18 at 08:16

5 Answers5

221

Interesting, I didn't know make would default to using the C compiler given rules regarding source files.

Anyway, a simple solution that demonstrates simple Makefile concepts would be:

HEADERS = program.h headers.h

default: program

program.o: program.c $(HEADERS)
    gcc -c program.c -o program.o

program: program.o
    gcc program.o -o program

clean:
    -rm -f program.o
    -rm -f program

(bear in mind that make requires tab instead of space indentation, so be sure to fix that when copying)

However, to support more C files, you'd have to make new rules for each of them. Thus, to improve:

HEADERS = program.h headers.h
OBJECTS = program.o

default: program

%.o: %.c $(HEADERS)
    gcc -c $< -o $@

program: $(OBJECTS)
    gcc $(OBJECTS) -o $@

clean:
    -rm -f $(OBJECTS)
    -rm -f program

I tried to make this as simple as possible by omitting variables like $(CC) and $(CFLAGS) that are usually seen in makefiles. If you're interested in figuring that out, I hope I've given you a good start on that.

Here's the Makefile I like to use for C source. Feel free to use it:

TARGET = prog
LIBS = -lm
CC = gcc
CFLAGS = -g -Wall

.PHONY: default all clean

default: $(TARGET)
all: default

OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)

%.o: %.c $(HEADERS)
    $(CC) $(CFLAGS) -c $< -o $@

.PRECIOUS: $(TARGET) $(OBJECTS)

$(TARGET): $(OBJECTS)
    $(CC) $(OBJECTS) -Wall $(LIBS) -o $@

clean:
    -rm -f *.o
    -rm -f $(TARGET)

It uses the wildcard and patsubst features of the make utility to automatically include .c and .h files in the current directory, meaning when you add new code files to your directory, you won't have to update the Makefile. However, if you want to change the name of the generated executable, libraries, or compiler flags, you can just modify the variables.

In either case, don't use autoconf, please. I'm begging you! :)

Joey Adams
  • 41,996
  • 18
  • 86
  • 115
  • 7
    To be technically correct, I believe you should use `.PHONY: clean all default` for those targets that are meant to be used from the command line. Also, Autoconf/Automake aren't that bad. Sure, they feel awful, and getting used to them is about as fun as forcing your head through a brick wall, but they do work, and they're well developed, and they'll cover most of your bases as far as portability, and will make your life a lot easier in the end once you get used to their awful design. – Chris Lutz Sep 28 '09 at 00:25
  • I guess this works, but I thought if I typed "make" on the terminal the program should run. This is what I get: gcc statsh.o -Wall -lm -o prog Is it possible to just type make and execute the program? – user69514 Sep 28 '09 at 00:38
  • where would you add the openmp flag -fopenmp – MySchizoBuddy Dec 24 '13 at 20:39
  • You sure this works? Even after copying and pasting your first example directly this gives "Cannot find the file specified", listing the .o file. Pretty sure it isn't creating the .o first – krb686 May 04 '14 at 14:42
  • @krb686: Thanks for letting me know. Did you make sure the makefile is indented with tabs instead of spaces? – Joey Adams May 05 '14 at 17:16
  • 1
    Why don't use autoconf joey-adams ? – Michal Gonda Apr 01 '16 at 12:03
  • 9
    If anyone wonders why there are dashes in front of `rm`: https://stackoverflow.com/questions/2989465/rm-rf-versus-rm-rf – Tor Klingberg May 22 '17 at 14:00
  • @JoeyAdams I use `make -n -f Makefile hello.c` but results `make: Nothing to be done for `hello.c'.` my [Makefile](https://paste.ubuntu.com/25895072/) ` #This is assignment 1, week one of System Programming of Griffith University. #@author: alhelal CC=gcc CFLAGS=-Wall hello : hello.o $(CC) -o $@ $< hello.o : hello.c $(CC) $(CFLAGS) -o $@ -c $<` – alhelal Nov 05 '17 at 13:46
  • Isn't the `$(HEADERS)` in `%.o: %.c $(HEADERS)` unnecessary? You get all of the existing header files with `HEADERS = $(wildcard *.h)`, and then assert that they must all exist. – Yay295 Sep 03 '18 at 07:09
  • 1
    Better use `:=` instead of `=`. With `:=` the `wildcard` function just runs once and one can append/extend variables later `OBJS := $(OBJS) other.o`. With `=` this is not possible, it will cause an infinite loop in the variable expansion! See: [The Two Flavors of Variables](https://www.gnu.org/software/make/manual/html_node/Flavors.html#Flavors). – netzego Nov 05 '21 at 20:14
26

For example this simple Makefile should be sufficient:

CC=gcc 
CFLAGS=-Wall

all: program
program: program.o
program.o: program.c program.h headers.h

clean:
    rm -f program program.o
run: program
    ./program

Note there must be <tab> on the next line after clean and run, not spaces.

UPDATE Comments below applied

Viliam
  • 4,404
  • 3
  • 28
  • 30
  • @user69514: `make` with no arguments usually only *build* your software. To run it, either use `make run` (available in this answer, but not necessarily in all `Makefile`s), or run it directly: `./program` – MestreLion Jan 22 '15 at 06:23
15
all: program
program.o: program.h headers.h

is enough. the rest is implicit

anonymous
  • 3,310
  • 1
  • 15
  • 12
  • 2
    And if your whole program is a single `.c` file, only `program:` is necessary. Sweet :) – MestreLion Jan 22 '15 at 06:14
  • While this is surely simple, no doubt, anonymous & @MestreLion , I am new to C, and have only recently split a large project into 2 source files and a header, and I am **not** using makefiles but rather a *very* simple C program that basically just uses `system()` from `stdlib.h`... No cons of this approach, are there ? – A P Jo Sep 04 '20 at 07:09
  • @APJo: with simple projects you can get away without a `Makefile` and simply directly invoke `gcc *.c *.h -o program`, possibly adding options like `-Wall -O2`, etc. – MestreLion Sep 04 '20 at 19:20
12

The simplest make file can be

all : test

test : test.o
        gcc -o test test.o 

test.o : test.c
        gcc -c test.c

clean :
        rm test *.o
Indrakumar
  • 121
  • 1
  • 3
1

Depending on the number of headers and your development habits, you may want to investigate gccmakedep. This program examines your current directory and adds to the end of the makefile the header dependencies for each .c/cpp file. This is overkill when you have 2 headers and one program file. However, if you have 5+ little test programs and you are editing one of 10 headers, you can then trust make to rebuild exactly those programs which were changed by your modifications.