Normally we have two methods to compile and build the C/CPP projects: makefile and cmakelist.
COMP9024 makefile
####################################################################################
# How to Use
#
# (1) Build the project
# make
# (2) Run the executable
# ./main
# (3) Clean the project
# make clean
#
# If you want to know more about makefile, please refer to:
#
# https://www.gnu.org/software/make/manual/html_node/Rule-Syntax.html
#
# You can reuse this Makefile in different assignments/projects in COMP9024.
# To be simple, please put your *.c and *.h in the src directory.
#
# COMP9024
####################################################################################
PROJ_ROOT_PATH = $(shell pwd)
TARGET_EXE = main
BUILD_DIR = build
C_SRC_FILES = $(shell find ./src -name "*.c")
H_SRC_FILES = $(shell find ./src -name "*.h")
# src/*.c ---> src/*.o ---> build/*.o
TMP_OBJ_FILES = $(C_SRC_FILES:.c=.o)
OBJ_FILES_IN_BUILD =$(subst src/,$(BUILD_DIR)/,$(TMP_OBJ_FILES))
CC= gcc
#CFLAGS = -m32 -g -no-pie --save-temps -I $(PROJ_ROOT_PATH)/src
#CFLAGS = -g --save-temps -I $(PROJ_ROOT_PATH)/src
#CFLAGS = -no-pie --save-temps -fno-asynchronous-unwind-tables -I $(PROJ_ROOT_PATH)/src
CFLAGS = -g -Wall -I $(PROJ_ROOT_PATH)/src
# create a directory
$(shell mkdir -p $(BUILD_DIR))
# the default target
all:
make $(TARGET_EXE)
# generate the target, which depends on the "build/*.o" files
$(TARGET_EXE): $(OBJ_FILES_IN_BUILD)
$(CC) $(CFLAGS) -o $(TARGET_EXE) $(OBJ_FILES_IN_BUILD)
# How to generate a "build/*.o" from a "src/*.c"
# To generate prerequisites automatically, please see COMP9024/C/HowToMake/Makefile.V2
# https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html
$(BUILD_DIR)/%.o: src/%.c $(H_SRC_FILES)
@mkdir -p $(shell dirname $@)
${CC} ${CFLAGS} -c $< -o $@
view:
find ./images -name "*.png" | sort | xargs feh -g 1024x768 &
# clean all the files generated
clean:
rm -rf $(TARGET_EXE) $(BUILD_DIR)
find . -name "*.o" | xargs rm -f
find . -name "*.s" | xargs rm -f
find . -name "*.i" | xargs rm -f
find . -name "*.d" | xargs rm -f
find . -name "*.bc" | xargs rm -f
DEPS Macro:
DEPS is a macro (or variable) that stores the dependencies for the .c files, typically the .h (header) files.
In a C program, .c files (source files) often depend on .h files (header files) for declarations, so they must be recompiled whenever the header files change.
By listing the header files in DEPS, you ensure that if any header file changes, the corresponding .c file will be recompiled.
DEPS = file1.h file2.h file3.h
.o File Rule (Object Files):
The .o files are object files (compiled but not yet linked), which are created from .c files.
This rule applies to any file ending with .o, meaning it’s a generic rule that works for all object files.
Rule Structure
Copy code
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
%.o: %.c $(DEPS)
: This line specifies that to create an .o
file (e.g., main.o
), you need the corresponding .c
file (e.g., main.c) and any header files defined in DEPS.
Key Parts
$(CC)
: The macro that holds the compiler (usually gcc or clang).-c
: Tells the compiler to generate an object file (.o) rather than a final executable.-o $@
: The -o flag tells the compiler where to put the output. The $@ is a special macro that stands for the target file, i.e., the .o file.$<
: This is another special macro that represents the first dependency in the list. In this case, it’s the .c file.$(CFLAGS)
: Compiler flags used for things like optimization or warnings.
Special Macros $@
and $^
:
These macros simplify rules in Makefiles:
$@
: Represents the target file (left of the :), so in %.o: %.c, $@ is the .o file.$^
: Represents all of the dependencies (right of the :), so it expands to both the .c file and the $(DEPS) files.
This makes the rule more general, so it can handle multiple dependencies easily.
Final Example:
Here’s how the Makefile might look with these macros:
Copy code
CC = gcc
CFLAGS = -Wall -g # Compiler flags for warnings and debugging
DEPS = file1.h file2.h
OBJ = main.o otherfile.o
%.o: %.c $(DEPS)
$(CC) -c -o $@ $< $(CFLAGS)
myprogram: $(OBJ)
$(CC) -o $@ $^ $(CFLAGS)
clean:
rm -f *.o myprogram
Welcome to point out the mistakes and faults!