2
\$\begingroup\$

I had a Makefile but it doesn't meet the "industry-standard expectation". That was feedback from my client. The old Makefile was rejected. Thus, I'm making a new one.

Here is the repository for my project.

My old Makefile:

# Boost C++ library
BOOST = /usr/local/include/boost_1_64_0

# Linear-algebra library
EIGEN = /usr/local/Cellar/eigen/3.2.8/include/eigen3

# HTSLIB library for BAM files
HTSLIB = /Users/tedwong/Sources/QA/htslib

# Where the header are
INCLUDE = src

EXEC         = anaquin
SOURCES      = $(wildcard src/*.cpp src/tools/*.cpp src/analyzers/*.cpp src/RnaQuin/*.cpp src/VarQuin/*.cpp src/MetaQuin/*.cpp src/data/*.cpp src/parsers/*.cpp src/writers/*.cpp src/stats/*.cpp src/cufflinks/*.cpp)
OBJECTS      = $(SOURCES:.cpp=.o)
OBJECTS_TEST = $(SOURCES_TEST:.cpp=.o)
SOURCES_LIB  = $(wildcard src/htslib/cram/*.c)
OBJECTS_LIB  = $(SOURCES_LIB:.c=.o)

$(EXEC): $(OBJECTS) $(OBJECTS_TEST) $(OBJECTS_LIB)
    g++ $(OBJECTS) $(OBJECTS_TEST) $(OBJECTS_LIB) -DBACKWARD_HAS_BFD -g -lpthread -lz -lhts -L $(HTSLIB) -o $(EXEC)

%.o: %.c
    gcc -g -c -DBACKWARD_HAS_BFD -I src/htslib -I $(INCLUDE) -I $(EIGEN) -I ${BOOST} $< -o $@

%.o: %.cpp
    g++ -g -DK_HACK -DBACKWARD_HAS_BFD -c -std=c++11 -I src/htslib -I src/stats -I $(INCLUDE) -I $(EIGEN) -I ${BOOST} $< -o $@

clean:
    rm -f $(EXEC) $(OBJECTS) $(OBJECTS_TEST)

My new Makefile:

#
# Please modify only BOOST, EIGEN and HTSLIB. You should be able to leave all other options intact. C++ compiler with C++11 support is mandatory.
#

# Boost C++ library
BOOST = /usr/local/include/boost_1_64_0

# Linear-algebra library
EIGEN = /usr/local/Cellar/eigen/3.2.8/include/eigen3

# HTSLIB library for reading BAM files
HTSLIB = /Users/tedwong/Sources/QA/htslib

CC     = g++
CFLAGS = -g -O2
CPPFLAGS = -c -std=c++11
DFLAGS = 
#DFLAGS = -DBACKWARD_HAS_BFD # https://github.com/bombela/backward-cpp
LIBS   = -lpthread -lz -lhts

# Where the header are (no need to modify this)
INCLUDE = src

EXEC         = anaquin
SOURCES      = $(wildcard src/*.cpp src/tools/*.cpp src/analyzers/*.cpp src/RnaQuin/*.cpp src/VarQuin/*.cpp src/MetaQuin/*.cpp src/data/*.cpp src/parsers/*.cpp src/writers/*.cpp src/stats/*.cpp src/cufflinks/*.cpp)
OBJECTS      = $(SOURCES:.cpp=.o)
OBJECTS_TEST = $(SOURCES_TEST:.cpp=.o)
SOURCES_LIB  = $(wildcard src/htslib/cram/*.c)
OBJECTS_LIB  = $(SOURCES_LIB:.c=.o)

$(EXEC): $(OBJECTS) $(OBJECTS_TEST) $(OBJECTS_LIB)
    $(CC) $(OBJECTS) $(OBJECTS_TEST) $(OBJECTS_LIB) $(CFLAGS) $(DFLAGS) $(LIBS) -L $(HTSLIB) -o $(EXEC)

%.o: %.c
    $(CC) $(CFLAGS) -c $(DFLAGS) -I $(INCLUDE) -I $(EIGEN) -I ${BOOST} $< -o $@

%.o: %.cpp
    $(CC) $(CFLAGS) $(DFLAGS) $(CPPFLAGS) -I $(HTSLIB) -I src/stats -I $(INCLUDE) -I $(EIGEN) -I ${BOOST} $< -o $@

clean:
    rm -f $(EXEC) $(OBJECTS) $(OBJECTS_TEST)
\$\endgroup\$
  • \$\begingroup\$ Why did you write CC = g++, when the original Makefile uses gcc to compile C code? \$\endgroup\$ – Toby Speight Oct 27 '17 at 8:51
6
\$\begingroup\$

Couple of things you do that don't match standards.

CXX is usually the C++ compiler
CC  is usually the C   compiler.


CXXFLAGS  are the flags that are applied to the C++ compiler.
CPPFLAGS  are the flags that are applied for the pre-processor.
          This usually means passed to both C and C++ compiler.

CFLAGS    are the flags passed to the C compiler.

LDDFLAGS  are the flags passed to the linker.

Why are you building the tests into your main executable? Should the test application be generated as a seprate application that includes the normal objects (apart from main) and the test objects.

Why do you have libs outside your lib variable?

$(LIBS) -L $(HTSLIB)

You should have a line earlier in your make file like:

# This adds more libs to the current set of libs.
LIBS    += -L $(HTSLIB)

I am confused why you are including -I ${BOOST} for the C compiler but not the C++ compiler. I did not think there was anything in the boost that could be used by C (I could be wrong but seems strange).

The default rule for C/C++/Linking are:

$(CC)  $(CPPFLAGS) $(CFLAGS) -c
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c
$(CC)  $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)

Unless you need to change these I would not. This means adding values to the existing variables.

Something like this (untested):

# Addition Packages.
SRC_PACKAGES = BOOST EIGEN
LIB_PACKAGES = HTSLIB

# Boost C++ library
ROOT_BOOST▸ = /usr/local/include/boost_1_64_0

# Linear-algebra library
ROOT_EIGEN = /usr/local/Cellar/eigen/3.2.8/include/eigen3

# HTSLIB library for reading BAM files
ROOT_HTSLIB = /Users/tedwong/Sources/QA/htslib

#
# Turn on BFD by compiling with
# make -DHASBFD=1
DFLAGS_1▸   = -DBACKWARD_HAS_BFD # https://github.com/bombela/backward-cpp
DFLAGS▸ ▸   = $(DFLAGS_$(HASBFD))

EXTRA_INCLUDE_DIR▸  = $(foreach loop, $(SRC_PACKAGES) $(LIB_PACKAGES), -I$(ROOT_$(loop)))
EXTRA_LIB_DIR▸  ▸   = $(foreach loop, $(LIB_PACKAGES),                 -L$(ROOT_$(loop)))

# Compiler
CXX▸▸   ▸   = g++ 
CC▸ ▸   ▸   = $(CXX)
CPPFLAGS▸   += -g -O2 $(EXTRAFLAGS) $(DFLAGS) -Isrc -Isrc/stats
CFLAGS▸ ▸   +=
CXXFLAGS▸   += -std=c++11

# Linker
LDFLAGS▸▸   += $(EXTRA_LIB_DIR)
LDLIBS▸ ▸   += -lpthread -lz -lhts

# Application
SRC_DIR▸▸   = src src/tools src/analyzers src/RnaQuin src/VarQuin src/MetaQuin src/data src/parsers src/writers src/stats src/cufflinks

EXEC        = anaquin
SOURCES     = $(wildcard $(foreach loop, $(SRC_DIR), $(loop)/*.cpp))
OBJECTS     = $(patsubst $(SOURCE), %.cpp, %.o)

$(EXEC): $(OBJECTS)

.PHONEY: clean
clean:
    $(RM) $(EXEC) $(OBJECTS) $(OBJECTS_TEST)
\$\endgroup\$
  • \$\begingroup\$ Great answer - you've covered most of what I wanted to say. May be worth mentioning how to get (GNU) Make to show you its built-in rules (i.e. make --print-data-base -f /dev/null). That can be as useful as reading the manual, for determining which of the standard variables are relevant to a rule. I had hoped that proper installations of Boost and Eigen would include pkg-config entries, to help us get the right compilation flags, but it seems they don't. :-( \$\endgroup\$ – Toby Speight Oct 27 '17 at 8:28
  • \$\begingroup\$ You missed the important pseudo-targets .DELETE_ON_ERROR: and .PHONY: clean; it's probably also more idiomatic to use $(RM) rather than rm -f. \$\endgroup\$ – Toby Speight Oct 27 '17 at 8:33
  • \$\begingroup\$ DYM CC = gcc? See my comment to the question. \$\endgroup\$ – Toby Speight Oct 27 '17 at 8:42

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.