summaryrefslogblamecommitdiff
path: root/Makefile.in
blob: 894165edf22f8d152e68ff8b94c1d39dada60f42 (plain) (tree)
1
2
3
4
5
6
7
8
9
10



                           
                 


                             

                       




                         
                                             

                                 
                                                   

                         
                                             











                                 
                     
 

               
 

                     

                   


                       
           
 
                                   
                         
                                           
                             
                             
                               
 

           

 






























































































                                                                              











                               




                                            




                                                                                                                      

           






                                                                          

                                                 
                      


                                                 
            
                                                               
                                                                                         
                                                      
                                               

                          
                                                                                        

                                                                                                          
                                                   
                                              
                                                                       
                                                                    
                                                                       

                                                                                      




                                                   

                                                 
                                               
                                             
                                               

                                                           
                                                                        
                                                                                         


                                                                                                  
 




                                                                              




                                                                         
                                                                      




                                                                           

                                                         
                                                                                                                                      
                                                                            

                                                           
                                                              

     
 





                                                                         
                   
                                
                                                        
 
                                      


                                           
                                                   




                                 
                       


                                                

                          

                           







                                                             
     




                                         























                                                                                     








                                                 


                                                                        








                                                                                                                                                                                                 
                                                                                                                                                                         



                                                                                        


                                                                                                                   

 
                                                                                                                                                                            
                  
                                                                                                                                     

                                                                                                                                                        
 
                                                                                                                                                                       
                  
                                                                                                                                                                        
                            


                                                                                                                                                                                          
 
                                                                                                                                                                             
                  
                                                                                                                                        




                                                                                                                                                                                              
                                                                                                                                            




                                                                                                                                                                                       
                                                                                                                                            

                                                                                                                                                               

 



                              
                        
                         



                    
            
               
                






                                                                     



                   



                                                                           
 
            
                       
           
                                        
             
                                                
          
                                        
           
                          
                       
                           
                  
                         
                          
          
                                      

                                             
                                                
 
                    
                                          
                      

                                                                          
                                                
                     



                                                                         
                                         

                      
                                                                

                      
                                                                

                      
                                                     
                      
                      
                                                     


                                                           
                            
                      
                                                                                 
                
 
                                                       
                      


                                                                    
                


                                                                

                                                                          
 








                                                                                                             

                                                   



                      
 
                                                           

                     


                                                                                                                                         
                      
                                                     
 
                                                              
                                                                               
                                                    
                                                                                                                                                            
                                      
                                         
                


                                                              
 
                 
                                                                           
 
                
                                                                           
 
                
                                                                           
 
                                                                                                                                    




                                 
                                  
                      
                                 
                
 
                  
                              
 

















                                                                                                                                                                                                                                                                 
                  


                                  


                               

                                 




                                          


                                                                        



                                         
 

                    
                                    
                                          
                           


                                                            

                                                                             
            



                                                



                                            
 





                                                           
                                                  


                                                             


                                          




                                                       
 

                        


                                                           

                                                                   




                                             

                      
                                   


                                                        




                                           

                     
                               



                                                        




                                          

                     
                                       



                                                           




                                           
                           
                                                                            




                                                    




                                                          
                                                         



                        
                                                                 

                       
                                                             
        
             
                                               




                                            
                                                                 


                                                                              
                                                                     
                                                                                                                                                                                   



                               
                                                                                                 


                                                           
                           



                                                                                            
 
                                                                                   
                  
                                                     










                                                                                                     

            
                             


                                                               

                                       
                             
                                
                                 

                                           
                
                                               

                                       
                             
                                
                                                                                              
                                                                                                  

                                           
                                    
                
                                               

                                       
                             
                                

                                           
                
                                    
 







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

include ${SRC_DIR}/version.make

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.make >&2)
stamp/generated.stamp:
	# if you get here, the shell above failed
	false

# path lists
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++0x
else
override CXX += -std=c++0x
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)
$(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}.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}

.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 $@ $<
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

# This isn't perfect.
$(filter %_test.pdc.o,${PDC_OBJECTS}) obj/gtest_main.pdc.o obj/gtest-all.pdc.o: override CPPFLAGS += -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 'python2.7 file_to_load = "$<"' -x ${SRC_DIR}/tools/debug-debug.gdb --args false
${DTEST_STAMPS}: tools/debug-debug.gdb
ifeq '$(findstring clang,${CXX})' 'clang'
${DTEST_STAMPS}:
	@echo "Error: sorry, but clang can't be used with gdb"
	-false
endif

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 ${<D}/fwd.hpp; then continue; fi; echo fgrep -q $${inc}/fwd.hpp ${<D}/fwd.hpp; fgrep -q $${inc}/fwd.hpp ${<D}/fwd.hpp || { echo ${<D}/fwd.hpp:''23: error: No $${inc}/fwd.hpp; exit 1; }; done
	touch $@

test: test-check-fwd
test-check-fwd: ${CHECK_FWDS}
stamp/%.fwdcheck: src/%/fwd.hpp
	$(MKDIR_FIRST)
	types=$$(grep -o '\(enum \|class \| struct \|union \)\+[A-Za-z_0-9]\+;$$' $< | sed 's/\(;\|enum \|class \|struct \|union \)//g'); \
	    for t in $$types; do echo grep -q $$t $(filter-out %/fwd.hpp,$(wildcard ${<D}/*.hpp)); grep -qw '\(enum \|class \|struct \|union \)'$$t $(filter-out %/fwd.hpp,$(wildcard ${<D}/*.hpp)) || { grep -Hnw $$t';$$' $<; exit 1; }; done
	includes=$$(grep -o '#include.*".*/fwd\.hpp"' $< | sed 's:^[^"]*"::;s:/[^/]*"$$:/:'); \
	    for inc in $$includes; do echo fgrep -q $$inc $(filter-out %/fwd.hpp,$(wildcard ${<D}/*.hpp ${<D}/*.tcc ${<D}/*.cpp)); fgrep -q $$inc $(filter-out %/fwd.hpp,$(wildcard ${<D}/*.hpp ${<D}/*.tcc ${<D}/*.cpp)) || { grep -Hn $$inc $<; exit 1; }; done
	touch $@

install := install
install_exe := ${install}
install_dir := ${install} -d
install_data := ${install} -m 0644

install:
	@echo = Done installing
uninstall:
	@echo = Done uninstalling

install: install-bin
install-bin:
	@echo + Installing binaries
	${install_dir} ${DESTDIR}${BINDIR}
	for exe in $(patsubst bin/%.elf,%,${BINARIES}); do \
	${install_exe} -T bin/$${exe}.elf ${DESTDIR}${BINDIR}/$${exe}; \
	done
uninstall: uninstall-bin
uninstall-bin:
	@echo - Uninstalling binaries
	-rm ${DESTDIR}${BINDIR}/${tmwa}-*

install: install-lib
install-lib:
	@echo + Installing libraries
	${install_dir} ${DESTDIR}${LIBDIR}
ifeq (${ENABLE_SHARED},yes)
	${install_data} -t ${DESTDIR}${LIBDIR} \
	    $(patsubst %.so,%.${SO_LONG},${LIBRARIES})
	for lib in $(patsubst lib/%.so,%,${LIBRARIES}); do \
	    ln -sfT $$lib.${SO_LONG} ${DESTDIR}${LIBDIR}/$$lib.${SO_SHORT}; \
	    ln -sfT $$lib.${SO_SHORT} ${DESTDIR}${LIBDIR}/$$lib.so; \
	done
else
	${install_data} -t ${DESTDIR}${LIBDIR} \
	    ${LIBRARIES}
endif
uninstall: uninstall-lib
uninstall-lib:
	@echo - Uninstalling libraries
	-rm ${DESTDIR}${LIBDIR}/lib${tmwa}-*

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 %.elf,%-gdb.py,${BINARIES})
	${install_dir} ${DESTDIR}${DEBUGDIR}${LIBDIR}
	${install_data} -t ${DESTDIR}${DEBUGDIR}${LIBDIR} \
	    $(patsubst %.so,%.${SO_LONG}-gdb.py,${LIBRARIES})
else
	@echo - Not installing debug files
endif
uninstall: uninstall-debug
uninstall-debug: uninstall-lib uninstall-bin
	@echo - Maybe uninstalling debug files
	-rm ${DESTDIR}${DEBUGDIR}${BINDIR}/${tmwa}-*
	-rm ${DESTDIR}${DEBUGDIR}${LIBDIR}/lib${tmwa}-*

install: install-include
install-include:
	@echo + Installing headers
	${install_dir} ${DESTDIR}${PACKAGEINCLUDEDIR}
	${install_data} -t ${DESTDIR}${PACKAGEINCLUDEDIR} \
	    $(addprefix ${SRC_DIR}/,$(filter include/%,${HEADERS}))

uninstall: uninstall-include
uninstall-include:
	@echo - Uninstalling headers
	-rm -r ${DESTDIR}${PACKAGEINCLUDEDIR}

install: install-state
install-state:
	@echo + Installing statedir
	${install_dir} ${DESTDIR}${PACKAGELOCALSTATEDIR}
	touch ${DESTDIR}${PACKAGELOCALSTATEDIR}/.keep

uninstall: uninstall-state
uninstall-state:
	@echo '*' Not uninstalling statedir
	: ${DESTDIR}${PACKAGELOCALSTATEDIR}

install: install-data
install-data:
	@echo + Installing data
	${install_dir} ${DESTDIR}${PACKAGEDATADIR}
	${install_data} -t ${DESTDIR}${PACKAGEDATADIR} \
	    ${SRC_DIR}/share/tmwa/*

uninstall: uninstall-data
uninstall-data:
	@echo - Uninstalling data
	-rm -r ${DESTDIR}${PACKAGEDATADIR}

install: install-conf
install-conf:
	@echo + Installing config files
	${install_dir} ${DESTDIR}${PACKAGESYSCONFDIR}
	${install_data} -t ${DESTDIR}${PACKAGESYSCONFDIR} \
	    ${SRC_DIR}/etc/tmwa/*

uninstall: uninstall-conf
uninstall-conf:
	@echo Not uninstalling config files
	: ${DESTDIR}${PACKAGESYSCONFDIR}

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

# 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 . -I ${SRC_DIR}/include

# 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/%-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})