From 7c77cbd24c03aceff65feae5082221b62eaeea6e Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Sat, 1 Feb 2014 14:57:23 -0800 Subject: Get rid of makefile indirection --- .travis.yml | 6 +- CHANGELOG | 22 ++++ Makefile.in | 418 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- real.make | 418 ------------------------------------------------------------ 4 files changed, 433 insertions(+), 431 deletions(-) delete mode 100644 real.make diff --git a/.travis.yml b/.travis.yml index 963b088..f2588ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -47,13 +47,13 @@ script: - mkdir build - cd build - ../configure --dev CPPFLAGS=-DQUIET - - make -k -j2 - - make format + - make -R -k -j2 + - make -R format - git diff --exit-code ## Do something after the main test script after_script: - - make test TESTER='valgrind --error-exitcode=1 --track-fds=yes' + - make -R test TESTER='valgrind --error-exitcode=1 --track-fds=yes' ### The rest of the file creates a build matrix ### containing gcc-4.6 through gcc-4.8 and clang-3.1 through clang-3.3 diff --git a/CHANGELOG b/CHANGELOG index 22464f3..23e4793 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,25 @@ +v14.1.27: + - new tracking IO for better errors + - Unified config parsing! This *requires* new config files in server-data + - reimplement shared string better + - fix IO-related abort during shutdown + - fix the numbering of certain map logs + - add mapexit script command, since @mapexit doesn't work without a player + - start enforcing code format automatically + - add debug printers +v13.11.24: + - don't consume spell components when under @hide + - tmwa-admin no longer logs passwords in cleartext + - tmwa-admin help slightly fixed (still terrible) + - make tmwa-finger work for tmwa-map also + - allow setting class + - I/O rewrite + - allow checking whether arrows are equipped + - more printers +v13.10.31: + - make debug printers more compatible with older systems + - fix account creation with ladmin + - fix building out of tree v13.10.29: - show MOTD in a way that works - ignore hidden GMs in more scripts diff --git a/Makefile.in b/Makefile.in index 1030212..64b0c27 100644 --- a/Makefile.in +++ b/Makefile.in @@ -48,14 +48,412 @@ ENABLE_DEBUG = @ENABLE_DEBUG@ -# This file is reverse included. Don't forward in that case. -ifeq '${MAKEFILE_LIST}' ' Makefile' -.DEFAULT_GOAL=.default-target-wrapper -# The documentation for ${MAKECMDGOALS} says "Note that this variable -# should be used only in special circumstances." -# If you do not understand *exactly* why I do this instead of -# %::;${MAKE}, stay away from this code. You have been warned. -.default-target-wrapper ${MAKECMDGOALS}: .all-target-wrapper ; @: -.all-target-wrapper: - ${MAKE} -rRf ${SRC_DIR}/real.make ${MAKECMDGOALS} +## 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 + +.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} =))) + +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 +LEXERS := $(shell cd ${SRC_DIR}; find src/ -name '*.lpp') +PARSERS := $(shell cd ${SRC_DIR}; find src/ -name '*.ypp') +GEN_SOURCES := \ + $(patsubst %.lpp,%.cpp,${LEXERS}) \ + $(patsubst %.ypp,%.cpp,${PARSERS}) +GEN_HEADERS := \ + $(patsubst %.ypp,%.hpp,${PARSERS}) +REAL_SOURCES := $(shell cd ${SRC_DIR}; find src/ -name '*.cpp') +REAL_HEADERS := $(shell cd ${SRC_DIR}; find src/ -name '*.hpp' -o -name '*.tcc') +REAL_SOURCES := $(filter-out ${GEN_SOURCES},${REAL_SOURCES}) +REAL_HEADERS := $(filter-out ${GEN_HEADERS},${REAL_HEADERS}) +SOURCES := ${GEN_SOURCES} ${REAL_SOURCES} +HEADERS := ${GEN_HEADERS} ${REAL_HEADERS} +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}) +GEN_DEPENDS := $(patsubst src/%.cpp,obj/%.d,${GEN_SOURCES}) +GEN_PREPROCESSED := $(patsubst %.d,%.ii,${GEN_DEPENDS}) +GEN_IRS := $(patsubst %.d,%.ll,${GEN_DEPENDS}) +GEN_BITCODES := $(patsubst %.d,%.bc,${GEN_DEPENDS}) +GEN_ASSEMBLED := $(patsubst %.d,%.s,${GEN_DEPENDS}) +GEN_OBJECTS := $(patsubst %.d,%.o,${GEN_DEPENDS}) +MAIN_SOURCES := $(filter %/main.cpp,${SOURCES}) +BINARIES := $(patsubst src/%/main.cpp,bin/tmwa-%,${MAIN_SOURCES}) + +TEST_DEPENDS := $(patsubst src/%/test.cpp,obj/%/autolist.d,$(filter %/test.cpp,${SOURCES})) +DEPENDS += ${TEST_DEPENDS} +TEST_BINARIES := $(patsubst obj/%/autolist.d,bin/test-%,${TEST_DEPENDS}) + +# 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 := $(shell cat $(patsubst %/test.d,%/autolist.d,${1}))) +$(eval more_deps := $(patsubst src/%.hpp,obj/%.d,${more_deps})) + +$(eval more_deps := $(filter ${DEPENDS},${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 +$(foreach exe,${BINARIES},$(eval ${exe}: $(strip $(patsubst %.d,%.o,$(call RECURSIVE_DEPS,$(patsubst bin/tmwa-%,obj/%/main.d,${exe})))))) +$(foreach exe,${TEST_BINARIES},$(eval ${exe}: $(strip $(patsubst %.d,%.o,$(call RECURSIVE_DEPS,$(patsubst bin/test-%,obj/%/test.d,${exe})))))) + +# utility functions for the rules +MKDIR_FIRST = @mkdir -p ${@D} + +# Stuff sensitive to attoconf +CXXFLAGS += ${WARNINGS} +ifeq (${ENABLE_WARNINGS},yes) +WARNINGS := -include ${SRC_DIR}/src/warnings.hpp +endif +${GEN_DEPENDS} ${GEN_PREPROCESSED} ${GEN_IRS} ${GEN_BITCODES} ${GEN_ASSEMBLED} ${GEN_OBJECTS}: override WARNINGS := +# can't just override for generated objects, +# because a generated header might be used for a non-generated object. +override CPPFLAGS += -I ${SRC_DIR}/$(patsubst obj/%,src/%,${@D}) + +# 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 + +# actual rules +vpath %.ypp ${SRC_DIR} +vpath %.lpp ${SRC_DIR} +vpath %.cpp ${SRC_DIR} +vpath %.hpp ${SRC_DIR} +vpath %.tcc ${SRC_DIR} +vpath tools/% ${SRC_DIR} + +.DELETE_ON_ERROR: +.DEFAULT_GOAL := all +# main goals +all: ${BINARIES} +cpp: ${GEN_SOURCES} ${GEN_HEADERS} +ii: ${PREPROCESSED} +ll: ${IRS} +bc: ${BITCODES} +s: ${ASSEMBLED} +o: ${OBJECTS} + +mostlyclean: + rm -rf obj conf-raw +clean: mostlyclean + rm -rf bin +distclean: clean gen-clean +gen-clean: + rm -f ${GEN_SOURCES} ${GEN_HEADERS} + +%.cpp: %.lpp + $(MKDIR_FIRST) + ${FLEX} -o $@ $< +%.cpp %.hpp: %.ypp + $(MKDIR_FIRST) + ${BISON} -d -o $*.cpp $< +ifndef MAKE_RESTARTS +# prevent errors if missing header +obj/%.d: src/%.cpp + $(MKDIR_FIRST) + set -o pipefail; \ + ${CXX} ${CPPFLAGS} -DGENERATING_DEPENDENCIES ${CXXFLAGS} -MG -MP -MM $< \ + -MT '$(patsubst %.d,%.ii,$@) $(patsubst %.d,%.ll,$@) $(patsubst %.d,%.bc,$@) $(patsubst %.d,%.s,$@) $(patsubst %.d,%.o,$@) $@' \ + | sed -e ':again; s:/[^/. ]*/\.\./:/:; t again' \ + -e 's: ${SRC_DIR}/: :g' \ + > $@ +endif +# the above SRC_DIR replacement is not really safe, but it works okayish. +obj/%.ii: src/%.cpp + $(MKDIR_FIRST) + ${CXX} ${CPPFLAGS} -E -o $@ $< +obj/%.ll: src/%.cpp + $(MKDIR_FIRST) + ${CXX} ${CPPFLAGS} ${CXXFLAGS} -S -emit-llvm -o $@ $< +obj/%.bc: src/%.cpp + $(MKDIR_FIRST) + ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -emit-llvm -o $@ $< +obj/%.s: src/%.cpp + $(MKDIR_FIRST) + ${CXX} ${CPPFLAGS} ${CXXFLAGS} -S -o $@ $< +obj/%.o: src/%.cpp + $(MKDIR_FIRST) + ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $< + +obj/%/autolist.d: $(filter-out %/autolist.d,${DEPENDS}) + echo $@: $(filter %_test.d,$^) > $@ +include ${DEPENDS} + +# I'm not convinced keeping the bin/ is a good idea +# TODO - for development, regenerate -gdb.py even if the binary +# doesn't need to be rebuilt. For release, the version forces rebuild. +bin/%: + $(MKDIR_FIRST) + ${CXX} ${LDFLAGS} $^ ${LDLIBS} -o $@ + cat ${SRC_DIR}/src/main-gdb-head.py \ + $(wildcard $(patsubst obj/%.o,${SRC_DIR}/src/%.py,$^)) \ + ${SRC_DIR}/src/main-gdb-tail.py \ + > $@-gdb.py + +${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) + ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $< + +test: $(patsubst bin/%,.run-%,${TEST_BINARIES}) +.run-%: bin/% + $< + +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} + 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 $*)"' | maybe-replace $@ +FORCE: ; +override CPPFLAGS += -I . + +# distribution tarballs +# this only works from within a git checkout +dist/%/version.make: + $(MKDIR_FIRST) + 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 archive --prefix=$*/ -o $@ HEAD + ( cd dist && tar uf $*-src.tar --mtime="$$(git log -n1 --pretty=%cd)" --mode=664 --owner=root --group=root $*/version.make ) + rm dist/$*/version.make + rmdir dist/$*/ +dist/%-attoconf-only.tar: + $(MKDIR_FIRST) + git --git-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 + +# lpp and ypp are (currently) very slow, so do them first (parallel) +format: format-lpp format-ypp format-cpp format-hpp +format-cpp: $(patsubst src/%,obj/%.formatted,${REAL_SOURCES}) +format-hpp: $(patsubst src/%,obj/%.formatted,${REAL_HEADERS}) +format-lpp: $(patsubst src/%,obj/%.formatted,${LEXERS}) +format-ypp: $(patsubst src/%,obj/%.formatted,${PARSERS}) +obj/%.cpp.formatted: src/%.cpp tools/indenter + $(MKDIR_FIRST) + apply-filter 'indenter -cpp' $< + touch $@ +obj/%.hpp.formatted: src/%.hpp tools/indenter + $(MKDIR_FIRST) + apply-filter 'indenter -cpp' $< + touch $@ +obj/%.tcc.formatted: src/%.tcc tools/indenter + $(MKDIR_FIRST) + apply-filter 'indenter -cpp' $< + touch $@ +obj/%.lpp.formatted: src/%.lpp tools/indenter + $(MKDIR_FIRST) + apply-filter 'indenter -lpp' $< + touch $@ +obj/%.ypp.formatted: src/%.ypp tools/indenter + $(MKDIR_FIRST) + apply-filter 'indenter -ypp' $< + touch $@ +.PHONY: format format-cpp format-hpp format-lpp format-ypp diff --git a/real.make b/real.make deleted file mode 100644 index dd22b2d..0000000 --- a/real.make +++ /dev/null @@ -1,418 +0,0 @@ -## real.make - The One Makefile that builds them all. -## -## Copyright © 2012-2013 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-2013 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 - -ifeq ($(findstring r, $(firstword ${MAKEFLAGS})),) -$(error Missing -r - please do not invoke this makefile directly.) -endif - -ifeq ($(findstring R, $(firstword ${MAKEFLAGS})),) -$(error Missing -R - please do not invoke this makefile directly.) -endif - -ifneq "$(notdir ${MAKEFILE_LIST})" "real.make" -$(error not used as sole toplevel makefile!) -endif - -include Makefile # for variables - this is handled VERY carefully - -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 -LEXERS := $(shell cd ${SRC_DIR}; find src/ -name '*.lpp') -PARSERS := $(shell cd ${SRC_DIR}; find src/ -name '*.ypp') -GEN_SOURCES := \ - $(patsubst %.lpp,%.cpp,${LEXERS}) \ - $(patsubst %.ypp,%.cpp,${PARSERS}) -GEN_HEADERS := \ - $(patsubst %.ypp,%.hpp,${PARSERS}) -REAL_SOURCES := $(shell cd ${SRC_DIR}; find src/ -name '*.cpp') -REAL_HEADERS := $(shell cd ${SRC_DIR}; find src/ -name '*.hpp' -o -name '*.tcc') -REAL_SOURCES := $(filter-out ${GEN_SOURCES},${REAL_SOURCES}) -REAL_HEADERS := $(filter-out ${GEN_HEADERS},${REAL_HEADERS}) -SOURCES := ${GEN_SOURCES} ${REAL_SOURCES} -HEADERS := ${GEN_HEADERS} ${REAL_HEADERS} -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}) -GEN_DEPENDS := $(patsubst src/%.cpp,obj/%.d,${GEN_SOURCES}) -GEN_PREPROCESSED := $(patsubst %.d,%.ii,${GEN_DEPENDS}) -GEN_IRS := $(patsubst %.d,%.ll,${GEN_DEPENDS}) -GEN_BITCODES := $(patsubst %.d,%.bc,${GEN_DEPENDS}) -GEN_ASSEMBLED := $(patsubst %.d,%.s,${GEN_DEPENDS}) -GEN_OBJECTS := $(patsubst %.d,%.o,${GEN_DEPENDS}) -MAIN_SOURCES := $(filter %/main.cpp,${SOURCES}) -BINARIES := $(patsubst src/%/main.cpp,bin/tmwa-%,${MAIN_SOURCES}) - -TEST_DEPENDS := $(patsubst src/%/test.cpp,obj/%/autolist.d,$(filter %/test.cpp,${SOURCES})) -DEPENDS += ${TEST_DEPENDS} -TEST_BINARIES := $(patsubst obj/%/autolist.d,bin/test-%,${TEST_DEPENDS}) - -# 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 := $(shell cat $(patsubst %/test.d,%/autolist.d,${1}))) -$(eval more_deps := $(patsubst src/%.hpp,obj/%.d,${more_deps})) - -$(eval more_deps := $(filter ${DEPENDS},${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 -$(foreach exe,${BINARIES},$(eval ${exe}: $(strip $(patsubst %.d,%.o,$(call RECURSIVE_DEPS,$(patsubst bin/tmwa-%,obj/%/main.d,${exe})))))) -$(foreach exe,${TEST_BINARIES},$(eval ${exe}: $(strip $(patsubst %.d,%.o,$(call RECURSIVE_DEPS,$(patsubst bin/test-%,obj/%/test.d,${exe})))))) - -# utility functions for the rules -MKDIR_FIRST = @mkdir -p ${@D} - -# Stuff sensitive to attoconf -CXXFLAGS += ${WARNINGS} -ifeq (${ENABLE_WARNINGS},yes) -WARNINGS := -include ${SRC_DIR}/src/warnings.hpp -endif -${GEN_DEPENDS} ${GEN_PREPROCESSED} ${GEN_IRS} ${GEN_BITCODES} ${GEN_ASSEMBLED} ${GEN_OBJECTS}: override WARNINGS := -# can't just override for generated objects, -# because a generated header might be used for a non-generated object. -override CPPFLAGS += -I ${SRC_DIR}/$(patsubst obj/%,src/%,${@D}) - -# 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 - -# actual rules -vpath %.ypp ${SRC_DIR} -vpath %.lpp ${SRC_DIR} -vpath %.cpp ${SRC_DIR} -vpath %.hpp ${SRC_DIR} -vpath %.tcc ${SRC_DIR} -vpath tools/% ${SRC_DIR} - -.DELETE_ON_ERROR: -.DEFAULT_GOAL := all -# main goals -all: ${BINARIES} -cpp: ${GEN_SOURCES} ${GEN_HEADERS} -ii: ${PREPROCESSED} -ll: ${IRS} -bc: ${BITCODES} -s: ${ASSEMBLED} -o: ${OBJECTS} - -mostlyclean: - rm -rf obj conf-raw -clean: mostlyclean - rm -rf bin -distclean: clean gen-clean -gen-clean: - rm -f ${GEN_SOURCES} ${GEN_HEADERS} - -%.cpp: %.lpp - $(MKDIR_FIRST) - ${FLEX} -o $@ $< -%.cpp %.hpp: %.ypp - $(MKDIR_FIRST) - ${BISON} -d -o $*.cpp $< -ifndef MAKE_RESTARTS -# prevent errors if missing header -obj/%.d: src/%.cpp - $(MKDIR_FIRST) - set -o pipefail; \ - ${CXX} ${CPPFLAGS} -DGENERATING_DEPENDENCIES ${CXXFLAGS} -MG -MP -MM $< \ - -MT '$(patsubst %.d,%.ii,$@) $(patsubst %.d,%.ll,$@) $(patsubst %.d,%.bc,$@) $(patsubst %.d,%.s,$@) $(patsubst %.d,%.o,$@) $@' \ - | sed -e ':again; s:/[^/. ]*/\.\./:/:; t again' \ - -e 's: ${SRC_DIR}/: :g' \ - > $@ -endif -# the above SRC_DIR replacement is not really safe, but it works okayish. -obj/%.ii: src/%.cpp - $(MKDIR_FIRST) - ${CXX} ${CPPFLAGS} -E -o $@ $< -obj/%.ll: src/%.cpp - $(MKDIR_FIRST) - ${CXX} ${CPPFLAGS} ${CXXFLAGS} -S -emit-llvm -o $@ $< -obj/%.bc: src/%.cpp - $(MKDIR_FIRST) - ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -emit-llvm -o $@ $< -obj/%.s: src/%.cpp - $(MKDIR_FIRST) - ${CXX} ${CPPFLAGS} ${CXXFLAGS} -S -o $@ $< -obj/%.o: src/%.cpp - $(MKDIR_FIRST) - ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $< - -obj/%/autolist.d: $(filter-out %/autolist.d,${DEPENDS}) - echo $@: $(filter %_test.d,$^) > $@ -include ${DEPENDS} - -# I'm not convinced keeping the bin/ is a good idea -# TODO - for development, regenerate -gdb.py even if the binary -# doesn't need to be rebuilt. For release, the version forces rebuild. -bin/%: - $(MKDIR_FIRST) - ${CXX} ${LDFLAGS} $^ ${LDLIBS} -o $@ - cat ${SRC_DIR}/src/main-gdb-head.py \ - $(wildcard $(patsubst obj/%.o,${SRC_DIR}/src/%.py,$^)) \ - ${SRC_DIR}/src/main-gdb-tail.py \ - > $@-gdb.py - -${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) - ${CXX} ${CPPFLAGS} ${CXXFLAGS} -c -o $@ $< - -test: $(patsubst bin/%,.run-%,${TEST_BINARIES}) -.run-%: bin/% - $< - -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} - 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 $*)"' | maybe-replace $@ -FORCE: ; -override CPPFLAGS += -I . - -# distribution tarballs -# this only works from within a git checkout -dist/%/version.make: - $(MKDIR_FIRST) - 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 archive --prefix=$*/ -o $@ HEAD - ( cd dist && tar uf $*-src.tar --mtime="$$(git log -n1 --pretty=%cd)" --mode=664 --owner=root --group=root $*/version.make ) - rm dist/$*/version.make - rmdir dist/$*/ -dist/%-attoconf-only.tar: - $(MKDIR_FIRST) - git --git-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 - -# lpp and ypp are (currently) very slow, so do them first (parallel) -format: format-lpp format-ypp format-cpp format-hpp -format-cpp: $(patsubst src/%,obj/%.formatted,${REAL_SOURCES}) -format-hpp: $(patsubst src/%,obj/%.formatted,${REAL_HEADERS}) -format-lpp: $(patsubst src/%,obj/%.formatted,${LEXERS}) -format-ypp: $(patsubst src/%,obj/%.formatted,${PARSERS}) -obj/%.cpp.formatted: src/%.cpp tools/indenter - $(MKDIR_FIRST) - apply-filter 'indenter -cpp' $< - touch $@ -obj/%.hpp.formatted: src/%.hpp tools/indenter - $(MKDIR_FIRST) - apply-filter 'indenter -cpp' $< - touch $@ -obj/%.tcc.formatted: src/%.tcc tools/indenter - $(MKDIR_FIRST) - apply-filter 'indenter -cpp' $< - touch $@ -obj/%.lpp.formatted: src/%.lpp tools/indenter - $(MKDIR_FIRST) - apply-filter 'indenter -lpp' $< - touch $@ -obj/%.ypp.formatted: src/%.ypp tools/indenter - $(MKDIR_FIRST) - apply-filter 'indenter -ypp' $< - touch $@ -.PHONY: format format-cpp format-hpp format-lpp format-ypp -- cgit v1.2.3-60-g2f50