CC = gcc
CFLAGS = -Wall -g
# How to include only "hello.h"?
INCLUDES = -Isrc/lilb
# How to write the rest for debugging only "hello.c"?
First of all you don't need to specify explicitly the compiler you are going to use. Make uses default options that will start cc which is normally an alias of the compiler you use in your environment. This is also true for CFLAGS but, as the default flags are not the ones you state, you need to specify them. This also affects the include directories where you save your files.
Next you need to specify a set of dependency commands between source, compiler (.o files) and the final executable. As you have several files conforming the final executable you will need to specify the dependencies between the executable and the .o files from which it is made, and the dependencies from the .c sources and the .h sources included by the .c files (unfortunately you don't specify which .h files you include in each .c and .h files. I will assume some arrangement, based on my experience)
As an example, and to give you the most spread variety of cases I will assume that each source file source.c will #include <source.h> and that the foo compilation unit includes bar.h and hello and world both include foo.h.
hello.c -- hello.h
+ world.h
+ foo.h
world.c -- world.h
+ foo.h
foo.c -- foo.h
+ bar.h
bar.c -- bar.h
We will start with the dependencies of hello_world (I will use variables to avoid repetitions):
hello_world_objs = hello.o world.o foo.o bar.o
hello_world: $(hello_world_objs)
$(CC) $(LDFLAGS) -o $@ $(hello_world_objs)
Which will link all the object files into a new executable in case any of them changes.
Next, we need to specify the dependencies of the object files. I will write one dependency only as the make tool has some implicit rules that allow you to compile only specifying the object file and the source file:
foo.o: foo.c foo.h bar.h
$(CC) $(CFLAGS) -c -o $@ foo.c
This rule before is implicitly included in make by indicating a series of suffixes in the makefile and the dependencies between them. As I say, you don't need to create the automatic dependency because it is included by default in make:
.c.o: # dependency of a .o file from a .c file
$(CC) $(CFLAGS) -c -o $@ $<
You will see there are special variable names that allow you to abreviate the target ($@) and the dependent file ($<) in the command line.
If you have special dependencies you want to specify but the normal case is to compile a source using the implicit command, you can specify that in a rule that has no commands below, like:
hello.o: hello.c hello.h world.h
world.o: world.c world.h foo.h
foo.o: foo.c foo.h bar.h
bar.o: bar.c bar.h
all these files will be compiled each with the default routing, in case the source or any of the header files it includes is changed.
Finally, as you have seen, the variable CFLAGS is included in the command of the implicit rule to compile a file, but the INCLUDES variable is not. In order to compile all files specifying the includes directory, you need to add the INCLUDES variable contents into the CFLAGS with
CFLAGS += $(INCLUDES)
so finally your Makefile will be:
(A final note: I have added the compilation option -O0 to inhibit all optimizations, as if you are going to debug your code you will need to deactivate optimizations, so your compiled code reflects exactly what you wrote in the source. Or you will see strange things when running the compiler over optimized code.)
# Makefile -- script to build hello_world
# Author: Put your name here.
# Date: Mon Oct 27 10:31:48 EET 2025
# Copyright: (C) 2025 your name again here.
# License: bla bla.
CFLAGS = -Wall -g -O0
LDFLAGS = -g
INCLUDES = -I src/lilb
CFLAGS += $(INCLUDES) # you don't need INCLUDES if you had
# added the includes directory directly
# to CFLAGS
hello_world_objs = hello.o world.o foo.o bar.o
hello_world: $(hello_world_objs)
$(CC) $(LDFLAGS) -o $@ $($@_objs)
# Explicit dependencies between files, to be compiled with
# the implicit .c --> .o make rule
# .c.o:
# $(CC) $(CFLAGS) -c -o $@ $<
hello.o: hello.c hello.h world.h
world.o: world.c world.h foo.h
foo.o: foo.c foo.h bar.h
bar.o: bar.c bar.h
make src/lib/world.omain()function? You might want to edit your question to clarify and optimally add a minimal reproducible example.