Makefile Structure - c

I'm making a program in C and I want to know how to structure and run my program using a Makefile.
I have three files:
main.c
count.c
bin2csv.c
I also have these headers:
bin2csv.h
count.h
struct.h
This is my makefile:
CC = gcc
OBJS = main.o count.o bin2csv.o
HEADERS = struct.h count.h bin2csv.h
APP_NAME = project2
all: $(APP_NAME)
$(APP_NAME): $(OBJS) $(HEADERS)
$(CC) $(OBJS) -o $(APP_NAME)
main.o:
$(CC) -c main.c
count.o:
$(CC) -c count.c
bin2csv.o:
$(CC) -c bin2csv.c
clean:
rm -f *.o $(APP_NAME)
My questions are as follows:
What is happening in this make file? It goes through the hierarchy and compiles these .c files into object files, including the headers?
How would I run and compile my program?
I attempted to make a change in main.c, by adding a print statement, but I figure compiling using gcc would throw off the makefile. I know I can use the command make I don't believe anything changed.

You need to say that the .o files depend on the .c files:
main.o: main.c <---- HERE
$(CC) -c main.c
count.o: count.c <---- HERE
$(CC) -c count.c
bin2csv.o: bin2csv.c <---- HERE
Otherwise, make has no reason to think it needs to re-make the .o files.

To prevent re-make (so add dependecies), I recomand you to use a variable to list your .c files instead of .o ones and deduce objects name:
SRC= main.c \
count.c \
bin2csv.c
OBJS= $(SRC:.c=.o)
OBJS will contain your .o filenames, and you can use it in same way that you're doing:
$(APP_NAME): $(OBJS) $(HEADERS)
$(CC) -o $(APP_NAME) $(OBJS)
And clean rule
clean:
rm -f $(OBJS) $(APP_NAME)
If you want change headers files you can add -I to gcc to add specific headers directory:
HEADERS_DIR= $(PROJECT_ROOT)/include
$(CC) -I $(HEADERS_DIR) -o $(APP_NAME) $(OBJS)

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

Makefile doesn't clean object files

Here is the makefile:
OBJS = main.o hashFunction.o input.o list.o list_inverted_index.o memory.o operations.o sort.o
SOURCE = main.c hashFunction.c input.c list.c list_inverted_index.c memory.c operations.c sort.c
HEADER = hashFunction.h input.h list.h list_inverted_index.h memory.h operations.h sort.h
OUT = myexe
CC = gcc
FLAGS = -g -c -Wall
# -g option enables debugging mode
# -c flag generates object code for separate files
all: $(OBJS)
$(CC) -g $(OBJS) -o $(OUT)
# create/compile the individual files >>separately<<
main.o: main.c
$(CC) $(FLAGS) main.c
hashFunction.o: hashFunction.c
$(CC) $(FLAGS) hashFunction.c
input.o: input.c
$(CC) $(FLAGS) input.c
list.o: list.c
$(CC) $(FLAGS) list.c
list_inverted_index.o: list_inverted_index.c
$(CC) $(FLAGS) list_inverted_index.c
memory.o: memory.c
$(CC) $(FLAGS) memory.c
operations.o: operations.c
$(CC) $(FLAGS) operations.c
sort.o: sort.c
$(CC) $(FLAGS) sort.c
# clean house
clean:
rm -f $(OBJS) $(OUT)
# do a bit of accounting
count:
wc $(SOURCE) $(HEADER)
I tried to append this *.o to the clean section (because of this answer), but it didn't work.
I had to modify the makefile as such:
all: $(OBJS)
$(CC) -g $(OBJS) -o $(OUT)
make clean
You might lack a
.PHONY: all clean count
rule. The .PHONY: target and rule should appear near the start of the Makefile, just after the variables definition (in your case, below the definition of FLAGS).
If you happen to have all or clean files (check with ls -l clean all in a terminal), you need to remove them using rm
You'll clean using make clean command.
See also this answer for useful hints (about remake -x & make --trace)
BTW, your FLAGSĀ  should probably be CFLAGS (see output of make -p)
Read the documentation of make
You should not normally need or want to "clean object files". The whole point of using Make, is that you don't clean up but stay dirty!
If you always want to clean everything up and start each build from scratch, then don't bother using Make, but write a shell script instead.

Including a .h file and directing .o files to a directory: Make

I am trying to learn make files.
My directory Structure is
$ ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'
.
|-bin
|---exe
|---obj
|-build
|-include
|-lib
|-make
|-source
What I am trying to do is place my include file conversion.h in include folder, all .c files in source, makefile in make, compiled all .o files in bin/obj and exe in /bin/exe
I referred below posts:
makefile include *.h file in other directory
Using make to move .o files to a separate directory
my makefile is:
VPATH= ./../source
OBJDIR= ./../bin/obj
EXEDIR= ./../bin/exe
#vpath %.o $(OBJDIR)
CFLAGS= -Wall -c -I.
#INCLUDES= -I./../include
objects= binary.o hex.o octal.o
conversion: $(objects)
# gcc -Wall -o conversion $(objects) -I.
binary.o: binary.c conversion.h
gcc $(CFLAGS) $< -o $(OBJDIR)/$#
octal.o: octal.c conversion.h
gcc $(CFLAGS) $< -o $(OBJDIR)/$#
hex.o: hex.c conversion.h
gcc $(CFLAGS) $< -o $(OBJDIR)/$#
clean:
rm -rf $(OBJDIR)/*.o *.o *~ conversion
I am using cygwin.
My questions are:
1) I am not able to include my conversion.h from location ./../include
,-I. works fine if I copy conversion.h to make folder
-but as soon as I replace with -I./../include without any copy of conversion.h in make folder
I get below error
$ make
make: *** No rule to make target 'conversion.h', needed by 'binary.o'. Stop.
2) My makefile does place all .o files to /bin/obj but when I try to use vpath as shown below (instead of using manual placement like --o $(OBJDIR)/$#)
vpath %.o $(OBJDIR)
...
$(OBJDIR)/binary.o: binary.c conversion.h
gcc $(CFLAGS) $< -o $#
...
...
doing above replacement for all .o rules,does not place all .o files to bin/obj directory
Any help would be appreciated.
Thanks
You have to be explicit about the locations of the .h file, the .c files, the .o files, and the executable when you define the targets and their dependencies.
VPATH= ./../source
INCLUDEDIR= ./../include
OBJDIR= ./../bin/obj
EXEDIR= ./../bin/exe
#vpath %.o $(OBJDIR)
INCLUDES= -I./../include
CFLAGS= -Wall -c -I. $(INCLUDES)
objects= $(OBJDIR)/binary.o $(OBJDIR)/hex.o $(OBJDIR)/octal.o
$(EXEDIR)/conversion: $(objects)
# gcc -Wall -o conversion $(objects) -I.
$(OBJDIR)/binary.o: $(VPATH)/binary.c $(INCLUDEDIR)/conversion.h
gcc $(CFLAGS) $< -o $#
$(OBJDIR)/octal.o: $(VPATH)/octal.c $(INCLUDEDIR)/conversion.h
gcc $(CFLAGS) $< -o $#
$(OBJDIR)/hex.o: $(VPATH)/hex.c $(INCLUDEDIR)/conversion.h
gcc $(CFLAGS) $< -o $#
clean:
rm -rf $(OBJDIR)/*.o *.o *~ $(EXEDIR)/conversion
Since your header files are in a separate directory, make cannot locate them. Since it can't locate them, it tries to build them by looking for a target rule. Since it cant find a target, you get the error listed in your question.
The -I./../includes only affects the compiler's include search path. It does not affect how make looks for include.
If you want make to search for your header files you will need to add a vpath for the headers. You will likely get the same error for the source files since they are in a separate directory as well. Thus, you will need to add a vpath for the source files as well.
To get your original to work with vpath as opposed to explicit locations, try the following:
VPATH= ./../source
OBJDIR= ./../bin/obj
EXEDIR= ./../bin/exe
INCLUDES= -I./../include
vpath %.c $(VPATH)
vpath %.h $(INCLUDES)
vpath %.o $(OBJDIR)
CFLAGS= -Wall -c -I. $(INCLUDES)
As noted in my comment and the comments for your referenced question, it is not recommended to use vpath to locate object files.

I need some assistance with Makefile in my project

I'm trying to make a Makefile but I'm having some problems
first I have
2 source files: ~/main.c ~/lib/library.c
1 header file: ~/include/library.h
main.c and library.c both share the same header file library.h
# Compiler options
CC = gcc
INC = -I../include
CFLAGS = -Wall -g -c $(INC)
LIB = -L../lib
LFLAGS = -Wall -g $(LIB)
# Dependencies
LIBS = -libmylib
OBJS = main.o
SRCS = $(OBJS:.o=.c)
EXEC = a.out
# Other rules
RM = rm -rf
TAGS = tags
BAK = Makefile.bak
all: $(EXEC)
#echo ------------------------ Compile Complete ----------------------------
.PHONY: clean depend
$(EXEC): $(OBJS)
$(CC) $(LFLAGS) -o $# $^ $(LIBS)
.c.o:
$(CC) $(INC) -M $^
$(CC) $(CFLAGS) -o $# $<
clean:
$(RM) *.o *~ $(EXEC) $(TAGS) $(BAK)
depend: $(SRCS)
makedepend $(INC) $^
it keeps saying that I it can't make a rule out of library.o
plus I have another question
I acknowledge the fact that when Makefile comes in to action after calling 'make',
and subsequently go to the line .c.o or %c: %o(in GNU enhanced version) and make
.o files. but why doesn't it also call clean and depend automatically?
I've edited some things from the previous version of Makefile
this time, (well pretty similar to the previous problem) even though I
clarified the library path(-I../lib),
the Makefile cannot find the archive file (which I created as libmylib.a in ../lib dir)
now it's driving me crazy
but why doesn't it also call clean and depend automatically?
Because make only builds the target you tell it. If you don't specify one, the first target is built, which in many cases, such as yours, is the 'all' target.

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