make it

Since i decided to begin a C/C++ project, i thought that i must firstly prepare a development environment for my own convenience. So i began to dig about make tool for building an environment for myself. The most important feature i wish to implement was a proper directory structure. After hours reading GNU make manual, i found myself writing one that resolves header and source dependency between object files under a directory structure.

Here i share well parametrized and documented simplistic make file that supplies all my needs. The directory structure i use is:

./src
./src/greeter.cpp
./src/printer.cpp
./src/main.cpp
./bin
./makefile
./obj
./inc
./inc/printer.h
./inc/greeter.h

Since i’m not an make tool expert, please feel free to share if there is an absurdity or if you want extend it somehow

makefile:

# ------------------------------------------------------------------------------
# Copyright [2008] [Kadir PEKEL]
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# 	http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ------------------------------------------------------------------------------

# ------------------------------------------------------------------------------
# This simple GNU make file automates your build processes with simple
# dependency resolution under a DIRECTORY STRUCTURE.
# ------------------------------------------------------------------------------

# ------------------------------------------------------------------------------
# Name your own project
# ------------------------------------------------------------------------------

PROJECT = testProject

# ------------------------------------------------------------------------------
# Compiler parameters
# ------------------------------------------------------------------------------

CC = g++
CFLAGS = -Wall -g

# ------------------------------------------------------------------------------
# Directory structure
# ------------------------------------------------------------------------------

SRC_DIR = src
OUT_DIR = bin
OBJ_DIR = obj
INC_DIR = inc

# ------------------------------------------------------------------------------
# Source file sufix
# ------------------------------------------------------------------------------

SUFFIX = .cpp

# ------------------------------------------------------------------------------
# You shouldn't modify below unless you do know what you are doing.
# -
# The thing that is going on here is that any source file under the source
# directory is compiled into its own object file under the objects directory.
# Dependency declaration of the object file to its corresponding source file
# is done automatically. Also, if your source file has got a header file with
# the same name in the include directory, it's also declared as a dependency
# for the related object file.
# ------------------------------------------------------------------------------

ALL_CFLAGS = -I. -I./$(INC_DIR)
OUTPUT = $(OUT_DIR)/$(PROJECT)

SRC_FILES = $(wildcard $(SRC_DIR)/*$(SUFFIX))

OBJ_FILES = $(patsubst $(SRC_DIR)/%$(SUFFIX), $(OBJ_DIR)/%.o, $(SRC_FILES))

INC_FILES = $(wildcard $(INC_DIR)/*.h)
INC_SRC_FILES = $(patsubst $(INC_DIR)/%.h, $(SRC_DIR)/%$(SUFFIX), $(INC_FILES))
INC_SRC_OBJ_FILES = $(patsubst $(SRC_DIR)/%$(SUFFIX), $(OBJ_DIR)/%.o, \
							$(INC_SRC_FILES))

_main: $(OBJ_FILES)
	$(CC) $(CFLAGS) $(ALL_CFLAGS) $(OBJ_FILES) -o $(OUTPUT)

$(INC_SRC_OBJ_FILES): $(OBJ_DIR)/%.o: $(INC_DIR)/%.h

$(OBJ_DIR)/%.o: $(SRC_DIR)/%$(SUFFIX)
	$(CC) $(CFLAGS) $(ALL_CFLAGS) -c $< -o $@

# ------------------------------------------------------------------------------
# Default target that does the work when you type 'make' without pointing to
# any target
# ------------------------------------------------------------------------------

.DEFAULT : all
all: _main

# ------------------------------------------------------------------------------
# Put your cross dependiences here
# ------------------------------------------------------------------------------

$(OBJ_DIR)/greeter.o: $(INC_DIR)/printer.h
$(OBJ_DIR)/main.o: $(INC_DIR)/greeter.h

# ------------------------------------------------------------------------------
# Here you can write down custom targets and if you wish, you can make the
# default target dependent to yours. For ex: 'all: _main <your_target>'
# ------------------------------------------------------------------------------

.PHONY : clean
clean:
	-rm $(OBJ_DIR)/* $(OUT_DIR)/*

your_target:
	@echo "your target"