1# boilermake: A reusable, but flexible, boilerplate Makefile.
2#
3# Copyright 2008, 2009, 2010 Dan Moulding, Alan T. DeKok
4#
5# This program is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18# Caution: Don't edit this Makefile! Create your own main.mk and other
19#          submakefiles, which will be included by this Makefile.
20#          Only edit this if you need to modify boilermake's behavior (fix
21#          bugs, add features, etc).
22
23# Note: Parameterized "functions" in this makefile that are marked with
24#       "USE WITH EVAL" are only useful in conjuction with eval. This is
25#       because those functions result in a block of Makefile syntax that must
26#       be evaluated after expansion. Since they must be used with eval, most
27#       instances of "$" within them need to be escaped with a second "$" to
28#       accomodate the double expansion that occurs when eval is invoked.
29
30#  Before doing ANYTHING, initialize submodules...if the version of
31#  git is compatible.
32gitv := $(shell git --version | cut -d\  -f 3 | cut -c 1)
33ifeq (1, $(gitv))
34  gitv := $(shell git --version | cut -d\  -f 3)
35  $(error git '$(shell which git)' version '$(gitv)' too old; at least version 2.12 is required)
36endif
37
38ifeq ($(wildcard utility/src/Makefile), )
39  $(info $(shell git submodule update --init utility))
40  $(info $(space))
41endif
42
43# ADD_CLEAN_RULE - Parameterized "function" that adds a new rule and phony
44#   target for cleaning the specified target (removing its build-generated
45#   files).
46#
47#   USE WITH EVAL
48#
49define ADD_CLEAN_RULE
50    clean: clean_${1}
51    .PHONY: clean_${1}
52    clean_${1}:
53	$$(strip rm -f ${TARGET_DIR}/${1} $${${1}_OBJS:%.o=%.[doP]})
54	$${${1}_POSTCLEAN}
55endef
56
57# ADD_OBJECT_RULE - Parameterized "function" that adds a pattern rule for
58#   building object files from source files with the filename extension
59#   specified in the second argument. The first argument must be the name of the
60#   base directory where the object files should reside (such that the portion
61#   of the path after the base directory will match the path to corresponding
62#   source files). The third argument must contain the rules used to compile the
63#   source files into object code form.
64#
65#   USE WITH EVAL
66#
67define ADD_OBJECT_RULE
68${1}/%.o: ${2} utility/src/utility/version.H
69	${3}
70endef
71
72# ADD_TARGET_RULE - Parameterized "function" that adds a new target to the
73#   Makefile. The target may be an executable or a library. The two allowable
74#   types of targets are distinguished based on the name: library targets must
75#   end with the traditional ".a" extension.
76#
77#   USE WITH EVAL
78#
79define ADD_TARGET_RULE
80    ifeq "$$(suffix ${1})" ".a"
81        # Add a target for creating a static library.
82        $${TARGET_DIR}/${1}: $${${1}_OBJS}
83	        @mkdir -p $$(dir $$@)
84	        $$(strip $${AR} $${ARFLAGS} $$@ $${${1}_OBJS})
85	        $${${1}_POSTMAKE}
86    else
87      # Add a target for linking an executable. First, attempt to select the
88      # appropriate front-end to use for linking. This might not choose the
89      # right one (e.g. if linking with a C++ static library, but all other
90      # sources are C sources), so the user makefile is allowed to specify a
91      # linker to be used for each target.
92      ifeq "$$(strip $${${1}_LINKER})" ""
93          # No linker was explicitly specified to be used for this target. If
94          # there are any C++ sources for this target, use the C++ compiler.
95          # For all other targets, default to using the C compiler.
96          ifneq "$$(strip $$(filter $${CXX_SRC_EXTS},$${${1}_SOURCES}))" ""
97              ${1}_LINKER = $${CXX}
98          else
99              ${1}_LINKER = $${CC}
100          endif
101      endif
102
103      $${TARGET_DIR}/${1}: $${${1}_OBJS} $${${1}_PREREQS}
104	      @mkdir -p $$(dir $$@)
105	      $$(strip $${${1}_LINKER} -o $$@ $${LDFLAGS} $${${1}_LDFLAGS} $${${1}_OBJS} $${${1}_LDLIBS} $${LDLIBS})
106	      $${${1}_POSTMAKE}
107  endif
108endef
109
110# CANONICAL_PATH - Given one or more paths, converts the paths to the canonical
111#   form. The canonical form is the path, relative to the project's top-level
112#   directory (the directory from which "make" is run), and without
113#   any "./" or "../" sequences. For paths that are not  located below the
114#   top-level directory, the canonical form is the absolute path (i.e. from
115#   the root of the filesystem) also without "./" or "../" sequences.
116define CANONICAL_PATH
117$(patsubst ${CURDIR}/%,%,$(abspath ${1}))
118endef
119
120# COMPILE_C_CMDS - Commands for compiling C source code.
121define COMPILE_C_CMDS
122	@mkdir -p $(dir $@)
123	$(strip ${CC} -o $@ -c -MD ${CFLAGS} ${SRC_CFLAGS} ${INCDIRS} \
124	    ${SRC_INCDIRS} ${SRC_DEFS} ${DEFS} $<)
125	@cp ${@:%$(suffix $@)=%.d} ${@:%$(suffix $@)=%.P}; \
126	 sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
127	     -e '/^$$/ d' -e 's/$$/ :/' < ${@:%$(suffix $@)=%.d} \
128	     >> ${@:%$(suffix $@)=%.P}; \
129	 rm -f ${@:%$(suffix $@)=%.d}
130endef
131
132# COMPILE_CXX_CMDS - Commands for compiling C++ source code.
133define COMPILE_CXX_CMDS
134	@mkdir -p $(dir $@)
135	$(strip ${CXX} -o $@ -c -MD ${CXXFLAGS} ${SRC_CXXFLAGS} ${INCDIRS} \
136	    ${SRC_INCDIRS} ${SRC_DEFS} ${DEFS} $<)
137	@cp ${@:%$(suffix $@)=%.d} ${@:%$(suffix $@)=%.P}; \
138	 sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
139	     -e '/^$$/ d' -e 's/$$/ :/' < ${@:%$(suffix $@)=%.d} \
140	     >> ${@:%$(suffix $@)=%.P}; \
141	 rm -f ${@:%$(suffix $@)=%.d}
142endef
143
144# INCLUDE_SUBMAKEFILE - Parameterized "function" that includes a new
145#   "submakefile" fragment into the overall Makefile. It also recursively
146#   includes all submakefiles of the specified submakefile fragment.
147#
148#   USE WITH EVAL
149#
150define INCLUDE_SUBMAKEFILE
151    # Initialize all variables that can be defined by a makefile fragment, then
152    # include the specified makefile fragment.
153    TARGET        :=
154    TGT_CFLAGS    :=
155    TGT_CXXFLAGS  :=
156    TGT_DEFS      :=
157    TGT_INCDIRS   :=
158    TGT_LDFLAGS   :=
159    TGT_LDLIBS    :=
160    TGT_LINKER    :=
161    TGT_POSTCLEAN :=
162    TGT_POSTMAKE  :=
163    TGT_PREREQS   :=
164
165    SOURCES       :=
166    SRC_CFLAGS    :=
167    SRC_CXXFLAGS  :=
168    SRC_DEFS      :=
169    SRC_INCDIRS   :=
170
171    SUBMAKEFILES  :=
172
173    # A directory stack is maintained so that the correct paths are used as we
174    # recursively include all submakefiles. Get the makefile's directory and
175    # push it onto the stack.
176    DIR := $(call CANONICAL_PATH,$(dir ${1}))
177    DIR_STACK := $$(call PUSH,$${DIR_STACK},$${DIR})
178
179    include ${1}
180
181    # Initialize internal local variables.
182    OBJS :=
183
184    # Determine which target this makefile's variables apply to. A stack is
185    # used to keep track of which target is the "current" target as we
186    # recursively include other submakefiles.
187    ifneq "$$(strip $${TARGET})" ""
188        # This makefile defined a new target. Target variables defined by this
189        # makefile apply to this new target. Initialize the target's variables.
190
191        ifeq "$$(suffix $${TARGET})" ".a"
192          TGT := $$(addprefix lib/, $$(strip $${TARGET}))
193        else
194          TGT := $$(addprefix bin/, $$(strip $${TARGET}))
195        endif
196        ALL_TGTS += $${TGT}
197        $${TGT}_CFLAGS    := $${TGT_CFLAGS}
198        $${TGT}_CXXFLAGS  := $${TGT_CXXFLAGS}
199        $${TGT}_DEFS      := $${TGT_DEFS}
200        $${TGT}_DEPS      :=
201        TGT_INCDIRS       := $$(call QUALIFY_PATH,$${DIR},$${TGT_INCDIRS})
202        TGT_INCDIRS       := $$(call CANONICAL_PATH,$${TGT_INCDIRS})
203        $${TGT}_INCDIRS   := $${TGT_INCDIRS}
204        $${TGT}_LDFLAGS   := $${TGT_LDFLAGS}
205        $${TGT}_LDLIBS    := $${TGT_LDLIBS}
206        $${TGT}_LINKER    := $${TGT_LINKER}
207        $${TGT}_OBJS      :=
208        $${TGT}_POSTCLEAN := $${TGT_POSTCLEAN}
209        $${TGT}_POSTMAKE  := $${TGT_POSTMAKE}
210        $${TGT}_PREREQS   := $$(addprefix $${TARGET_DIR}/lib/,$${TGT_PREREQS})
211        $${TGT}_SOURCES   :=
212    else
213        # The values defined by this makefile apply to the the "current" target
214        # as determined by which target is at the top of the stack.
215        TGT := $$(strip $$(call PEEK,$${TGT_STACK}))
216        $${TGT}_CFLAGS    += $${TGT_CFLAGS}
217        $${TGT}_CXXFLAGS  += $${TGT_CXXFLAGS}
218        $${TGT}_DEFS      += $${TGT_DEFS}
219        TGT_INCDIRS       := $$(call QUALIFY_PATH,$${DIR},$${TGT_INCDIRS})
220        TGT_INCDIRS       := $$(call CANONICAL_PATH,$${TGT_INCDIRS})
221        $${TGT}_INCDIRS   += $${TGT_INCDIRS}
222        $${TGT}_LDFLAGS   += $${TGT_LDFLAGS}
223        $${TGT}_LDLIBS    += $${TGT_LDLIBS}
224        $${TGT}_POSTCLEAN += $${TGT_POSTCLEAN}
225        $${TGT}_POSTMAKE  += $${TGT_POSTMAKE}
226        $${TGT}_PREREQS   += $${TGT_PREREQS}
227    endif
228
229    # Push the current target onto the target stack.
230    TGT_STACK := $$(call PUSH,$${TGT_STACK},$${TGT})
231
232    ifneq "$$(strip $${SOURCES})" ""
233        # This makefile builds one or more objects from source. Validate the
234        # specified sources against the supported source file types.
235        BAD_SRCS := $$(strip $$(filter-out $${ALL_SRC_EXTS},$${SOURCES}))
236        ifneq "$${BAD_SRCS}" ""
237            $$(error Unsupported source file(s) found in ${1} [$${BAD_SRCS}])
238        endif
239
240        # Qualify and canonicalize paths.
241        SOURCES     := $$(call QUALIFY_PATH,$${DIR},$${SOURCES})
242        SOURCES     := $$(call CANONICAL_PATH,$${SOURCES})
243        SRC_INCDIRS := $$(call QUALIFY_PATH,$${DIR},$${SRC_INCDIRS})
244        SRC_INCDIRS := $$(call CANONICAL_PATH,$${SRC_INCDIRS})
245
246        # Save the list of source files for this target.
247        $${TGT}_SOURCES += $${SOURCES}
248
249        # Convert the source file names to their corresponding object file
250        # names.
251        OBJS := $$(addprefix $${BUILD_DIR}/$$(call CANONICAL_PATH,$${TGT})/,\
252                   $$(addsuffix .o,$$(basename $${SOURCES})))
253
254        # Add the objects to the current target's list of objects, and create
255        # target-specific variables for the objects based on any source
256        # variables that were defined.
257        $${TGT}_OBJS += $${OBJS}
258        $${TGT}_DEPS += $${OBJS:%.o=%.P}
259        $${OBJS}: SRC_CFLAGS   := $${$${TGT}_CFLAGS} $${SRC_CFLAGS}
260        $${OBJS}: SRC_CXXFLAGS := $${$${TGT}_CXXFLAGS} $${SRC_CXXFLAGS}
261        $${OBJS}: SRC_DEFS     := $$(addprefix -D,$${$${TGT}_DEFS} $${SRC_DEFS})
262        $${OBJS}: SRC_INCDIRS  := $$(addprefix -I,\
263                                     $${$${TGT}_INCDIRS} $${SRC_INCDIRS})
264    endif
265
266    ifneq "$$(strip $${SUBMAKEFILES})" ""
267        # This makefile has submakefiles. Recursively include them.
268        $$(foreach MK,$${SUBMAKEFILES},\
269           $$(eval $$(call INCLUDE_SUBMAKEFILE,\
270                      $$(call CANONICAL_PATH,\
271                         $$(call QUALIFY_PATH,$${DIR},$${MK})))))
272    endif
273
274    # Reset the "current" target to it's previous value.
275    TGT_STACK := $$(call POP,$${TGT_STACK})
276    TGT := $$(call PEEK,$${TGT_STACK})
277
278    # Reset the "current" directory to it's previous value.
279    DIR_STACK := $$(call POP,$${DIR_STACK})
280    DIR := $$(call PEEK,$${DIR_STACK})
281endef
282
283
284# MIN - Parameterized "function" that results in the minimum lexical value of
285#   the two values given.
286define MIN
287$(firstword $(sort ${1} ${2}))
288endef
289
290# PEEK - Parameterized "function" that results in the value at the top of the
291#   specified colon-delimited stack.
292define PEEK
293$(lastword $(subst :, ,${1}))
294endef
295
296# POP - Parameterized "function" that pops the top value off of the specified
297#   colon-delimited stack, and results in the new value of the stack. Note that
298#   the popped value cannot be obtained using this function; use peek for that.
299define POP
300${1:%:$(lastword $(subst :, ,${1}))=%}
301endef
302
303# PUSH - Parameterized "function" that pushes a value onto the specified colon-
304#   delimited stack, and results in the new value of the stack.
305define PUSH
306${2:%=${1}:%}
307endef
308
309# QUALIFY_PATH - Given a "root" directory and one or more paths, qualifies the
310#   paths using the "root" directory (i.e. appends the root directory name to
311#   the paths) except for paths that are absolute.
312define QUALIFY_PATH
313$(addprefix ${1}/,$(filter-out /%,${2})) $(filter /%,${2})
314endef
315
316###############################################################################
317#
318# Start of Makefile Evaluation
319#
320###############################################################################
321
322# Older versions of GNU Make lack capabilities needed by boilermake.
323# With older versions, "make" may simply output "nothing to do", likely leading
324# to confusion. To avoid this, check the version of GNU make up-front and
325# inform the user if their version of make doesn't meet the minimum required.
326
327MIN_MAKE_VERSION := 3.81
328MIN_MAKE_VER_MSG := boilermake requires GNU Make ${MIN_MAKE_VERSION} or greater
329ifeq "${MAKE_VERSION}" ""
330    $(info GNU Make not detected)
331    $(error ${MIN_MAKE_VER_MSG})
332endif
333ifneq "${MIN_MAKE_VERSION}" "$(call MIN,${MIN_MAKE_VERSION},${MAKE_VERSION})"
334    $(info This is GNU Make version ${MAKE_VERSION})
335    $(error ${MIN_MAKE_VER_MSG})
336endif
337
338# Define the source file extensions that we know how to handle.
339
340C_SRC_EXTS := %.c
341CXX_SRC_EXTS := %.C %.cc %.cp %.cpp %.CPP %.cxx %.c++
342JAVA_EXTS    := %.jar %.tar
343ALL_SRC_EXTS := ${C_SRC_EXTS} ${CXX_SRC_EXTS} ${JAVA_EXTS}
344
345# Initialize global variables.
346
347ALL_TGTS :=
348DEFS :=
349DIR_STACK :=
350INCDIRS :=
351TGT_STACK :=
352
353# Discover our OS and architecture.  These were previously used to set
354# BUILD_DIR and TARGET_DIR to allow multi-platform builds.  DESTDIR will do
355# that for us too.
356
357OSTYPE      := $(shell echo `uname`)
358OSVERSION   := $(shell echo `uname -r`)
359MACHINETYPE := $(shell echo `uname -m`)
360
361ifeq (${MACHINETYPE}, x86_64)
362  MACHINETYPE = amd64
363endif
364
365ifeq (${MACHINETYPE}, Power Macintosh)
366  MACHINETYPE = ppc
367endif
368
369ifeq (${OSTYPE}, SunOS)
370  MACHINETYPE = ${shell echo `uname -p`}
371  ifeq (${MACHINETYPE}, sparc)
372    ifeq (${shell /usr/bin/isainfo -b}, 64)
373      MACHINETYPE = sparc64
374    else
375      MACHINETYPE = sparc32
376    endif
377  endif
378endif
379
380#  Set paths for building and installing.  If DESTDIR doesn't exist, use the
381#  directory just above us.
382
383ifeq "$(strip ${DESTDIR})" ""
384  BUILD_DIR    := $(realpath ..)/build/obj
385  TARGET_DIR   := $(realpath ..)/build
386else
387  BUILD_DIR    := $(DESTDIR)/$(MODULE)/build/obj
388  TARGET_DIR   := $(DESTDIR)/$(MODULE)/build
389endif
390
391#
392#  Set compiler and flags based on discovered hardware
393#
394#  By default, debug symbols are included in all builds (even optimized).
395#
396#  BUILDOPTIMIZED  will disable debug symbols (leaving it just optimized)
397#  BUILDDEBUG      will disable optimization  (leaving it just with debug symbols)
398#  BUILDSTACKTRACE will enable stack trace on crashes, only works for Linux
399#                  set to 0 on command line to disable (it's enabled by default for Linux)
400#
401#  BUILDPROFILE used to add -pg to LDFLAGS, and remove -D_GLIBCXX_PARALLE from CXXFLAGS and LDFLAGS,
402#  and remove -fomit-frame-pointer from CXXFLAGS.  It added a bunch of complication and wasn't
403#  really used.
404#
405#  BUILDJEMALLOC will enable jemalloc library support.
406#
407
408ifeq ($(origin CXXFLAGS), undefined)
409  ifeq ($(BUILDOPTIMIZED), 1)
410  else
411    CXXFLAGS += -g3
412  endif
413
414  ifeq ($(BUILDDEBUG), 1)
415  else
416    CXXFLAGS += -O4 -funroll-loops -fexpensive-optimizations -finline-functions -fomit-frame-pointer
417  endif
418
419  ifeq ($(BUILDJEMALLOC), 1)
420    CXXFLAGS += -DJEMALLOC -I`jemalloc-config --includedir`
421    LDFLAGS  += -L`jemalloc-config --libdir` -Wl,-rpath,`jemalloc-config --libdir` -ljemalloc `jemalloc-config --libs`
422  endif
423
424  #  Enable some warnings.
425  #     gcc7:  -Wno-format-truncation  - sprintf() into possibly smaller buffer
426  #            -Wno-parentheses
427  CXXFLAGS += -Wall -Wextra -Wformat
428  CXXFLAGS += -Wno-char-subscripts
429  CXXFLAGS += -Wno-sign-compare
430  CXXFLAGS += -Wno-unused-function
431  CXXFLAGS += -Wno-unused-parameter
432  CXXFLAGS += -Wno-unused-variable
433  CXXFLAGS += -Wno-deprecated-declarations
434  CXXFLAGS += -Wno-format-truncation
435  CXXFLAGS += -std=c++11
436else
437  CXXFLAGSUSER := ${CXXFLAGS}
438endif
439
440
441
442
443ifeq (${OSTYPE}, Linux)
444  CC        ?= gcc
445  CXX       ?= g++
446
447  CXXFLAGS  += -pthread -fopenmp -fPIC
448  LDFLAGS   += -pthread -fopenmp -lm
449
450  BUILDSTACKTRACE ?= 1
451endif
452
453
454#  The default MacOS compiler - even as of 10.13 High Sierra - doesn't support OpenMP.
455#  Clang 6.0 installed from MacPorts supports OpenMP, but fails to compile Canu.
456#  So, we require gcc7 (from MacPorts) or gcc8 (from hommebrew).
457#
458#  If from MacPorts:
459#    port install gcc7
460#    port select gcc mp-gcc7
461#
462#  If CC is set to 'cc', the GNU make default, we'll automagically search for other
463#  versions and use those if found, preferring gcc7 over gcc8.
464#
465#  There' definitely a clever way to do this with 'foreach', but my Make is lacking.
466#
467ifeq (${OSTYPE}, Darwin)
468  ifeq ($(CC), cc)
469    CC7    := $(shell echo `which gcc-mp-7`)
470    CXX7   := $(shell echo `which g++-mp-7`)
471
472    ifdef CXX7
473      CC  := $(CC7)
474      CXX := $(CXX7)
475    endif
476  endif
477
478  ifeq ($(CC), cc)
479    CC8    := $(shell echo `which gcc-7`)
480	  CXX8   := $(shell echo `which g++-7`)
481
482    ifdef CXX8
483      CC  := $(CC8)
484      CXX := $(CXX8)
485    endif
486  endif
487
488  ifeq ($(CC), cc)
489    CC8    := $(shell echo `which gcc-8`)
490	  CXX8   := $(shell echo `which g++-8`)
491
492    ifdef CXX8
493      CC  := $(CC8)
494      CXX := $(CXX8)
495    endif
496  endif
497
498  ifneq ($(shell echo `$(CXX) --version 2>&1 | grep -c clang`), 0)
499     CPATH := $(shell echo `which $(CXX)`)
500     CLANG := $(shell echo `$(CXX) --version 2>&1 | grep clang`)
501     space :=
502
503     $(warning )
504     ifeq ($(CXX), $(CPATH))
505       $(warning Compiler '$(CXX)' reports version '$(CLANG)'.)
506     else
507       $(warning Compiler '$(CXX)' at '$(CPATH)' reports version '$(CLANG)'.)
508     endif
509     $(warning )
510     $(warning Canu cannot be compiled with this compiler.  Please install GCC and/or)
511     $(warning specify a non-Clang compiler on the command line, e.g.,)   #  Quite the evil trick to get
512     $(warning $(space)    make CC=/path/to/gcc CXX=/path/to/g++);        #  this line indented!
513     $(warning )
514     $(error unsupported compiler)
515  endif
516
517  CXXFLAGS += -fopenmp -pthread -fPIC -m64 -Wno-format
518  LDFLAGS  += -fopenmp -pthread -lm
519endif
520
521
522ifeq (${OSTYPE}, FreeBSD)
523ifeq (${CANU_BUILD_ENV}, ports)
524
525  # If building in the FreeBSD ports system, use the architecture as defined
526  # there (technically, -p, not -m) and assume compiler and most options
527  # are already defined correctly.
528
529  MACHINETYPE=${ARCH}
530
531  CXXFLAGS  += -pthread -fopenmp -fPIC
532  LDFLAGS   += -pthread -fopenmp
533
534else
535
536  # Ignore the gmake default 'c++' and force g++9.
537	ifeq ($(origin CXX), default)
538    CC    = gcc9
539    CXX   = g++9
540    CCLIB = -rpath /usr/local/lib/gcc9
541  endif
542
543  #  GCC
544  CXXFLAGS  += -I/usr/local/include -pthread -fopenmp -fPIC
545  LDFLAGS   += -L/usr/local/lib     -pthread -fopenmp ${CCLIB} -lm -lexecinfo
546
547  #  CLANG
548  #CXXFLAGS  += -I/usr/local/include -pthread -fPIC
549  #LDFLAGS   += -L/usr/local/lib     -pthread -lm -lexecinfo -lgomp
550
551  #  Google Performance Tools malloc and heapchecker (HEAPCHECK=normal)
552  #CXXFLAGS  +=
553  #LDFLAGS   += -ltcmalloc
554
555  #  Google Performance Tools cpu profiler (CPUPROFILE=/path)
556  #CXXFLAGS  +=
557  #LDFLAGS   += -lprofiler
558
559  #  callgrind
560  #CXXFLAGS  += -g3 -Wa,--gstabs -save-temps
561endif
562endif
563
564
565ifneq (,$(findstring CYGWIN, ${OSTYPE}))
566  CC        ?= gcc
567  CXX       ?= g++
568
569  CXXFLAGS  := -fopenmp -pthread
570  LDFLAGS   := -fopenmp -pthread -lm
571endif
572
573
574#  Stack tracing support.  Wow, what a pain.  Only Linux is supported.  This is just documentation,
575#  don't actually enable any of this stuff!
576#
577#  backward-cpp looks very nice, only a single header file.  But it needs libberty (-liberty) and
578#  libbfd (-lbfd).  The former should be installed with gcc, and the latter is in elfutils.  On
579#  three out of our three development machines, it fails for various reasons.
580#
581#  libunwind is pretty basic.
582#
583#  libbacktrace works (on Linux) and is simple enough to include in our tree.
584#
585#  None of these give any useful information on BSDs (which includes OS X aka macOS).
586#
587#
588#  Backtraces with libunwind.  Not informative on FreeBSD.
589#CXXFLAGS  += -DLIBUNWIND
590#LDFLAGS   +=
591#LDLIBS    += -lunwind -lunwind-x86_64
592#
593#
594#  Backtraces with libbacktrace.  FreeBSD works, but trace is empty.
595#BUILDSTACK = 1
596#CXXFLAGS  += -DLIBBACKTRACE
597#LDFLAGS   +=
598#LDLIBS    +=
599#
600#
601#  Backtraces with backward-cpp.
602#
603#  Stack walking:
604#    BACKWARD_HAS_UNWIND    - used by gcc/clang for exception handling
605#    BACKWARD_HAS_BACKTRACE - part of glib, not as accurate, more portable
606#
607#  Stack interpretation:
608#    BACKWARE_HAS_DW               - most information, libdw, (elfutils or libdwarf)
609#    BACKWARD_HAS_BFD              - some information, libbfd
610#    BACKWARD_HAS_BACKTRACE_SYMBOL - minimal information (file and function), portable
611#
612#  helix   fails with: cannot find -liberty
613#  gryphon fails with: cannot find -lbfd
614#  freebsd can't install a working elfutils, needed for libdw"
615#    In file included from AS_UTL/AS_UTL_stackTrace.C:183:0:
616#    AS_UTL/backward.hpp:241:30: fatal error: elfutils/libdw.h: No such file or directory
617#     #  include <elfutils/libdw.h>
618#
619#CXXFLAGS  += -DBACKWARDCPP -DBACKWARD_HAS_BFD
620#LDFLAGS   +=
621#LDLIBS    += -lbfd -liberty -ldl -lz
622#
623#  Needs libdw, elfutils
624#CXXFLAGS  += -DBACKWARDCPP -DBACKWARD_HAS_DW
625#LDFLAGS   +=
626#LDLIBS    += -ldl -lz
627#
628#  Generates nothing useful, no function names, just binary names
629#CXXFLAGS  += -DBACKWARDCPP
630#LDFLAGS   +=
631#LDLIBS    += -ldl -lz
632#
633#
634#  No backtrace support.
635#CXXFLAGS   += -DNOBACKTRACE
636
637#  But, if we we have an old GCC, stack tracing support isn't there.
638#  The second test is because gcc7 (and only gcc7) reports '7' for -dumpversion.
639
640GXX_45 := $(shell expr `${CXX} -dumpversion     | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40500)
641GXX_VV := $(shell ${CXX} -dumpversion)
642
643ifeq (${GXX_VV}, 7)
644GXX_45 := $(shell expr `${CXX} -dumpfullversion | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/'` \>= 40500)
645GXX_VV := $(shell ${CXX} -dumpfullversion)
646endif
647
648ifeq (${BUILDSTACKTRACE}, 1)
649ifeq (${GXX_45}, 0)
650$(info WARNING:)
651$(info WARNING: ${CXX} ${GXX_VV} detected, disabling stack trace support.  Please upgrade to GCC 4.7 or higher.)
652$(info WARNING:)
653BUILDSTACKTRACE = 0
654endif
655endif
656
657ifeq (${BUILDSTACKTRACE}, 1)
658CXXFLAGS  += -DLIBBACKTRACE
659else
660CXXFLAGS  += -DNOBACKTRACE
661endif
662
663
664# Include the main user-supplied submakefile. This also recursively includes
665# all other user-supplied submakefiles.
666$(eval $(call INCLUDE_SUBMAKEFILE,main.mk))
667
668# Perform post-processing on global variables as needed.
669DEFS := $(addprefix -D,${DEFS})
670INCDIRS := $(addprefix -I,$(call CANONICAL_PATH,${INCDIRS}))
671
672# Define the "all" target (which simply builds all user-defined targets) as the
673# default goal.
674.PHONY: all
675all: $(addprefix ${TARGET_DIR}/,${ALL_TGTS}) \
676     ${TARGET_DIR}/share/seqrequester/ultra-long-nanopore \
677     ${TARGET_DIR}/share/seqrequester/pacbio \
678     ${TARGET_DIR}/share/seqrequester/pacbio-hifi
679	@echo ""
680	@echo "Success!"
681	@echo "seqrequester installed in ${TARGET_DIR}/bin/seqrequester"
682	@echo ""
683
684# Add a new target rule for each user-defined target.
685$(foreach TGT,${ALL_TGTS},\
686  $(eval $(call ADD_TARGET_RULE,${TGT})))
687
688# Add pattern rule(s) for creating compiled object code from C source.
689$(foreach TGT,${ALL_TGTS},\
690  $(foreach EXT,${C_SRC_EXTS},\
691    $(eval $(call ADD_OBJECT_RULE,${BUILD_DIR}/$(call CANONICAL_PATH,${TGT}),\
692             ${EXT},$${COMPILE_C_CMDS}))))
693
694# Add pattern rule(s) for creating compiled object code from C++ source.
695$(foreach TGT,${ALL_TGTS},\
696  $(foreach EXT,${CXX_SRC_EXTS},\
697    $(eval $(call ADD_OBJECT_RULE,${BUILD_DIR}/$(call CANONICAL_PATH,${TGT}),\
698             ${EXT},$${COMPILE_CXX_CMDS}))))
699
700# Add "clean" rules to remove all build-generated files.
701.PHONY: clean
702$(foreach TGT,${ALL_TGTS},\
703  $(eval $(call ADD_CLEAN_RULE,${TGT})))
704
705# Include generated rules that define additional (header) dependencies.
706$(foreach TGT,${ALL_TGTS},\
707  $(eval -include ${${TGT}_DEPS}))
708
709
710${TARGET_DIR}/share/seqrequester/ultra-long-nanopore: ../share/ultra-long-nanopore
711	cp -pf ../share/ultra-long-nanopore ${TARGET_DIR}/share/seqrequester/ultra-long-nanopore
712
713${TARGET_DIR}/share/seqrequester/pacbio: ../share/pacbio
714	cp -pf ../share/pacbio ${TARGET_DIR}/share/seqrequester/pacbio
715
716${TARGET_DIR}/share/seqrequester/pacbio-hifi: ../share/pacbio-hifi
717	cp -pf ../share/pacbio-hifi ${TARGET_DIR}/share/seqrequester/pacbio-hifi
718
719
720#  Makefile processed.  Regenerate the version number file, make some
721#  directories, and report that we're starting the build.
722
723$(eval $(shell ../scripts/version_update.pl $(MODULE) utility/src/utility/version.H))
724
725$(shell mkdir -p ${TARGET_DIR}/share/seqrequester)
726$(shell mkdir -p ${TARGET_DIR}/bin)
727
728$(info For '${OSTYPE}' '${OSVERSION}' as '${MACHINETYPE}' into '${TARGET_DIR}/{bin,obj}'.)
729$(info Using '$(shell which ${CXX})' version '${GXX_VV}'.)
730ifneq ($(origin CXXFLAGSUSER), undefined)
731$(info Using user-supplied CXXFLAGS '${CXXFLAGSUSER}'.)
732endif
733$(info )
734