'Makefile with multiple source folders

I'm trying to write a make file for my C++ project

I have the following source structure

project folder content:

main.cpp
lib/
include/
src/

as the name says 'main.cpp' contain the main() function, include hold the *.h files and src hold *.cpp file (and in case other subfolders with other sources)

what I would like to achieve is a makefile that as target compile main.cpp and all his included sources recursivelly , without specify all the sources names or mantaining the make file adding a source every time I create or add it

any help or a good tutorial to solve this problem would be very appreciated



Solution 1:[1]

Not sure what flavour of Makefile you use, or what OS you're building, however here are some ideas for a GNU Make and a unix-like environment

  1. Use a single make (instead of recursively invoking make on subdirectories).
  2. Use prefix rules to generate *.cpp to *.o
  3. Now consider an src.mk present on each source subdirectory that fills an SRC variable with the actual *.cpp on each directory:

    SRC+= $(addprefix $(ROOT)/src/, \
        Source1.cpp \
        Source2.cpp \
    )
    
  4. ... and in the Makefile you can have an

    -include src.mk
    OBJ=$(SRC:.cpp=.o)
    executable: $(OBJ)
    
  5. Now the next thing is to be able to generate the src.mk: you can have a prefix rule for that and rely on a shell script:

    %/src.mk: %/
         gensrc $(dir $@)
    
  6. The gensrc is a shell script that adds -include subdir/src.mk for each subdir of the argument and creates SRC variable with the *.cppin the argument directory.

Hope this gives you some ideas.

Solution 2:[2]

bro!

If your main project architecture just like this:

fitBody

|

|__main.cpp

|__Makefile

|__build

|__lib

    |__XYZ

|__include
             
    |__fitbody.h

|__src
             
    |__fitbody.cpp

    [...]

Update Jan. 31 2022 PM 17:27

Just use this Makefile:

# (1)Compiler
CXX = clang++
# (2)Compile options
CXX_FLAGS = -Wall -Wextra -std=c++11 -g
# (3)Build task directory path
# I do care about out-of-source builds
BUILD_DIR ?= ./build
# (4)Source files directory path
SRC_DIRS ?= ./
SRC_DIRS_SRC ?= ./src
# (5)Library files directory path
LIBDIR :=
# (6)Add library files
LIBS := ./lib
# (7)Target file, excutable file.
TARGET ?= main
# (8)Source files(code), to be compiled
# Find source files we want to compile 
# *expression must around by single quotos
SRCS := $(shell find $(SRC_DIRS) -name '*.cpp' -or -name '*.c' -or -name '*.s')
SRCS_SRC := $(shell find $(SRC_DIRS_SRC) -name '*.cpp' -or -name '*.c' -or -name '*.s')
# (9)Object files
# String substituion for every C/C++ file
# e.g: ./src/bank.cpp turns into ./build/bank.cpp.o
OBJS := $(patsubst %.cpp, ${BUILD_DIR}/%.cpp.o, $(notdir $(SRCS)))
OBJS_SRC := $(patsubst %.cpp, ${BUILD_DIR}/%.cpp.o, $(notdir $(SRCS_SRC)))
# (10)Dependency files
# which will generate a .d file next to the .o file. Then to use the .d files,
# you just need to find them all:
DEPS := $(OBJS:.o=.d)
DEPS_SRC := $(OBJS_SRC:.o=.d)
# (11)Include files directory path
# Every folder in ./src find include files to be passed via clang 
INC_DIRS := ./inc
# (12)Include files add together a prefix, clang make sense that -I or -L flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
LIBS_FLAGS := $(addprefix -L,$(LIBS)) 
# (13)Make Makefiles output Dependency files
# That -MMD and -MP flags together to generate Makefiles 
# That generated Makefiles will take .o as .d to the output
# That "-MMD" and "-MP" To generate the dependency files, all you have to do is
# add some flags to the compile command (supported by both Clang and GCC):
CPP_FLAGS ?= $(INC_FLAGS) -MMD -MP
# (14)Link: Generate executable file from the object file
# make your target depend on the object files:
${BUILD_DIR}/${TARGET} : $(OBJS) 
    $(CXX) $^ -o $@ $(LIBS_FLAGS)
# (15)Compile: Generate object files from source files
# $@ := {TARGET}
# $< := THE first file
# $^ all the dependency
# C++ Sources
$(BUILD_DIR)/%.cpp.o : $(SRC_DIRS)/%.cpp 
    $(MKDIR_P) $(dir $@)
    $(CXX) $(CPP_FLAGS) $(CXX_FLAGS) -c $< -o $@
$(BUILD_DIR)/%.cpp.o : $(SRC_DIRS_SRC)/%.cpp 
    $(CXX) $(CPP_FLAGS) $(CXX_FLAGS) -c $^ -o $@

.PHONY:  all clean 
all: ${BUILD_DIR}/${TARGET}
clean:
    $(RM) $(DEPS) $(DEPS_MAIN) $(OBJS) $(OBJS_MAIN) ${BUILD_DIR}/${TARGET} 

-include $(DEPS) $(DEPS_MAIN)

MKDIR_P ?= mkdir -p
 

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jsantander
Solution 2