SRC_DIR = @SRC_DIR@
CONFIG_HASH = @CONFIG_HASH@
PACKAGE = @PACKAGE@
tmwa = ${PACKAGE}
PACKAGE_NAME = @PACKAGE_NAME@
PREFIX = @PREFIX@
EPREFIX = @EXEC_PREFIX@
# EPREFIX = @EPREFIX@
BINDIR = @BINDIR@
SBINDIR = @SBINDIR@
LIBEXECDIR = @LIBEXECDIR@
SYSCONFDIR = @SYSCONFDIR@
PACKAGESYSCONFDIR := ${SYSCONFDIR}/${PACKAGE}
SHAREDSTATEDIR = @SHAREDSTATEDIR@
LOCALSTATEDIR = @LOCALSTATEDIR@
PACKAGELOCALSTATEDIR := ${LOCALSTATEDIR}/${PACKAGE}
LIBDIR = @LIBDIR@
INCLUDEDIR = @INCLUDEDIR@
PACKAGEINCLUDEDIR := ${INCLUDEDIR}/${PACKAGE}
OLDINCLUDEDIR = @OLDINCLUDEDIR@
DATAROOTDIR = @DATAROOTDIR@
DATADIR = @DATADIR@
PACKAGEDATADIR = @PACKAGEDATADIR@
INFODIR = @INFODIR@
LOCALEDIR = @LOCALEDIR@
MANDIR = @MANDIR@
DOCDIR = @DOCDIR@
HTMLDIR = @HTMLDIR@
DVIDIR = @DVIDIR@
PDFDIR = @PDFDIR@
PSDIR = @PSDIR@
DEBUGDIR = @DEBUGDIR@
BUILD = @BUILD@
HOST = @HOST@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LDLIBS = @LIBS@
# LDLIBS = @LDLIBS@
CXX = @CXX@
CXXFLAGS = @CXXFLAGS@
GTEST_DIR = @GTEST_DIR@
GDB = @GDB@
ENABLE_WARNINGS = @ENABLE_WARNINGS@
ENABLE_ABI = @ENABLE_ABI@
ENABLE_CYGWIN_HACKS = @ENABLE_CYGWIN_HACKS@
ENABLE_DEBUG = @ENABLE_DEBUG@
ENABLE_RPATH = @ENABLE_RPATH@
ENABLE_SHARED = @ENABLE_SHARED@
TESTER =
TEST_ARGS =
## real.make - The One Makefile that builds them all.
##
## Copyright © 2012-2014 Ben Longbons <b.r.longbons@gmail.com>
##
## This file is part of The Mana World (Athena server)
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <http://www.gnu.org/licenses/>.
# With the One Makefile, you never have to remember to update the list of
# objects you need to link your programs. It is designed to behave (almost)
# exactly the way you expect a Makefile to act - which cannot be said of
# automake, cmake, or qmake.
#
# The One Makefile lives under the name 'real.make', because it is
# reponsible for doing all the actual building, but it is not the file
# that the user actually calls (using make) directly. The reason for this
# is that the One Makefile requires a certain environment that it cannot
# arrange for on its own.
#
# Specifically:
# The -r and -R flags must be passed.
# A list of variables must be included, but regenerating Makefile from
# Makefile.in is time-consuming, so real.make actually *includes* the
# file that called it.
#
# For an example of how to do this safely, look at the Makefile.in shipped
# by TMWA. Of course, you could use any other mechanism to generate a
# Makefile, as long as it supplies the appropriate list of variables.
# TODO:
# 1. Implement support for static libraries
# This should be trivial.
# 2. Implement support for shared libraries
# This requires building two different .o files and such.
# 3. Implement support for mixed C and C++ source trees
# This just requires writing more patsubst in various places
# At that point, they should *probably* be refactored out into functions.
# However, it would be hard to allow linking some binaries as pure C.
# Unless maybe we should use .c.o and .cpp.o ?
# 4. See if something can be done about all the mkdirs.
# 5. Remove the few (obvious) bits that are hard-coded for TMWA.
# 6. Handle testing better. I'm guessing I should actually compile just
# one foo_test.cpp file into each executable test ...
# 7. Refactor into several files after all. We need extensibility!
#
# IWBNMI:
# 1. Add 'make check' and 'make installcheck'.
# 2. 'make distclean' should remove "anything that ./configure created".
# 3. 'make dist' should be implemented. Git only or not?
# 4. 'make install' should install documentation.
# 5. Split 'make install-exec' and 'make install-data'. Beware etc and var!
# 6. '--program-prefix' and '--program-suffix' (easy). What about sed?
# 7. Support DESTDIR during 'make install' (URGENT).
# 8. 'make distcheck' using the 'make dist' tarball?
# 9. Add rules for gettext.
# 10. Support per-target build flags? (requires renaming)
ifeq ($(findstring s,$(firstword ${MAKEFLAGS})),)
ifndef MAKE_RESTARTS
# TODO: should I write this in tengwar?
# The major problem is that it's usually encoded in the PUA
# and thus requires a font specification.
# There *is* a formal request and tentative allocation in the SMP,
# but it has been languishing for 15 years.
# TODO: regardless of the preceding, look up the words for 'build' and 'link'.
# (Does there exist a word that could mean "makefile"?
# Maybe something like 'instructional scroll')
# Note: the space is necessary
$(info )
$(info Welcome to the One Makefile)
$(info Copyright 2012-2014 Ben Longbons)
$(info )
$(info One Makefile to build them all,)
$(info One Makefile to find them,)
$(info One Makefile to bring them all)
$(info and in the darkness link them.)
$(info )
else
$(info The Road goes ever on and on ...)
endif
endif
include ${SRC_DIR}/version.make
ifeq (${ENABLE_SHARED},yes)
LIB_SUFFIX_FAKE := so
LIB_SUFFIX_SHORT := ${SO_SHORT}
LIB_SUFFIX_LONG := ${SO_LONG}
else
LIB_SUFFIX_FAKE := a
LIB_SUFFIX_SHORT := a
LIB_SUFFIX_LONG := a
endif
c = @colorize 6: 2:$< 3:$@ :
ifneq '$c' ''
l = @colorize 6: $(patsubst %,2:%,$^) 3:$@ :
endif
.SUFFIXES:
# make 3.81 doesn't support 'undefine' and Debian hasn't shipped it yet
# even though all the related bugs have already been fixed.
$(foreach var,$(filter-out .% MAKE% SUFFIXES,${.VARIABLES}),$(if $(filter default,$(origin ${var})),$(eval ${var} =)))
.SECONDARY:
export PATH:=$(realpath ${SRC_DIR}/tools):${PATH}
# bash is needed for 'set -o pipefail' below - I have had real bugs there!
# It's just not worth the bother to see if another shell works when it
# needs to *and* fails when it needs to. Just use bash.
SHELL=bash
# need to generate source files before path lists
$(shell make -f ${SRC_DIR}/generate.make >&2)
stamp/generated.stamp:
# if you get here, the shell above failed
false
# path lists
REAL_SOURCES := $(shell cd ${SRC_DIR}; find src/ -name '*.cpp')
REAL_HEADERS := $(shell cd ${SRC_DIR}; find include/ src/ -name '*.hpp' -o -name '*.tcc')
PIES := $(shell cd ${SRC_DIR}; find src/ -name '*.py')
PIES := $(filter-out src/main-gdb-%.py,${PIES})
SOURCES := ${REAL_SOURCES}
HEADERS := ${REAL_HEADERS}
CHECK_HEADERS := $(patsubst src/%.hpp,stamp/%.hpp.check,$(filter %.hpp,${REAL_HEADERS}))
CHECK_RANK_FWDS := $(patsubst src/%,stamp/%.rank,${REAL_HEADERS} $(filter-out %_test.cpp,${REAL_SOURCES}))
CHECK_FWDS := $(patsubst src/%/fwd.hpp,stamp/%.fwdcheck,$(filter %/fwd.hpp,${REAL_HEADERS}))
PATTERN_ROOTS := $(patsubst src/%.cpp,%,${SOURCES})
PATTERN_PIES := $(patsubst src/%.py,%,${PIES})
PATTERN_MAINS := $(patsubst %/main,%,$(filter %/main,${PATTERN_ROOTS}))
PATTERN_LIBS := $(patsubst %/lib,%,$(filter %/lib,${PATTERN_ROOTS}))
PATTERN_TESTS := $(patsubst %/test,%,$(filter %/test,${PATTERN_ROOTS}))
PATTERN_GTESTS := $(subst /,--,$(patsubst %_test,%,$(filter %_test,${PATTERN_ROOTS})))
PATTERN_DTESTS := $(patsubst debug-debug/%,%,$(filter debug-debug/%,${PATTERN_ROOTS}))
DEPENDS := $(patsubst src/%.cpp,obj/%.d,${SOURCES})
PREPROCESSED := $(patsubst %.d,%.ii,${DEPENDS})
IRS := $(patsubst %.d,%.ll,${DEPENDS})
BITCODES := $(patsubst %.d,%.bc,${DEPENDS})
ASSEMBLED := $(patsubst %.d,%.s,${DEPENDS})
PDC_OBJECTS := $(patsubst %.d,%.pdc.o,${DEPENDS})
PIC_OBJECTS := $(patsubst %.d,%.pic.o,${DEPENDS})
MAIN_SOURCES := $(filter %/main.cpp,${SOURCES})
LIB_SOURCES := $(filter %/lib.cpp,${SOURCES})
TEST_SOURCES := $(filter %/test.cpp,${SOURCES})
GTEST_SOURCES := $(filter %_test.cpp,${SOURCES})
DTEST_SOURCES := $(filter src/debug-debug/%.cpp,${SOURCES})
BINARIES := $(patsubst src/%/main.cpp,bin/${tmwa}-%.elf,${MAIN_SOURCES})
LIBRARIES := $(patsubst src/%/lib.cpp,lib/lib${tmwa}-%.${LIB_SUFFIX_FAKE},${LIB_SOURCES})
TEST_BINARIES := $(patsubst src/%/test.cpp,bin/tests/test-%.elf,${TEST_SOURCES})
GTEST_BINARIES := $(patsubst src--%_test.cpp,bin/tests/gtest-%.elf,$(subst /,--,${GTEST_SOURCES}))
DTEST_BINARIES := $(patsubst src/debug-debug/%.cpp,bin/tests/dtest-%.elf,${DTEST_SOURCES})
DOC_DOTS := $(shell cd ${SRC_DIR}; find doc-gen/ -name '*.gv')
DOC_PNGS := $(patsubst %.gv,${SRC_DIR}/%.png,${DOC_DOTS})
DOC_OBSOLETE :=
DOC_OBSOLETE += $(filter-out ${DOC_PNGS},$(wildcard ${SRC_DIR}/doc-gen/*.png))
# tricky part
# We can't put comments in a macro so here goes:
# 1: Include the contents of the current %.d file ($1).
# 2: For each header, substitute the corresponding %.o's dependency file.
# 3: For each lib.hpp header, substitute the corresponding .so library
# 4: Remove all non-deps - clutter and lonely headers.
# 5: Prevent infinite loops later by filtering out deps we've already seen.
# 6: Merge new deps into the existing dep list.
# 7: Recurse over all new deps (see 5).
define RECURSIVE_DEPS_IMPL
$(eval more_deps := $(value ${1}))
$(eval more_deps := $(patsubst src/%.hpp,%,${more_deps}))
$(eval lib_deps += $(patsubst include/${tmwa}/%.hpp,lib/lib${tmwa}-%.${LIB_SUFFIX_LONG},$(filter include/${tmwa}/%.hpp,${more_deps})))
$(eval more_deps := $(filter ${PATTERN_ROOTS} ${PATTERN_PIES},${more_deps}))
$(eval more_deps := $(filter-out ${cur_deps},${more_deps}))
$(eval cur_deps += ${more_deps})
$(foreach dep,${more_deps},${call RECURSIVE_DEPS_IMPL,${dep}})
endef
# 1: Initialize the dep list ($1 is a %.d).
# 2: Call the real function on it.
# 3: Blank for clarity.
# 4: Expand to text. Note that *nothing* else actually produces anything!
define RECURSIVE_DEPS
$(eval cur_deps := ${1})
$(eval lib_deps :=)
$(call RECURSIVE_DEPS_IMPL,${1})
$(eval py_deps := $(filter ${PATTERN_PIES},${cur_deps}))
$(filter ${PATTERN_ROOTS},${cur_deps})
endef
# Apply the rules to all the main.cpp files
# (now below, since it has to go below the include)
# utility functions for the rules
MKDIR_FIRST = @mkdir -p ${@D}
# Stuff sensitive to attoconf
CPPFLAGS += ${WARNINGS}
ifeq (${ENABLE_WARNINGS},yes)
WARNINGS := -include ${SRC_DIR}/src/warnings.hpp
endif
# related to gdb bug 15801
ifeq (${ENABLE_ABI},yes)
CXXFLAGS += -fabi-version=8
endif
# This needs to edit CXX instead of CXXFLAGS in order to make
# the %.ii rule work.
ifeq (${ENABLE_CYGWIN_HACKS},yes)
override CXX += -std=gnu++0x
else
override CXX += -std=c++0x
endif
CXXFLAGS += -fstack-protector
override CXXFLAGS += -fno-strict-aliasing
override CXXFLAGS += -fvisibility=hidden
nothing=
space=${nothing} ${nothing}
define relpath
$(subst ${space},/,$(foreach component,$(subst /,${space},$1),..))$2
endef
,=,
ifeq (${ENABLE_RPATH},relative)
rel_BINDIR := $(subst ${EPREFIX},,${BINDIR})
rel_LIBDIR := $(subst ${EPREFIX},,${LIBDIR})
ifneq (${EPREFIX}${rel_BINDIR},${BINDIR})
$(error BINDIR must be within EPREFIX to use relative rpath)
endif
ifneq (${EPREFIX}${rel_LIBDIR},${LIBDIR})
$(error LIBDIR must be within EPREFIX to use relative rpath)
endif
override LDFLAGS += -Wl,-rpath='$$ORIGIN/$(call relpath,${rel_BINDIR},${rel_LIBDIR})'
endif
ifeq (${ENABLE_RPATH},absolute)
override LDFLAGS += -Wl,rpath=${LIBDIR}
override LDFLAGS += $(patsubst -L%,-Wl$,rpath=%,$(filter -L%,${LDFLAGS}))
endif
# above is configury
# below are actual rules
# first pass, include silently, but force rebuild
ifndef MAKE_RESTARTS
# disabled due to bad interaction with generating dependencies that fail
#-include ${DEPENDS}
include ${DEPENDS}
else
include ${DEPENDS}
endif
thisdir := $(abspath .)
#$(foreach root,${PATTERN_ROOTS},$(info pre-root: ${root} := $(value ${root}))$(info ))
# can't do $(filter %.hpp yet)
$(foreach root,${PATTERN_ROOTS},$(eval ${root} := $(sort $(patsubst ${thisdir}/%,%,$(abspath $(patsubst ${SRC_DIR}/%,%,$(wildcard $(value ${root})) $(filter conf-raw/%.h,$(value ${root}))))))))
# have to redo what we undid to get it as a variable
$(foreach root,${PATTERN_ROOTS},$(eval obj/${root}.ii obj/${root}.ll obj/${root}.bc obj/${root}.s obj/${root}.pdc.o obj/${root}.pic.o obj/${root}.d : $(value ${root})) )
#$(foreach root,${PATTERN_ROOTS},$(info post-root: ${root} := $(value ${root}))$(info ))
# test.o implicitly (NOT explicitly) depends on all (nonexistent) test_*.hpp
# TODO actually have more than one test.o, each with its own set of files
#$(foreach test,${PATTERN_TESTS},$(eval ${test}/test += $(patsubst %,src/%.hpp,$(filter %_test,${PATTERN_ROOTS}))))
# FIXME find a better way
$(foreach test,tests,$(eval ${test}/test += $(patsubst %,src/%.hpp,$(filter %_test,${PATTERN_ROOTS}))))
$(foreach it,${PATTERN_MAINS},$(eval main-${it} := $(strip $(call RECURSIVE_DEPS,${it}/main))) $(eval main-${it}-libs := ${lib_deps}) $(eval main-${it}-pies := ${py_deps}))
# actual rule deps
$(foreach it,${PATTERN_MAINS},$(eval bin/${tmwa}-${it}.elf : $(patsubst %,obj/%.pdc.o,$(value main-${it})) $(value main-${it}-libs)))
$(foreach it,${PATTERN_MAINS},$(eval bin/${tmwa}-${it}-gdb.py : $(patsubst %,src/%.py,$(value main-${it}-pies))))
#$(foreach it,${PATTERN_MAINS},$(info post-main: main-${it}: $(value main-${it})) $(info post-main: main-${it}-libs: $(value main-${it}-libs)) $(info ))
$(foreach it,${PATTERN_LIBS},$(eval lib-${it} := $(strip $(call RECURSIVE_DEPS,${it}/lib))) $(eval lib-${it}-libs := ${lib_deps}) $(eval lib-${it}-pies := ${py_deps}))
# actual rule deps
$(foreach it,${PATTERN_LIBS},$(eval lib/lib${tmwa}-${it}.a : $(patsubst %,obj/%.pdc.o,$(value lib-${it})) $(filter-out lib/lib${tmwa}-${it}.a,$(value lib-${it}-libs))))
# no -gdb.py for static libs
$(foreach it,${PATTERN_LIBS},$(eval lib/lib${tmwa}-${it}.${SO_LONG} : $(patsubst %,obj/%.pic.o,$(value lib-${it})) $(filter-out lib/lib${tmwa}-${it}.${SO_LONG},$(value lib-${it}-libs))))
$(foreach it,${PATTERN_LIBS},$(eval lib/lib${tmwa}-${it}.${SO_LONG}-gdb.py : $(patsubst %,src/%.py,$(value lib-${it}-pies))))
#$(foreach it,${PATTERN_LIBS},$(info post-lib: lib-${it}: $(value lib-${it})) $(info post-lib: lib-${it}-libs: $(value lib-${it}-libs)) $(info ))
$(foreach it,${PATTERN_TESTS},$(eval test-${it} := $(strip $(call RECURSIVE_DEPS,${it}/test))) $(eval test-${it}-libs := ${lib_deps}) $(eval test-${it}-pies := ${py_deps}))
# actual rule deps
$(foreach it,${PATTERN_TESTS},$(eval bin/tests/test-${it}.elf : $(patsubst %,obj/%.pdc.o,$(value test-${it})) $(value test-${it}-libs)))
$(foreach it,${PATTERN_TESTS},$(eval bin/tests/test-${it}-gdb.py : $(patsubst %,src/%.py,$(value test-${it}-pies))))
#$(foreach it,${PATTERN_TESTS},$(info post-test: test-${it}: $(value test-${it})) $(info post-test: test-${it}-libs: $(value test-${it}-libs)) $(info ))
$(foreach it,${PATTERN_GTESTS},$(eval gtest-${it} := $(strip $(call RECURSIVE_DEPS,$(subst --,/,${it})_test))) $(eval gtest-${it}-libs := ${lib_deps}) $(eval gtest-${it}-pies := ${py_deps}))
# actual rule deps
$(foreach it,${PATTERN_GTESTS},$(eval bin/tests/gtest-${it}.elf : $(patsubst %,obj/%.pdc.o,$(value gtest-${it})) $(value gtest-${it}-libs)))
$(foreach it,${PATTERN_GTESTS},$(eval bin/tests/gtest-${it}-gdb.py : $(patsubst %,src/%.py,$(value gtest-${it}-pies))))
#$(foreach it,${PATTERN_GTESTS},$(info post-gtest: gtest-${it}: $(value gtest-${it})) $(info post-gtest: gtest-${it}-libs: $(value gtest-${it}-libs)) $(info ))
$(foreach it,${PATTERN_DTESTS},$(eval dtest-${it} := $(strip $(call RECURSIVE_DEPS,debug-debug/${it}))) $(eval dtest-${it}-libs := ${lib_deps}) $(eval dtest-${it}-pies := ${py_deps}))
# actual rule deps
$(foreach it,${PATTERN_DTESTS},$(eval bin/tests/dtest-${it}.elf : $(patsubst %,obj/%.pdc.o,$(value dtest-${it})) $(value dtest-${it}-libs)))
$(foreach it,${PATTERN_DTESTS},$(eval bin/tests/dtest-${it}-gdb.py : $(patsubst %,src/%.py,$(value dtest-${it}-pies))))
#$(foreach it,${PATTERN_DTESTS},$(info post-dtest: dtest-${it}: $(value dtest-${it})) $(info post-dtest: dtest-${it}-libs: $(value dtest-${it}-libs)) $(info ))
vpath src/%.cpp ${SRC_DIR}
vpath src/%.hpp ${SRC_DIR}
vpath include/%.hpp ${SRC_DIR}
vpath src/%.tcc ${SRC_DIR}
vpath tools/% ${SRC_DIR}
vpath src/%.py ${SRC_DIR}
.DELETE_ON_ERROR:
.DEFAULT_GOAL := all
# main goals
all: bin lib
.PHONY: bin lib
bin: ${BINARIES}
ifeq (${ENABLE_SHARED},yes)
lib: sharedlib
else
lib: staticlib
endif
sharedlib: $(patsubst %.${LIB_SUFFIX_FAKE},%.${SO_LONG},${LIBRARIES})
staticlib: $(patsubst %.${LIB_SUFFIX_FAKE},%.a,${LIBRARIES})
ii: ${PREPROCESSED}
ll: ${IRS}
bc: ${BITCODES}
s: ${ASSEMBLED}
o: ${PDC_OBJECTS}
# why not PIC objects? Because this is only for debugging, so we don't need
# duplicates, and PDC is more common, and also some override rules are only
# currently defined for PDC
clean-stamp:
$l rm -rf stamp
clean-deps:
-$l find obj -name '*.d' -delete
clean-format:
-$l find obj -name '*.formatted' -delete
clean-obj:
-$l find obj -name '*.o' -delete
clean-conf:
$l rm -rf conf-raw
mostlyclean: clean-conf
$l rm -rf obj stamp
clean: mostlyclean
$l rm -rf bin lib
distclean: clean gen-clean
gen-clean:
$l rm -f stamp/generate*.stamp
$l rm -rf ${SRC_DIR}/src/proto2/
$l rm -rf ${SRC_DIR}/src/debug-debug/
$l rm -rf ${SRC_DIR}/src/*/*_conf.[ch]pp
ifndef MAKE_RESTARTS
obj/%.d: src/%.cpp | stamp/generated.stamp
$(MKDIR_FIRST)
# Not using $c because it's slow and this should be fast
${CXX} ${CPPFLAGS} -DGENERATING_DEPENDENCIES ${CXXFLAGS} -MG -MM \
-MT '$(patsubst obj/%.d,%,$@) := ' \
-MF $@ $<
endif
# the above SRC_DIR replacement is not really safe, but it works okayish.
obj/%.ii: src/%.cpp
$(MKDIR_FIRST)
$c ${CXX} ${CPPFLAGS} -E -o $@ $<
obj/%.ll: src/%.cpp
$(MKDIR_FIRST)
$c ${CXX} ${CPPFLAGS} ${CXXFLAGS} -S -emit-llvm -o $@ $<
obj/%.bc: src/%.cpp
$(MKDIR_FIRST)
$c ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -emit-llvm -o $@ $<
obj/%.s: src/%.cpp
$(MKDIR_FIRST)
$c ${CXX} ${CPPFLAGS} ${CXXFLAGS} -S -o $@ $<
obj/%.pdc.o: src/%.cpp
$(MKDIR_FIRST)
$c ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $<
obj/%.pic.o: src/%.cpp
$(MKDIR_FIRST)
$c ${CXX} ${CPPFLAGS} ${CXXFLAGS} -fPIC -c -o $@ $<
stamp/%.hpp.check: src/%.hpp
$(MKDIR_FIRST)
${CXX} ${CPPFLAGS} ${CXXFLAGS} -x c++ -fsyntax-only - <<< '#include "$<"'
touch $@
bin/%-gdb.py: src/main-gdb-head.py src/main-gdb-tail.py
$(MKDIR_FIRST)
cat $(filter %/main-gdb-head.py,$^) \
$(filter-out %/main-gdb-head.py %/main-gdb-tail.py,$^) \
$(filter %/main-gdb-tail.py,$^) \
> $@
@# aliases to let in-place execution work
ln -sf $(notdir $@) $(patsubst %-gdb.py,%.elf-gdb.py,$@)
bin/%.elf: bin/%-gdb.py
$(MKDIR_FIRST)
$l ${CXX} ${LDFLAGS} $(filter-out bin/%-gdb.py,$^) ${LDLIBS} -o $@
lib/%.${SO_LONG}-gdb.py:
$(MKDIR_FIRST)
cat ${SRC_DIR}/src/main-gdb-head.py \
$^ \
${SRC_DIR}/src/main-gdb-tail.py \
> $@
lib/%.${SO_LONG}: lib/%.${SO_LONG}-gdb.py
$(MKDIR_FIRST)
$l ${CXX} -shared -Wl,-soname=$*.${SO_SHORT} ${LDFLAGS} $(filter-out lib/%-gdb.py,$^) ${LDLIBS} -o $@
$c ln -sfT $*.${SO_LONG} lib/$*.${SO_SHORT}
$c ln -sfT $*.${SO_SHORT} lib/$*.so
lib/%.a:
$(MKDIR_FIRST)
rm -f $@
ar cr $@ $^
${GTEST_BINARIES}: obj/gtest_main.pdc.o obj/gtest-all.pdc.o
# This isn't perfect.
$(filter %_test.pdc.o,${PDC_OBJECTS}) obj/gtest_main.pdc.o obj/gtest-all.pdc.o: override CPPFLAGS += -DGTEST_HAS_PTHREAD=0 -I${GTEST_DIR}
obj/gtest-all.pdc.o obj/gtest_main.pdc.o: override WARNINGS :=
obj/gtest%.pdc.o: ${GTEST_DIR}/src/gtest%.cc
$(MKDIR_FIRST)
$c ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $<
DTEST_OBJS := $(filter obj/debug-debug/%.pdc.o,${PDC_OBJECTS})
DTEST_STAMPS := $(patsubst bin/tests/%.elf,stamp/run-%.stamp,${DTEST_BINARIES})
${DTEST_OBJS}: override CXXFLAGS += -g -O0 -gdwarf-3
${DTEST_STAMPS}: override TESTER=${GDB} -return-child-result -nx -batch -ex 'python file_to_load = "$<"' -x ${SRC_DIR}/tools/debug-debug.gdb --args false
${DTEST_STAMPS}: tools/debug-debug.gdb
test: test-direct
test-direct: $(patsubst bin/tests/%.elf,stamp/run-%.stamp,${TEST_BINARIES})
test: test-gtest
test-gtest: $(patsubst bin/tests/%.elf,stamp/run-%.stamp,${GTEST_BINARIES})
test: test-dtest
test-dtest: $(patsubst bin/tests/%.elf,stamp/run-%.stamp,${DTEST_BINARIES})
$(patsubst bin/tests/%.elf,stamp/run-%.stamp,${TEST_BINARIES} ${GTEST_BINARIES} ${DTEST_BINARIES}): stamp/symlink-test-lib-dir.stamp
stamp/symlink-test-lib-dir.stamp:
@mkdir -p bin
ln -sfT ../lib bin/lib
touch $@
stamp/run-%.stamp: bin/tests/%.elf
$(MKDIR_FIRST)
${TESTER} $< ${TEST_ARGS}
touch $@
test: test-headers
test-headers: ${CHECK_HEADERS}
test: test-rank-fwd
test-rank-fwd: ${CHECK_RANK_FWDS}
stamp/%.rank: src/%
$(MKDIR_FIRST)
includes=$$(grep '#include.*".*/.*"' $< | sed 's/^[^"]*"//;s/"[^"]*$$//;s:/[^/]*$$::' | sort -u | fgrep -vx -e '..' -e 'conf-raw' -e '../conf'); \
for inc in $$includes; do if ! test -f ${<D}/fwd.hpp; then continue; fi; echo fgrep -q $${inc}/fwd.hpp ${<D}/fwd.hpp; fgrep -q $${inc}/fwd.hpp ${<D}/fwd.hpp || { echo ${<D}/fwd.hpp:''23: error: No $${inc}/fwd.hpp; exit 1; }; done
touch $@
test: test-check-fwd
test-check-fwd: ${CHECK_FWDS}
stamp/%.fwdcheck: src/%/fwd.hpp
$(MKDIR_FIRST)
types=$$(grep -o '\(enum \|class \| struct \|union \)\+[A-Za-z_0-9]\+;$$' $< | sed 's/\(;\|enum \|class \|struct \|union \)//g'); \
for t in $$types; do echo grep -q $$t $(filter-out %/fwd.hpp,$(wildcard ${<D}/*.hpp)); grep -qw '\(enum \|class \|struct \|union \)'$$t $(filter-out %/fwd.hpp,$(wildcard ${<D}/*.hpp)) || { grep -Hnw $$t';$$' $<; exit 1; }; done
includes=$$(grep -o '#include.*".*/fwd\.hpp"' $< | sed 's:^[^"]*"::;s:/[^/]*"$$:/:'); \
for inc in $$includes; do echo fgrep -q $$inc $(filter-out %/fwd.hpp,$(wildcard ${<D}/*.hpp ${<D}/*.tcc ${<D}/*.cpp)); fgrep -q $$inc $(filter-out %/fwd.hpp,$(wildcard ${<D}/*.hpp ${<D}/*.tcc ${<D}/*.cpp)) || { grep -Hn $$inc $<; exit 1; }; done
touch $@
install := install
install_exe := ${install}
install_dir := ${install} -d
install_data := ${install} -m 0644
install:
@echo = Done installing
uninstall:
@echo = Done uninstalling
install: install-bin
install-bin:
@echo + Installing binaries
${install_dir} ${DESTDIR}${BINDIR}
for exe in $(patsubst bin/%.elf,%,${BINARIES}); do \
${install_exe} bin/$${exe}.elf ${DESTDIR}${BINDIR}/$${exe}; \
done
uninstall: uninstall-bin
uninstall-bin:
@echo - Uninstalling binaries
-rm ${DESTDIR}${BINDIR}/${tmwa}-*
install: install-lib
install-lib:
@echo + Installing libraries
${install_dir} ${DESTDIR}${LIBDIR}
ifeq (${ENABLE_SHARED},yes)
${install_data} -t ${DESTDIR}${LIBDIR} \
$(patsubst %.so,%.${SO_LONG},${LIBRARIES})
for lib in $(patsubst lib/%.so,%,${LIBRARIES}); do \
ln -sfT $$lib.${SO_LONG} ${DESTDIR}${LIBDIR}/$$lib.${SO_SHORT}; \
ln -sfT $$lib.${SO_SHORT} ${DESTDIR}${LIBDIR}/$$lib.so; \
done
else
${install_data} -t ${DESTDIR}${LIBDIR} \
${LIBRARIES}
endif
uninstall: uninstall-lib
uninstall-lib:
@echo - Uninstalling libraries
-rm ${DESTDIR}${LIBDIR}/lib${tmwa}-*
install: install-debug
install-debug:
ifeq (${ENABLE_DEBUG},yes)
@echo + Installing debug files
${install_dir} ${DESTDIR}${DEBUGDIR}${BINDIR}
${install_data} -t ${DESTDIR}${DEBUGDIR}${BINDIR} \
$(patsubst %.elf,%-gdb.py,${BINARIES})
${install_dir} ${DESTDIR}${DEBUGDIR}${LIBDIR}
${install_data} -t ${DESTDIR}${DEBUGDIR}${LIBDIR} \
$(patsubst %.so,%.${SO_LONG}-gdb.py,${LIBRARIES})
else
@echo - Not installing debug files
endif
uninstall: uninstall-debug
uninstall-debug: uninstall-lib uninstall-bin
@echo - Maybe uninstalling debug files
-rm ${DESTDIR}${DEBUGDIR}${BINDIR}/${tmwa}-*
-rm ${DESTDIR}${DEBUGDIR}${LIBDIR}/lib${tmwa}-*
install: install-include
install-include:
@echo + Installing headers
${install_dir} ${DESTDIR}${PACKAGEINCLUDEDIR}
${install_data} -t ${DESTDIR}${PACKAGEINCLUDEDIR} \
$(addprefix ${SRC_DIR}/,$(filter include/%,${HEADERS}))
uninstall: uninstall-include
uninstall-include:
@echo - Uninstalling headers
-rm -r ${DESTDIR}${PACKAGEINCLUDEDIR}
install: install-state
install-state:
@echo + Installing statedir
${install_dir} ${DESTDIR}${PACKAGELOCALSTATEDIR}
touch ${DESTDIR}${PACKAGELOCALSTATEDIR}/.keep
uninstall: uninstall-state
uninstall-state:
@echo '*' Not uninstalling statedir
: ${DESTDIR}${PACKAGELOCALSTATEDIR}
install: install-data
install-data:
@echo + Installing data
${install_dir} ${DESTDIR}${PACKAGEDATADIR}
${install_data} -t ${DESTDIR}${PACKAGEDATADIR} \
${SRC_DIR}/share/tmwa/*
uninstall: uninstall-data
uninstall-data:
@echo - Uninstalling data
-rm -r ${DESTDIR}${PACKAGEDATADIR}
install: install-conf
install-conf:
@echo + Installing config files
${install_dir} ${DESTDIR}${PACKAGESYSCONFDIR}
${install_data} -t ${DESTDIR}${PACKAGESYSCONFDIR} \
${SRC_DIR}/etc/tmwa/*
uninstall: uninstall-conf
uninstall-conf:
@echo Not uninstalling config files
: ${DESTDIR}${PACKAGESYSCONFDIR}
tags: ${SOURCES} ${HEADERS}
$l ctags --totals -h .tcc --langmap=C++:+.tcc --c-kinds=+px -f $@ $^
Makefile: ${SRC_DIR}/Makefile.in
@echo Makefile.in updated, reconfiguring ...
./config.status
# TODO - fix pattern priority bug so I can make these .hpp
#
# This is complicated and still isn't optimal.
conf-raw/int-%.h: FORCE
$(MKDIR_FIRST)
@echo '#define $* $(value $*)' | maybe-replace $@
bool_yes := true
bool_no := false
conf-raw/bool-%.h: FORCE
$(MKDIR_FIRST)
@echo '#define $* $(bool_$(value $*))' | maybe-replace $@
conf-raw/str-%.h: FORCE
$(MKDIR_FIRST)
@echo '#define $* "$(value $*)"_s' | maybe-replace $@
FORCE: ;
.PHONY: FORCE
override CPPFLAGS += -I . -I ${SRC_DIR}/include
# distribution tarballs
# this only works from within a git checkout
dist/%/version.make:
$(MKDIR_FIRST)
git --git-dir=${SRC_DIR}/.git show HEAD:version.make > $@
sed 's/^VERSION_FULL := .*/#&\nVERSION_FULL := ${VERSION_FULL}/' -i $@
sed 's/^VERSION_HASH := .*/#&\nVERSION_HASH := ${VERSION_HASH}/' -i $@
dist/%-src.tar: dist/%/version.make
git --git-dir=${SRC_DIR}/.git archive --prefix=$*/ -o $@ HEAD
( mtime="$$(git --git-dir=${SRC_DIR}/.git log -n1 --pretty=%ci)" && cd dist && tar uf $*-src.tar --mtime="$${mtime}" --mode=664 --owner=root --group=root $*/version.make )
rm dist/$*/version.make
rmdir dist/$*/
dist/%-attoconf-only.tar:
$(MKDIR_FIRST)
git --git-dir=${SRC_DIR}/deps/attoconf/.git archive --prefix=$*/deps/attoconf/ HEAD -o $@
dist/%-bundled.tar: dist/%-src.tar dist/%-attoconf-only.tar
cp dist/$*-src.tar $@
tar Af $@ dist/$*-attoconf-only.tar
dist/%-bin-${HOST}.tar: all
${MAKE} install DESTDIR=$(abspath dist/${HOST}/$*)
if test -n '${BUNDLED_LIBS}'; then cp ${BUNDLED_LIBS} dist/${HOST}/$*/${LIBDIR}/; fi
tar cf $@ -C dist/${HOST} $*
rm -r dist/${HOST}/
dist: dist/${tmwa}-${VERSION_FULL}-src.tar dist/${tmwa}-${VERSION_FULL}-bundled.tar
ifneq '' '${HOST}'
bindist: dist/${tmwa}-${VERSION_FULL}-bin-${HOST}.tar
else
bindist:
@echo
@echo
@echo "Fatal Error: 'make bindist' requires './configure --host='."
@echo "Maybe you want `${CXX} -v 2>&1 | sed -n '/Target: /{s///;p}'`, but I refuse to guess,"
@echo "because there are too many options like -m32 that confuse me."
@echo
@echo
@false
endif
.PHONY: dist
format: format-cpp format-hpp
format-cpp: $(patsubst src/%,stamp/%.formatted,${REAL_SOURCES})
format-hpp: $(patsubst src/%,stamp/%.formatted,${REAL_HEADERS})
stamp/%.cpp.formatted: src/%.cpp tools/indenter
$(MKDIR_FIRST)
apply-filter 'indenter -cpp' $<
fgrep -q Copyright $<
fgrep -q $(notdir $<) $<
fgrep -q ../poison.hpp $<
grep -q '^namespace tmwa$$' $<
grep -q '^} // namespace tmwa$$' $<
touch $@
stamp/%.hpp.formatted: src/%.hpp tools/indenter
$(MKDIR_FIRST)
apply-filter 'indenter -cpp' $<
fgrep -q Copyright $<
fgrep -q $(notdir $<) $<
if [[ $< == *fwd* ]]; then fgrep -q ../sanity.hpp $<; else fgrep -q '"fwd.hpp"' $<; fi
if [[ $< == *fwd* ]]; then ! fgrep -q '"fwd.hpp"' $<; else ! fgrep -q ../sanity.hpp $<; fi
grep -q '^namespace tmwa$$' $<
grep -q '^} // namespace tmwa$$' $<
grep -q '^#pragma once$$' $<
touch $@
stamp/%.tcc.formatted: src/%.tcc tools/indenter
$(MKDIR_FIRST)
apply-filter 'indenter -cpp' $<
fgrep -q Copyright $<
fgrep -q $(notdir $<) $<
grep -q '^namespace tmwa$$' $<
grep -q '^} // namespace tmwa$$' $<
touch $@
.PHONY: format format-cpp format-hpp
vpath doc-gen/%.gv ${SRC_DIR}
${SRC_DIR}/doc-gen/%.png: doc-gen/%.gv
dot -Tpng $< -o $@
doc: ${DOC_PNGS}
test -e ${SRC_DIR}/doc-gen/.git
rm -f ${DOC_OBSOLETE}
.PHONY: doc
most: $(filter-out bin/${tmwa}-map.elf,${BINARIES})
magic: $(filter obj/map/magic%,${PDC_OBJECTS})
common: $(filter-out %/lib.pdc.o obj/debug-debug/% %_test.pdc.o obj/login/% obj/char/% obj/map/% obj/admin/%,${PDC_OBJECTS})