How do I make a simple makefile for gcc on Linux? - c

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.

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! :)

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

all: program
program.o: program.h headers.h
is enough. the rest is implicit

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

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.

Related

How to run a C program when it has multiple files?

In a program, I have a list.c file, list.h file and run.c file. In the run.c file, the code contains my main program and also "#include list.h". In my list.h file, my functions are just void and being defined. Finally, in my list.c file, I include list.h again and I have the meaning and code of what each function is going to do. I made a makefile that looks like so:
SOURCES = run.c list.c
OBJECTS= run.o list.o
HEADERS = list.h
CC = gcc
CFLAGS = -g -Wall
lab1: $(OBJECTS)
(tab) $(CC) $(CFLAGS) $(OBJECTS) -o lab1
clean:
(tab) rm -fR *o lab1
There is nothing wrong in any of my code because it is already finished and I am just copying code. However, I am unsure how to use the makefile to run these multiple files. I am only familiar with runner files after compiling with gcc and using "./". Is there something wrong with my makefile or is there a step for compiling these files in a different way?
Thank you for any help
The given makefile is working and generates an executable lab1 file. However, the .o files depend on the list.h file, and this dependency is not captured.
You should specify targets to build the .o files, as follows:
SOURCES = run.c list.c
OBJECTS= run.o list.o
HEADERS = list.h
CC = gcc
CFLAGS = -g -Wall
lab1: $(OBJECTS)
(tab) $(CC) $(CFLAGS) $(OBJECTS) -o lab1
%.o: %.c $(HEADERS)
$(CC) -c $(CFLAGS) $< -o $#
clean:
rm -fR *o lab1
Word of caution: With this makefile, if the list of HEADERS grows, a change in any of the headers will warrant a rebuild of all .o files.
For example, imagine we also have buf.c which uses buf.h. Now HEADERS = list.h buf.h. If we change buf.h, our makefile would rebuild both list.o and buf.o, even though a buf.o rebuild would suffice.
To remedy this, we could use a more verbose makefile which identifies the specific header prerequisites for each .o file with rules such as the following:
list.o: list.c list.h
$(CC) -c $(CFLAGS) $< -o $#
buf.o: buf.c buf.h
$(CC) -c $(CFLAGS) $< -o $#
Solution 1: Simply list each .c file separately as input and compile once
gcc list.c run.c -o lab1
Solution 2: Compile each .c file separately
gcc -c list.c
gcc -c run.c
gcc -o lab1 list.o run.o
Your project is small and simple enough that a fully generalized makefile is overkill:
SOURCES = run.c list.c
CC = gcc
CFLAGS = -g -Wall
all:
$(CC) $(CFLAGS) $(SOURCES) -o lab1
clean:
rm -fR *o lab1
The all: is a default target that executes when you simply type make with no arguments.
After compiling, it did end up making a lab1 file that I could run and everything worked. My makefile ended up working fine, I was just completely oblivious to the fact that it was making a file called lab1. I did change my makefile to the above options and that also worked. Thank you

When I use "gcc" in makefile, after making it, I got a "cc" output

For example:
There are 3 source files {main.c test1.c test2.c} in the directory
and a directory file named test3,
and there is a source file named test.c in the directory of test3.
Now I want to create a makefile to compile and link these four source files.
And this is my Makefile:
# Cancel statement "CC=gcc"
src:=$(wildcard *.c) test3.c
obj:=$(patsubst %.c,%.o,$(src))
main:$(obj)
gcc -o main $(obj)
.PHONY:clean
clean:
rm *.o *~
When I called make to compile them, I got a output like this:
cc -c -o main.o main.c
cc -c -o test1.o test1.c
cc -c -o test2.o test2.c
cc -c -o test3.o test3/test3.c
gcc -o main main.o test1.o test2.o test3.o
I know 'cc' is linked to 'gcc' in Linux.
What I don't understand is why did Make call cc to compile these four source files, but call gcc to link the object files?
You changed one rule: the one that links the program main from the object files. And when make did that link, you can see it used gcc.
You didn't do anything to change the built-in rules that make is using to compile the object files, so they use the default (the value of the variable CC) which is cc.
You wrote only the rule to link the object files, and allowed Make to use its default rule to decide how to build the object files from the source files.
GNU Make will expose its rules if you ask it with --print-data-base. In this case, it tells us
%.o: %.c
# recipe to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
and
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
and finally
CC = cc
This explains why Make uses cc to compile your C sources. To change that, simply set CC = gcc. Here's a complete Makefile which does that and also makes best use of Make's built-in rules, to help when you need to extend it:
src := $(wildcard *.c) test3.c
obj := $(patsubst %.c,%.o,$(src))
CC = gcc
main: $(obj)
$(LINK.c) -o $# $^ $(LDLIBS)
.PHONY: clean
clean:
$(RM) *.o *~

Why does my Makefile do nothing?

#
# MakeFile assignment 2
# Variables
CC=gcc
LINK=gcc
CFLAGS=-c -Wall -I.
OBJECT_FILES = cmpsc311-f13-assign2.o a2support.o
#Suffix rules
.SUFFIXES: .c .o
.c.o:
$(CC) -c $(CFLAGS) -o $# $<
#Productions
cmpsc311-f13-assign2 : $(OBJECT_FILES)
$(LINK) $(OBJECT_FILES) -o $#
#Dependencies
cmpsc311-f13-assign2.o : cmpsc311-f13-assign2.c a2support.h
a2support.o : a2support.c a2support.h
clean:
rm cmpsc311-f13-assign2.o
rm a2support.o
Every time I use the command make Makefile it does nothing, is there something wrong with my makefile or is it another issue?
Running the following command also dose nothing:
gcc -o cmpsc311-f13-assign2 cmpsc311-f13-assign2.c a2support.c a2support.h -I.
Every time I use the command make Makefile it does nothing
make Makefile tries to create Makefile. Since you don't have any rule to create it, there's nothing to do.
Usually make is invoked with no arguments; it uses Makefile by default, and tries to make the first target defined (in your case, cmpsc311-f13-assign2).
You can use the -f option to specify a different makefile to use:
make -f foo.mk
or you can use an argument to specify what to build:
make clean
or both:
make -f foo.mk clean
Apart from the answer mentioned above you also need to add a TAB character at line 14.
$(CC) -c $(CFLAGS) -o $# $<

Using a Makefile with C

So I have three files:
jarvismarch.c (includes "jarvismarchtools.h")
jarvismarchtools.c
jarvismarchtools.h
I would like to use a makefile to compile the aforementioned files. How would I go about this?
The typical minimal makefile looks like this:
OBJ = jarvismarch.o jarvismarchtools.o
all: $(OBJ)
$(CC) -o jarvismarch $(OBJ)
Taking the comment of asveikau into account and adding a clean target it becomes:
OBJ = jarvismarch.o jarvismarchtools.o
BIN = jarvismarch
CFLAGS = -Wall -pedantic -ansi
all: $(BIN)
$(BIN): $(OBJ)
$(CC) -o # $(OBJ)
clean:
rm -f $(OBJ) $(BIN)
(Windows users need to use .obj instead of .o)
I strongly recommend against using make. It might be simple at first, but once your project grows I highly recommend a more complete build tool like SCons, CMake or Boost.Build.
Assuming that you are trying to build jarvismarch.exe:
jarvismarch.exe : jarvismarch.o jarvismarchtools.o
$(CC) -o $# $^
The leading whitespace on the second line needs to be a TAB character.

make file, Is this look ok?

all: run
run: test.o list.o matrix.o smatrix.o
gcc test.o list.o matrix.o smatrix.o -o matrix-mul
list.o: list.c list.h
gcc -g -c list.c
matrix.o: matrix.c matrix.h
gcc -g -std=c99 -c -o matrix.o matrix.c
smatrix.o: smatrix.c smatrix.h
gcc -g -c -o smatrix.o smatrix.c
test.o: test.c test.h
gcc -g -c test.c
I was having lots of problems to make a makefile and I finally got this working. And I just want to make sure these are ok (not just for making program running but in term of a good make file)
One question is that why do matrix.o and smatrix.o have .o files in the line gcc -g -c ... where as list.o and test.o don't have that line..
I had to add -std=c99 because I was getting some weird for loop error but still don't understand why I need to put matrix.o in the line..
The file is OK-ish. It is not very easily maintainable.
This website has a really good tutorial on how to make nice makefiles:
http://mrbook.org/blog/tutorials/make/
Especially look at the last example:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
This should show you how to enhance maintainability (add extra files to SOURCES, and the rest is done automatically.
The below file supports make all make depend and make clean - you only need to change the first lines. Remember to make depend if you change includes in any file.
TARGET:=matrix-mul
SOURCES:=test.c list.c matrix.c smatrix.c
OBJECTS:=$(SOURCES:%.c=%.o)
CC=gcc
CFLAGS=-g -std=c99 -Wall
LD=gcc
LDFLAGS=
# First target - simply say that we want to produce matrix-mul
all: $(TARGET)
# To create the target we need all .o files, and we link with LD/LDFLAGS
# $# is the file we're making, aka matrix-mul
$(TARGET): $(OBJECTS)
$(LD) -o $# $(OBJECTS) $(LDFLAGS)
#Creating a .o from a .c
# $< is the c file, $# is the corresponding .o file
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
# Regenerate dependencies
depend:
$(CC) $(CFLAGS) -MM $(SOURCES) > .depend
# Remove produced files
clean:
rm -rf $(OBJECTS) $(TARGET) .depend
# If there's no dependency file, create it
.depend: depend
# Include the autogenerated dependency file
include .depend
EDIT: If you want this even more generic, you can replace the SOURCE:= line with:
SOURCES:=$(wildcard *.c)
This makefile will then simply build TARGET from all .c files in the current directory.
One thing I would highly suggest here would be to add a clean target that deletes all your intermediate files (probably all the .o files), like so:
clean:
rm *.o
For extra credit, put all your *.o files in a make variable, and use that variable as the target of the run rule, and after the rm command above.
The reason I want you to do this is for debugging purposes. It could be that you have one of the above rules wrong, but since you already built all your .o files once, it is just picking up an old one every time. If you do a make clean before your build, it will catch that.

Resources