Search code examples
c++makefilegeneric-programming

Huge c++ project makefile by hand


I'm using CODEO (Eclipse + overlay) to build an app for the ELinOS RTOS. Thing is, I lose the ability to auto-generate the Makefile using eclipse CDT and I have a generic Makefile alreayd generated.

Instead of typing this huge Makefile (Lots and lots of include and sources directories), I tried things with addprefix patsubst and some wildcard but that didn't work out, mainly because I suck with generic makefile !

Regarding libraries, only a few are used, so I'll write them by hand.

Here is how my code is structured.

Top directory
|
---> common ---> inc/
|                src/
---> pack_AAA ---> comp_AAA ---> inc/
|            |                   src/
|            ----> comp_AAB ---> inc/
|                                src/
---> comp_BBB ---> inc/
|                  src/
---> main.cpp

I'd like to enumerate only the top folders (common, pack_AAA, comp_BBB and so on, mostly because not every TOP folder has to be compiled, my Makefile is in one of these top folder). Below there is a variable amount of subdirectories. Leafs are ALWAYS inc/ (.hpp files) and src/ (as you might guess, .cpp files) folders.

Moreover, the amount of TOP folders won't change, so I mind declaring them, but subfolders will.

Objects files can be anywhere they want (separate top build/ directory, within src/ ...) as long as the resulting executable, let's call it HUGE_PROJECT is in the top directory

Thanks in advance !

SOKS

Here is the generated makefile that I have to start with

-include makefile.init

RM := rm -rf

PROG = HUGE_PROJECT_EXECUTABLE

MODULES := common comp_AAA comp_BBB pack_AAA pack_BBB pack_CCC
SRC_DIRS   := $(addprefix ../../,$(MODULES))
#BUILD_DIR := $(addprefix ../../build/,$(MODULES))

#Original non-recursive & working example
OBJS = $(patsubst %.cpp,%.o,$(wildcard ./src/*.cpp))
DEPS = $(patsubst %.cpp,%.d,$(wildcard ./src/*.cpp))

#bad attempt
#SRCS       := $(foreach sdir,$(SRC_DIRS),$(wildcard $(sdir)/*.cpp))
#OBJS       := $(patsubst %.cpp,%.o,$(SRCS))
#INCLUDES  := $(addprefix -I,$(SRC_DIR))


ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(DEPS)),)
-include $(DEPS)
endif
endif

-include makefile.defs

# All Target
all: $(PROG).tgz

$(PROG).tgz: $(PROG).mkefs $(PROG)
    @echo 'Building file: $@'
    @echo 'Invoking: Embeddable file system generator'
    mkefs -a -s -o"$@" -f"$<"
    @echo 'Finished building: $@'
    @echo ' '

$(PROG): $(OBJS) $(USER_OBJS)
    @echo 'Building target: $@'
    @echo 'Invoking: ELinOS C/C++ Linker'
    $(CXX)  -o "$(PROG)" $(SRCS) $(USER_OBJS) $(LIBS)
    @echo 'Finished building target: $@'
    @echo ' '

clean:
    -$(RM) $(OBJS) $(DEPS) $(PROG) $(PROG).tgz
    -@echo ' '

./src/%.o: ./src/%.cpp
    @echo 'Building file: $<'
    @echo 'Invoking: ELinOS C/C++ Compiler'
    $(CXX) -I./include -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
    @echo 'Finished building: $<'
    @echo ' '

.PHONY: all clean dependents
.SECONDARY:

-include makefile.targets

Solution

  • Here is the Makefile I ended up with. I had to hide components name.

    #Executables
    RM := rm -rf
    CXX=YOUR_CXX_COMPILER
    CC=YOUR_CC_COMPILER
    
    PROG=YOUR_PROGRAM
    
    #Root directory of your program (all files should be in it)
    ROOT_DIR := ../../
    
    #####################################
    
    ########################################
    #      Define here all directories     #
    #   containing src/ and inc/ folders   #
    ########################################
    
    #pack_AAA folders
    #Modules containing both src/ and inc/.
    AAA_MODULES         := moduleA moduleB
    #Modules with an include folder only + module with both
    AAA_DIRS_INC        := moduleD moduleEF $(AAA_MODULES)
    
    #pack_BBB modules list
    BBB_MODULES         := comp_A comp_B comp_C comp_B/comp_D comp_B/comp_E
    
    MMM_MODULES     := comp_F comp_G comp_H
    
    PPP_MODULES     := . I
    
    CCC_MODULES     := J comp_K comp_L \
                        comp_L/comp_M \ 
                        $(addprefix pack_BBB/,$(BBB_MODULES)) \
                        $(addprefix pack_MMM/,$(MMM_MODULES)) \
                        $(addprefix comp_PPP/,$(PPP_MODULES))
    
    #pack_DDD
    DDD_MODULES         := M comp_N comp_N/comp_O
    
    #comp_EEE
    EEE_MODULES     := . P Q
    
    OTHER_MODULES       := R S comp_T
    
    #All folders containing src/ subdir
    SRC_MODULES         := $(OTHER_MODULES) \
                        $(addprefix comp_EEE/,$(EEE_MODULES)) \
                        $(addprefix pack_DDD/,$(DDD_MODULES)) \
                        $(addprefix pack_AAA/,$(AAA_MODULES)) \
                        $(addprefix pack_CCC/, $(CCC_MODULES))
    
    #All folders containing inc/ subdir
    INCLUDE_MODULES     := $(OTHER_MODULES) \
                        $(addprefix comp_EEE/,$(EEE_MODULES)) \
                        $(addprefix pack_DDD/,$(DDD_MODULES)) \
                        $(addprefix pack_AAA/,$(AAA_DIRS_INC)) \
                        $(addprefix pack_CCC/, $(CCC_MODULES))
    
    #####################################
    
    #WRAPPERS
    ROOT_DIR_WRAPPERS       := $(ROOT_DIR)../WRAPPERS/
    
    LIST_WRAPPERS           := WA WB WC WD
    
    SRC_WRAPPERS            := $(addprefix pack_Wrappers/csc_Wrapper,$(LIST_WRAPPERS))
    
    #DRIVERS
    LIST_DRIVERS            := DA DB DC DD
    DIR_DRIVERS             := $(addprefix pack_Drivers/csc_Driver,$(LIST_DRIVERS))
    
    SRC_DIRS_WRAPPERS       := $(addsuffix /src,$(SRC_WRAPPERS))
    
    INCLUDE_DIRS_WRAPPERS   := $(addsuffix /inc,$(SRC_WRAPPERS)) \
                                $(addsuffix /inc,$(DIR_DRIVERS)) \
                                Common
    
    
    #####################################
    #LIB_1 INCLUDE
    ROOT_DIR_LIB_1          := $(ROOT_DIR)../../ObjetsCompiles/LIB_1/
    INCLUDE_DIRS_LIB_1      := dir1 dir2 dir3
    
    #####################################
    #LIB_2 INCLUDE
    ROOT_DIR_LIB_2      := $(ROOT_DIR)../../ObjetsCompiles/LIB_2/include
    INCLUDE_DIRS_LIB_2  := . dir1 dir2 dir3/subdir dir4
    
    
    #####################################
    #Add "." to find main.cpp
    SRC_DIRS        := $(addsuffix /src,$(SRC_MODULES)) .
    INCLUDE_DIRS_SRC:= $(addsuffix /inc,$(INCLUDE_MODULES)) pack_ZZZ/comp_Without_Inc_Folder
    
    #All include dirs, LIB_1 + LIB_2
    INCLUDE_DIRS    := $(addprefix -I$(ROOT_DIR),$(INCLUDE_DIRS_SRC)) \
                        $(addprefix -I$(ROOT_DIR_LIB_1),$(INCLUDE_DIRS_LIB_1)) \
                        $(addprefix -I$(ROOT_DIR_LIB_2),$(INCLUDE_DIRS_LIB_2))
    
    INCLUDE_DIRS_CC := $(addprefix -I$(ROOT_DIR_WRAPPERS),$(INCLUDE_DIRS_WRAPPERS)) \
                        $(addprefix -I$(ROOT_DIR_LIB_2),$(INCLUDE_DIRS_LIB_2))
    
    #All objects (all .cpp & all .c)
    OBJS            := $(foreach dir,$(SRC_DIRS), \
                        $(patsubst %.cpp,%.o,$(wildcard $(ROOT_DIR)$(dir)/*.cpp))) \
                        $(foreach dirs,$(SRC_DIRS_WRAPPERS), \
                        $(patsubst %.c,%.o,$(wildcard $(ROOT_DIR_WRAPPERS)$(dirs)/*.c)))
    
    #All dependencies (same list as OBJS)
    DEPS            := $(foreach dir,$(SRC_DIRS), \
                        $(patsubst %.cpp,%.d,$(wildcard $(ROOT_DIR)$(dir)/*.cpp))) \
                        $(foreach dirs,$(SRC_DIRS_WRAPPERS), \
                        $(patsubst %.c,%.d,$(wildcard $(ROOT_DIR_WRAPPERS)$(dirs)/*.c)))
    
    #Exclude files from build
    #Win32 socket files + some misc
    EXCLUDED_FILES_LIST     := pack_AAA/comp_BBB/src/SocketWindowsOnLinuxForExample.cpp \
                            pack_BBB/comp_CCC/src/SomeOtherThingForWindows.cpp
    EXCLUDED_FILES_PATH     := $(addprefix $(ROOT_DIR),$(EXCLUDED_FILES_LIST))
    
    #Remove some objects (compilation is done, but no link)
    EXCLUDED_OBJS   := $(patsubst %.cpp,%.o,$(EXCLUDED_FILES_PATH))
    EXCLUDED_DEPS   := $(patsubst %.cpp,%.d,$(EXCLUDED_FILES_PATH))
    
    #Update OBJS & DEPS list with excluded files
    OBJS := $(filter-out $(EXCLUDED_OBJS),$(OBJS))
    DEPS := $(filter-out $(EXCLUDED_DEPS),$(DEPS))
    
    #FLAGS for DEBUG and RELEASE compilation
    CPPFLAGS    := -D__CPPFLAG1__ -D__CPPFLAG2__
    CFLAGS_D    := -O0 -g2 -Wall -c -fmessage-length=0
    CXXFLAGS_D  := -O0 -g2 -Wall -c -fmessage-length=0 -m32 -mcpu=powerpc -Winline
    CFLAGS_R    := -O2 -g0 -Wall -c -fmessage-length=0
    CXXFLAGS_R  := -O2 -g0 -Wall -c -fmessage-length=0 -m32 -mcpu=powerpc -Winline
    
    # L
    LD_PATH     := -L../../path_library_1 -L../../path_library_2
    LD_LIBS     := -lpthread_rt -lROHC -lpthread -lnative -lrtdm -lrt
    MAP         := $(PROG).map
    # -s (to strip)
    LD_FLAGS_D  := -Wl,--wrap,pthread_create -Wl,--wrap,pthread_kill -Wl,-Map,$(MAP)
    LD_FLAGS_R  := -s -Wl,--wrap,pthread_create -Wl,--wrap,pthread_kill -Wl,-Map,$(MAP)
    
    ##################################################
    #TARGETS
    
    default: release
    
    #Debug flags (-00 + -g2)
    debug: CFLAGS       := $(CFLAGS_D)
    debug: CXXFLAGS     := $(CXXFLAGS_D)
    debug: LD_FLAGS     := $(LD_FLAGS_D)
    debug: all
    
    #Release flags (-s + -02 + -g0)
    release: CFLAGS     := $(CFLAGS_R)
    release: CXXFLAGS   := $(CXXFLAGS_R)
    release: LD_FLAGS   := $(LD_FLAGS_R)
    release: all
    
    all: $(PROG)
    
    # Tool invocations
    $(PROG): $(OBJS)
        @echo 'Building target: $@'
        @$(CXX)  $(LD_FLAGS) $(LD_PATH) -o "$(PROG)" $(OBJS) $(LD_LIBS)
        @echo 'Finished building target: $@'
        @echo ' '
    
    # CXX compiler used by most of the code
    %.o: %.cpp
        @echo 'Building file: $<'
        @$(CXX) $(CPPFLAGS) $(INCLUDE_DIRS) $(CXXFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
    
    # CC compiler used by Wrappers only
    %.o: %.c
        @echo 'Building file: $<'
        @$(CC) $(INCLUDE_DIRS_CC) $(CFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<"
    
    # Other Targets
    clean:
        -$(RM) $(OBJS) $(DEPS) $(PROG) $(MAP)
        -@echo ' '
    
    .PHONY: all clean dependents
    .SECONDARY: