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 ## ## 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 . # 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.mk 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.mk >&2) stamp/generated.stamp: # if you get here, the shell above failed false # path lists GENERATED_FILES := src/conf/version.hpp 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++11 else override CXX += -std=c++11 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) # Sanitize the dependencies. # # ${root} has a value like "mmo/version", and ${mmo/version} in turn has the # value of all of its dependencies (from the %.d files). # # This reassigns the *value of the value* of ${root} to be: # - sorted # - relative and simplified: it's stripped of any absolute path relative to # the current directory after being converted to an absolute path. # This also converts paths from being relative to the build directory to # being relative to the source directory, if they differ. # This simplifies any construct such as: # ../src/mmo/../strings/zstring.tcc # to: # src/strings/zstring.tcc # - only files which either exist (the purpose of the wildcard function), # are in the conf-raw directory (the first filter function), or # are listed in the GENERATED_FILES variable (the second filter function). # This means that if there are any build-time generated files added, this # needs to be modified to not filter them out. # # The end result for each root will look something like: # mmo/version := conf-raw/int-VENDOR_POINT.h conf-raw/int-VERSION_DEVEL.h [...] # src/strings/zstring.tcc src/wire/fwd.hpp # Firstly, make the paths relative and simplified. $(foreach root,${PATTERN_ROOTS},$(eval \ ${root} := $(sort $(patsubst ${thisdir}/%,%, \ $(abspath $(patsubst ${SRC_DIR}/%,%, $(value ${root}))) \ )) \ )) # Secondly, make sure that the files actually exist, or are files we expect to # generate ourselves. Sort the result for readability. # Note that we re-add and remove the ${SRC_DIR} prefix when testing for # existence, as we need to test for existence relative to our build directory. $(foreach root,${PATTERN_ROOTS},$(eval \ ${root} := $(sort \ $(patsubst ${SRC_DIR}/%,%,$(wildcard $(addprefix ${SRC_DIR}/, \ $(value ${root}) \ ))) \ $(filter conf-raw/%.h,$(value ${root})) \ $(filter ${GENERATED_FILES},$(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} vpath src/%.in ${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 $@ $< # -MG takes the include parameter as-is without prepending the path whenever # it's not found, and presumed to be a not-yet generated file. # #include statements for generated files should always be relative to the # source (or build) directory. 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 # Need gtest include for both compile (*_test.pdc.o) and dependency-generation (*_test.d) steps. GTEST_NEED_INCLUDE := $(filter %_test.pdc.o,${PDC_OBJECTS}) $(filter %_test.d,${DEPENDS}) obj/gtest_main.pdc.o obj/gtest-all.pdc.o ${GTEST_NEED_INCLUDE}: override CXXFLAGS += -DGTEST_HAS_PTHREAD=0 -I${GTEST_DIR}/include # Special rule for src/gtest-all.cc, it includes "src/gtest.cc" # and thus additionally needs toplevel as include obj/gtest-all.pdc.o: override CXXFLAGS += -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 ${ $@ sed 's/^VERSION_FULL := .*/#&\nVERSION_FULL := ${VERSION_FULL}/' -i $@ sed 's/^VERSION_HASH := .*/#&\nVERSION_HASH := ${VERSION_HASH}/' -i $@ dist/%-src.tar: dist/%/version.mk 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.mk ) rm dist/$*/version.mk 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})