1
\$\begingroup\$

I have written a non-recursive Makefile that almost does the job I want. Apart from not full-fillng all my goals it doesn't look good. There should ways to solve the issues and also to improve/clean the makefile itself.

My setup

  • Several thousands of src files should each be built into individual programs.
  • The src files are grouped in several directories. Think 10 dirs with 400 files each.
  • Each file has a unique name.
  • Each of the programs are dependent on the same set of common files.

My goals

  1. Non-recursive
  2. Each program shall be gzipped
  3. The build of each program shall use a separate object directory
  4. The output of each program build, including the build commands themselves (CC, LD), should be captured in a log file. The logfile shall be unique for each build.
  5. As the build of each program uses several rules via dependencies, the logfile name has to be communicated from the top rule to the dependencies.
  6. All programs should be built in one go. Failing to build one program should not stop the build of the other programs.
  7. The logfile of each build should be placed in a “passed” or “failed” dir depending on build success.

My problems
(using the numbers above) Refer to the Makefile below when needed.

  1. I calculated the name of the dependedcy in the rule '$(BINDIR)/%.gz:' with mix of secondary expansion ($$*) and %. Is this correct?
  2. I only capture the output of the commands, not the command themselves.
  3. I don't decide on the name of the log file in the top rule '$(BINDIR)/%.gz:' and communicate it to the dependencies. I calculate it in each rule, knowing what the directory structure looks like. This is prone to error. I would like to do it with a pattern-specific macro in the top rule. This way It is only calculated once for the build of one program.
  4. I use 'MAKEFLAGS += --keep-going'. It will let the top rule '$(BINDIR)/%.gz:' try and link the program even if a compilation failed. I would like to keep that from happening for the build of this program, while keep building the other programs.
  5. Here I don't have a solution.

Makefile

#############################################
# TOOLS 
MKDIR := mkdir -p
ifeq ($(VERBOSE),yes)
   LOG := |& tee -a
else
   LOG := &>>
endif 
LOG0 := |& tee -a
GZIP := gzip -c
#############################################

MAKEFLAGS += --keep-going -j8

.SUFFIXES:
.SECONDARY:
.SECONDEXPANSION:

SRCDIR := source
OBJDIR_ROOT := obj
BINDIR   := bin

SRCDIRS := $(wildcard $(SRCDIR)/*.dir)
SRCFILES := $(foreach dir,$(SRCDIRS),$(wildcard $(dir)/*.cpp))
PROGS := $(foreach srcfile,$(SRCFILES),$(BINDIR)/$(basename $(notdir $(srcfile))).gz)


# Common files
COMMON_SRCDIR := common/src
COMMON_OBJDIR := $(OBJDIR_ROOT)/common
COMMON_OBJECTS := $(COMMON_OBJDIR)/common1.o
COMMON_OBJECTS += $(COMMON_OBJDIR)/common2.o

vpath %.cpp $(SRCDIRS)
vpath %.c $(COMMON_SRCDIR)

.PHONY: progs

progs: $(PROGS)

%.o: $$(notdir $$*).cpp
    @$(MKDIR) $(dir $@)
    $(eval RES_FILE := $(dir $@)/$(notdir $*).res)
    @echo Compiling $< $(LOG0) $(RES_FILE)
    @$(CXX) $(CXXFLAGS) $(CCFLAGS) -o $@ $< $(LOG) $(RES_FILE)

%.o: $$(notdir $$*).c
    @$(MKDIR) $(dir $@)
    $(eval RES_FILE := $(dir $@)/$(notdir $*).res)
    @echo Compiling $< $(LOG0) $(RES_FILES)
    @$(CC) $(CCFLAGS) -o $@ $< $(LOG) $(RES_FILE)

$(BINDIR)/%.gz: $(OBJDIR_ROOT)/$(notdir $$*)/%.o $(COMMON_OBJECTS)
    @$(MKDIR) $(dir $@)
    $(eval OBJDIR=$(OBJDIR_ROOT)/$*)
    $(eval EXENAME=$*)
    $(eval ELFFILE=$(OBJDIR)/$(EXENAME).elf)
    $(eval RES_FILE=$(OBJDIR)/$*.res)

    @echo "--- Linking $@" $(LOG0) $(RES_FILE)
    @$(LD) $(LDRFLAGS) $^ -o $(ELFFILE) $(LOG) $(RES_FILE)

    @echo "--- gzipping $(ELFFILE)" $(LOG0) $(RES_FILE)
    @$(GZIP) $(ELFFILE) >> $@
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.