Makefile

  1. COMP9024 makefile
    1. DEPS Macro:
    2. .o File Rule (Object Files):
      1. Rule Structure
      2. Key Parts
      3. Special Macros $@ and $^:
      4. Final Example:

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!