Here's the Makefile I added to the documentation (currently in the review, so I'll post it here):
Main functions
- Automatically detect
C sources in specified folders - Multiple Source Folders
- Multiple Target Folders for Object and Dependency Files
- Automatically create rules for each target folder
- Create destination folders when they do not exist
- Managing Dependencies with
gcc : Create Only What You Need - Works on
Unix and DOS systems - Written for
GNU Make
How to use this makefile
To adapt this Makefile to your project, you must:
- Change the
TARGET variable to your target name - Change the name of the
Sources and Build folders to SOURCEDIR and BUILDDIR - Change the detail level of the Makefile in the Makefile itself or in the make call (
make all VERBOSE=FALSE ) - Change the folder name in
DIRS according to your sources and create folders - Change the compiler and flags as needed
In this Makefile, Folder0 , Folder1 and Folder2 equivalent to your FolderA , FolderB and FolderC .
Please note that I did not have the opportunity to test it on a Unix system at the moment, but it works correctly on Windows.
Explanation of several complex parts:
Ignoring Windows mkdir Errors
ERRIGNORE = 2>NUL || true
This has two effects: First, 2>NUL - redirect the error output to NUL, since it is not included in the console.
Second, || true || true prevents the error level from rising. This is non-Makefile-related Windows material here because the Windows mkdir command raises errors if we try to create an existing folder, while we don't care if it really exists. A common solution is to use an if not exist structure, but not UNIX compatible, so even if it's complicated, I find my solution more understandable.
Creating an OBJS containing all the object files with their correct path
OBJS := $(subst $(SOURCEDIR),$(BUILDDIR),$(SOURCES:.c=.o))
Here we want OBJS to contain all the object files with their paths, and we already have SOURCES that contain all the source files with their paths. $(SOURCES:.c=.o) changes * .c to * .o for all sources, but the path is still one of the sources. $(subst $(SOURCEDIR),$(BUILDDIR), ...) will simply subtract the entire source path using the build path, so we will finally get a variable containing .o files with their paths.
Work with path separators in the style of Windows and Unix
SEP=\\ SEP = / PSEP = $(strip $(SEP))
It only exists to allow the Makefile to work on Unix and Windows, as Windows uses the backslash in the path, while everyone else uses slashes.
SEP=\\ Here, a double backslash is used to remove the backslash character, which make usually refers to the ignore newline character to allow writing on multiple lines.
PSEP = $(strip $(SEP)) This will remove the char space of the SEP variable, which was added automatically.
Automatically generate rules for each target folder
define generateRules $(1)/%.o: %.c @echo Building $$@ $(HIDE)$(CC) -c $$(INCLUDES) -o $$(subst /,$$(PSEP), $$@ ) $$(subst /,$$(PSEP),$$<) -MMD endef
This may be the trick that is most related to your usecase. This is a rule template that can be generated using $(eval $(call generateRules, param)) , where param is what you can find in the template as $(1) . This will basically populate the Makefile with these rules for each target folder:
path/to/target/%.o: %.c @echo Building $@ $(HIDE)$(CC) -c $(INCLUDES) -o $(subst /,$(PSEP), $@ ) $(subst /,$(PSEP),$<) -MMD