summaryrefslogblamecommitdiff
path: root/Makefile.in
blob: e2e3bca9daca43d6556b29885e5e4d6b1342f9b9 (plain) (tree)




























                                 
                     















                                                               
                             
 

           

 






























































































                                                                              




                                            




                                                                                                                      

           







                                                                          

                                                                                
                                                      

                          


                                                                       





                                                   
                                               
                                               
                                                                 
                                                                      











                                                                           

                                                         
 
                                                            

                                                           
                                                              

     
 











                                                                         
                                                   




                                 
                       


                                                











                                                             
     




                                         







































                                                                                                                                                                                                 



                        
                     




                    





                   







                                        
                  
                     
                          
            
 
                    

                      

                                                                          
                                                
                     



                                                                         
                                         

                      
                                                                

                      
                                                                

                      
                                                     

                      
                                                     
 
                                                   
             
                      
                                             
                
                                             



                                                                          







                                                                                                        
                                                     


                                               
                                 









































                                                                           
                                                                            



















                                                                
                                                            
        
             





                                            
                                                                 


                                                                              
                                                                     
                                                                                                                                                                                   



                               
                                                                                                 






                                                                             
                             

                                                             


                                             
                             
                                
                                 



                                             
                             
                                
                                                                                              
                                                                                                  



                                             
                             
                                
                
                                    
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 <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

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-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 $<
	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
	touch $@
obj/%.tcc.formatted: src/%.tcc tools/indenter
	$(MKDIR_FIRST)
	apply-filter 'indenter -cpp' $<
	fgrep -q Copyright $<
	fgrep -q $(notdir $<) $<
	touch $@
.PHONY: format format-cpp format-hpp