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

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

Related

How do you construct a C makefile so that it compiles the source.c file?

I have three files. main.c, graph.c, and graph.h.
I know the code works without a makefile because I tested it on the onlinegbd compiler. Everything runs smoothly.
When I try to run my makefile in terminal, I get an error of:
undefined reference to "function"
Where "function" is every function I call in main that is in graph.c.
So this leads me to think I'm not compiling graph.c in my makefile.
edit
I have confirmed it is the makefile. I compiled it using:
gcc -o xGraph main.c graph.c
And it ran without issue.
Here is the makefile:
CC = gcc
VPATH = SRC INCLUDE
TARGET = XGraph
CFLAGS = -g -Wall
all: $(TARGET)
$(TARGET): main.o graph.o
$(CC) main.o graph.o -o $(TARGET)
main.o: main.c graph.h
$(CC) $(CFLAGS) main.c
graph.o: graph.c graph.h
$(CC) $(CFLAGS) graph.c
clean:
rm *.o *~ $(TARGET)
When compiling C code the first stage is to generate .o files. Pass the -c flag to gcc to do this.
main.o: main.c graph.h
$(CC) $(CFLAGS) -c main.c
graph.o: graph.c graph.h
$(CC) $(CFLAGS) -c graph.c
In C, there are two types of undefined reference errors. The first results in an implicit declaration of function error, while the second gives your undefined reference. The first says gcc cannot find a definitition of your function. but the second means gcc sees nothing wrong with your code, then tries to link object files using ld and that crashes the code. Make sure that your source files are included in compilation and they have declarations, not just definitions. Also, providing a minimum reproducible example of your code might be helpful here.
Your simplest Makefile can be:
CFLAGS = -g -Wall
xGraph_objs = main.o graph.o
xGraph: $(xGraph_objs)
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $(xGraph_objs)
main.o graph.o: graph.h
as there are implicit rules (that use the $CFLAGS variable, so you don't need to add rules to do the compilation, just to specify the extra dependencies between the objects and the header file)
The structure I use frequently for small projects is very similar to yours:
targets = xGraph
toclean = $(targets)
xGraph_deps = # no dependencies to link the executable. (E.g. creating a library needed to link this)
xGraph_objs = main.o graph.o
xGraph_libs = # no libs to specify at link time. (E.g. -lm -lX11)
xGraph_ldfl = # no flags for the linker. (E.g. -L/usr/local/lib)
toclean += $(xGraph_objs)
all: $(targets)
clean:
$(RM) $(toclean)
xGraph: $(xGraph_deps) $(xGraph_objs)
$(CC) $(LDFLAGS) $(xGraph_ldfl) $(xGraph_objs) -o $# $(xGraph_libs)

Makefile Structure

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)

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.

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.

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

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.

Resources