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 --- Makefile.in | 418 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 408 insertions(+), 10 deletions(-) (limited to 'Makefile.in') 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 -- cgit v1.2.3-60-g2f50