SRC_DIR = @SRC_DIR@ CONFIG_HASH = @CONFIG_HASH@ PACKAGE = @PACKAGE@ PACKAGE_NAME = @PACKAGE_NAME@ PREFIX = @PREFIX@ EPREFIX = @EPREFIX@ BINDIR = @BINDIR@ SBINDIR = @SBINDIR@ LIBEXECDIR = @LIBEXECDIR@ SYSCONFDIR = @SYSCONFDIR@ SHAREDSTATEDIR = @SHAREDSTATEDIR@ LOCALSTATEDIR = @LOCALSTATEDIR@ LIBDIR = @LIBDIR@ INCLUDEDIR = @INCLUDEDIR@ 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@ BISON = @BISON@ FLEX = @FLEX@ CPPFLAGS = @CPPFLAGS@ LDFLAGS = @LDFLAGS@ LDLIBS = @LDLIBS@ CXX = @CXX@ CXXFLAGS = @CXXFLAGS@ GTEST_DIR = @GTEST_DIR@ ENABLE_BACKUPS_DURING_INSTALL = @ENABLE_BACKUPS_DURING_INSTALL@ ENABLE_WARNINGS = @ENABLE_WARNINGS@ ENABLE_ABI6 = @ENABLE_ABI6@ ENABLE_CYGWIN_HACKS = @ENABLE_CYGWIN_HACKS@ ENABLE_COMPAT_SYMLINKS = @ENABLE_COMPAT_SYMLINKS@ ENABLE_DEBUG = @ENABLE_DEBUG@ 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 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 # path lists REAL_SOURCES := $(shell cd ${SRC_DIR}; find src/ -name '*.cpp') REAL_HEADERS := $(shell cd ${SRC_DIR}; find src/ -name '*.hpp' -o -name '*.tcc') PIES := $(shell cd ${SRC_DIR}; find src/ -name '*.py') SOURCES := ${REAL_SOURCES} HEADERS := ${REAL_HEADERS} PATTERN_ROOTS := $(patsubst src/%.cpp,%,${SOURCES}) PATTERN_MAINS := $(patsubst %/main,%,$(filter %/main,${PATTERN_ROOTS})) PATTERN_TESTS := $(patsubst %/test,%,$(filter %/test,${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}) OBJECTS := $(patsubst %.d,%.o,${DEPENDS}) MAIN_SOURCES := $(filter %/main.cpp,${SOURCES}) TEST_SOURCES := $(filter %/test.cpp,${SOURCES}) BINARIES := $(patsubst src/%/main.cpp,bin/tmwa-%,${MAIN_SOURCES}) TEST_BINARIES := $(patsubst src/%/test.cpp,bin/test-%,${TEST_SOURCES}) # 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: Blank, reserved for header->libtmwa-common.a if that gets implemented. # 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 more_deps := $(filter ${PATTERN_ROOTS},${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}) $(call RECURSIVE_DEPS_IMPL,${1}) ${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_ABI6},yes) CXXFLAGS += -fabi-version=6 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 # above is configury # below are actual rules # first pass, include silently, but force rebuild ifndef MAKE_RESTARTS -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}.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})))) $(foreach main,${PATTERN_MAINS},$(eval main-${main} := $(strip $(call RECURSIVE_DEPS,${main}/main)))) # actual rule deps $(foreach main,${PATTERN_MAINS},$(eval bin/tmwa-${main} : $(patsubst %,obj/%.o,$(value main-${main})))) $(foreach main,${PATTERN_MAINS},$(eval bin/tmwa-${main}-gdb.py : $(filter ${PIES},$(patsubst %,src/%.py,$(value main-${main}))))) #$(foreach main,${PATTERN_MAINS},$(info post-main: main-${main}: $(value main-${main})) $(info )) $(foreach test,${PATTERN_TESTS},$(eval test-${test} := $(strip $(call RECURSIVE_DEPS,${test}/test)))) # actual rule deps $(foreach test,${PATTERN_TESTS},$(eval bin/test-${test} : $(patsubst %,obj/%.o,$(value test-${test})))) $(foreach test,${PATTERN_TESTS},$(eval bin/test-${test}-gdb.py : $(filter ${PIES},$(patsubst %,src/%.py,$(value test-${test}))))) #$(foreach test,${PATTERN_TESTS},$(info post-test: test-${test}: $(value test-${test})) $(info )) vpath %.cpp ${SRC_DIR} vpath %.hpp ${SRC_DIR} vpath %.tcc ${SRC_DIR} vpath tools/% ${SRC_DIR} vpath %.py ${SRC_DIR} .DELETE_ON_ERROR: .DEFAULT_GOAL := all # main goals all: ${BINARIES} ii: ${PREPROCESSED} ll: ${IRS} bc: ${BITCODES} s: ${ASSEMBLED} o: ${OBJECTS} clean-deps: -$c find obj -name '*.d' -delete clean-format: -$c find obj -name '*.formatted' -delete clean-obj: -$c find obj -name '*.o' -delete clean-conf: $c rm -rf conf-raw mostlyclean: clean-conf $c rm -rf obj clean: mostlyclean $c rm -rf bin distclean: clean gen-clean gen-clean: ; ifndef MAKE_RESTARTS obj/%.d: src/%.cpp $(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/%.o: src/%.cpp $(MKDIR_FIRST) $c ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $< # I'm not convinced keeping the bin/ is a good idea bin/%-gdb.py: $(MKDIR_FIRST) cat ${SRC_DIR}/src/main-gdb-head.py \ $^ \ ${SRC_DIR}/src/main-gdb-tail.py \ > $@ bin/%: bin/%-gdb.py $(MKDIR_FIRST) $l ${CXX} ${LDFLAGS} $(filter-out bin/%-gdb.py,$^) ${LDLIBS} -o $@ ${TEST_BINARIES}: obj/gtest-all.o # This isn't perfect. $(filter %_test.o,${OBJECTS}) obj/gtest-all.o: override CPPFLAGS += -DGTEST_HAS_PTHREAD=0 -I${GTEST_DIR} obj/gtest-all.o: override WARNINGS := obj/gtest-all.o: ${GTEST_DIR}/src/gtest-all.cc $(MKDIR_FIRST) $c ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $< test: $(patsubst bin/%,.run-%,${TEST_BINARIES}) .run-%: bin/% ${TESTER} $< ${TEST_ARGS} install := install --backup=${ENABLE_BACKUPS_DURING_INSTALL} install_exe := ${install} install_dir := ${install} -d install_data := ${install} -m 0644 install_symlink := ln --backup=${ENABLE_BACKUPS_DURING_INSTALL} -sf install: @echo = Done installing install: install-bin install-bin: @echo + Installing binaries ${install_dir} ${DESTDIR}${BINDIR} ${install_exe} -t ${DESTDIR}${BINDIR} \ ${BINARIES} install-bin: install-bin-compat install-bin-compat: ifeq (${ENABLE_COMPAT_SYMLINKS},yes) @echo + Installing compatibility symlinks ${install_dir} ${DESTDIR}${BINDIR} ${install_symlink} tmwa-login ${DESTDIR}${BINDIR}/login-server ${install_symlink} tmwa-char ${DESTDIR}${BINDIR}/char-server ${install_symlink} tmwa-map ${DESTDIR}${BINDIR}/map-server ${install_symlink} tmwa-admin ${DESTDIR}${BINDIR}/ladmin ${install_symlink} tmwa-monitor ${DESTDIR}${BINDIR}/eathena-monitor else @echo - Not installing compatibility symlinks endif 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 %,%-gdb.py,${BINARIES}) else @echo - Not installing debug files endif 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 include ${SRC_DIR}/version.make # 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 . # 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: dist/tmwa-${VERSION_FULL}-src.tar dist/tmwa-${VERSION_FULL}-bundled.tar .PHONY: dist format: format-cpp format-hpp format-cpp: $(patsubst src/%,obj/%.formatted,${REAL_SOURCES}) format-hpp: $(patsubst src/%,obj/%.formatted,${REAL_HEADERS}) obj/%.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 $@ obj/%.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 $@ obj/%.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