summaryrefslogtreecommitdiff
path: root/Makefile.src.in
blob: 5f29136bd19060f4a90218bb5d638fb180328731 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# $Id$

# This file is part of OpenTTD.
# OpenTTD 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, version 2.
# OpenTTD 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 OpenTTD. If not, see <http://www.gnu.org/licenses/>.

CC_HOST        = !!CC_HOST!!
CXX_HOST       = !!CXX_HOST!!
CC_BUILD       = !!CC_BUILD!!
CXX_BUILD      = !!CXX_BUILD!!
WINDRES        = !!WINDRES!!
STRIP          = !!STRIP!!
CFLAGS         = !!CFLAGS!!
CFLAGS_BUILD   = !!CFLAGS_BUILD!!
CXXFLAGS       = !!CXXFLAGS!!
CXXFLAGS_BUILD = !!CXXFLAGS_BUILD!!
LIBS           = !!LIBS!!
LDFLAGS        = !!LDFLAGS!!
LDFLAGS_BUILD  = !!LDFLAGS_BUILD!!
ROOT_DIR       = !!ROOT_DIR!!
BIN_DIR        = !!BIN_DIR!!
LANG_DIR       = !!LANG_DIR!!
SRC_OBJS_DIR   = !!SRC_OBJS_DIR!!
LANG_OBJS_DIR  = !!LANG_OBJS_DIR!!
SETTING_OBJS_DIR= !!SETTING_OBJS_DIR!!
SRC_DIR        = !!SRC_DIR!!
SCRIPT_SRC_DIR = !!SCRIPT_SRC_DIR!!
MEDIA_DIR      = !!MEDIA_DIR!!
TTD            = !!TTD!!
STRGEN         = !!STRGEN!!
ENDIAN_CHECK   = !!ENDIAN_CHECK!!
DEPEND         = !!DEPEND!!
ENDIAN_FORCE   = !!ENDIAN_FORCE!!
OS             = !!OS!!
STAGE          = !!STAGE!!
MAKEDEPEND     = !!MAKEDEPEND!!
CFLAGS_MAKEDEP = !!CFLAGS_MAKEDEP!!
SORT           = !!SORT!!
REVISION       = !!REVISION!!
AWK            = !!AWK!!
CONFIG_CACHE_COMPILER = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_COMPILER!!
CONFIG_CACHE_LINKER   = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_LINKER!!
CONFIG_CACHE_ENDIAN   = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_ENDIAN!!
CONFIG_CACHE_SOURCE   = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_SOURCE!!
CONFIG_CACHE_VERSION  = $(SRC_OBJS_DIR)/!!CONFIG_CACHE_VERSION!!

OBJS_C   := !!OBJS_C!!
OBJS_CPP := !!OBJS_CPP!!
OBJS_MM  := !!OBJS_MM!!
OBJS_RC  := !!OBJS_RC!!
OBJS     := $(OBJS_C) $(OBJS_CPP) $(OBJS_MM) $(OBJS_RC)
SRCS     := !!SRCS!!

# All C-files depend on those 3 files
FILE_DEP := $(CONFIG_CACHE_COMPILER) endian_target.h
# Create all dirs and subdirs
RES      := $(shell mkdir -p $(BIN_DIR) $(sort $(dir $(OBJS))))

# Make sure endian_target.h is reasable as if it was in the src/ dir
CFLAGS += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SETTING_OBJS_DIR)
CFLAGS_MAKEDEP += -I $(SRC_OBJS_DIR) -I $(LANG_OBJS_DIR) -I $(SETTING_OBJS_DIR)
ifdef SCRIPT_SRC_DIR
	CFLAGS_MAKEDEP += -I $(SCRIPT_SRC_DIR)
endif

ENDIAN_TARGETS := endian_target.h $(ENDIAN_CHECK)

# Check if we want to show what we are doing
ifdef VERBOSE
	Q =
	E = @true
else
	Q = @
	E = @echo
endif

# Our default target
all: $(BIN_DIR)/$(TTD)

# This are 2 rules that are pointing back to STRGEN stuff.
#  There is not really a need to have them here, but in case
#  some weirdo wants to run 'make' in the 'src' dir and expects
#  the languages to be recompiled, this catches that case and
#  takes care of it nicely.
$(LANG_OBJS_DIR)/$(STRGEN):
	$(MAKE) -C $(LANG_OBJS_DIR) $(STRGEN)

$(LANG_OBJS_DIR)/table/strings.h: $(LANG_DIR)/english.txt $(LANG_OBJS_DIR)/$(STRGEN)
	$(MAKE) -C $(LANG_OBJS_DIR) table/strings.h

# Always run version detection, so we always have an accurate modified
# flag
VERSIONS := $(shell AWK="$(AWK)" "$(ROOT_DIR)/findversion.sh")
MODIFIED := $(shell echo "$(VERSIONS)" | cut -f 3 -d'	')

ifdef REVISION
# Use specified revision (which should be of the form "r000").
REV := $(REVISION)
REV_NR := $(shell echo $(REVISION) | sed "s@[^0-9]@@g")
else
# Use autodetected revisions
REV      := $(shell echo "$(VERSIONS)" | cut -f 1 -d'	')
REV_NR   := $(shell echo "$(VERSIONS)" | cut -f 2 -d'	')
endif

# Make sure we have something in REV and REV_NR
ifeq ($(REV),)
REV := norev000
endif
ifeq ($(REV_NR),)
REV_NR := 0
endif

# This helps to recompile if flags change
RES := $(shell if [ "`cat $(CONFIG_CACHE_COMPILER) 2>/dev/null`" != "$(CFLAGS) $(CXXFLAGS)" ]; then echo "$(CFLAGS) $(CXXFLAGS)" > $(CONFIG_CACHE_COMPILER); fi )
RES := $(shell if [ "`cat $(CONFIG_CACHE_LINKER) 2>/dev/null`" != "$(LDFLAGS) $(LIBS)" ]; then echo "$(LDFLAGS) $(LIBS)" > $(CONFIG_CACHE_LINKER); fi )
RES := $(shell if [ "`cat $(CONFIG_CACHE_ENDIAN) 2>/dev/null`" != "$(ENDIAN_FORCE)" ]; then echo "$(ENDIAN_FORCE)" > $(CONFIG_CACHE_ENDIAN); fi )

# If there is a change in the source-file-list, make sure we recheck the deps
RES := $(shell if [ "`cat $(CONFIG_CACHE_SOURCE) 2>/dev/null`" != "$(SRCS)" ]; then echo "$(SRCS)" > $(CONFIG_CACHE_SOURCE); fi )
# If there is a change in the revision, make sure we recompile rev.cpp
RES := $(shell if [ "`cat $(CONFIG_CACHE_VERSION) 2>/dev/null`" != "$(REV) $(MODIFIED)" ]; then echo "$(REV) $(MODIFIED)" > $(CONFIG_CACHE_VERSION); fi )

ifndef MAKEDEPEND
# The slow, but always correct, dep-check
DEP_MASK := %.d
DEPS     := $(OBJS:%.o=%.d)

# Only include the deps if we are compiling everything
ifeq ($(filter $(ENDIAN_TARGETS) %.o clean mrproper, $(MAKECMDGOALS)),)
-include $(DEPS)
else
# In case we want to compile a single target, include the .d file for it
ifneq ($(filter %.o, $(MAKECMDGOALS)),)
SINGLE_DEP := $(filter %.o, $(MAKECMDGOALS))
-include $(SINGLE_DEP:%.o=%.d)
endif
endif

# Find the deps via GCC. Rarely wrong, but a bit slow

$(OBJS_C:%.o=%.d): %.d: $(SRC_DIR)/%.c $(FILE_DEP)
	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.c=%.c)'
	$(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@

$(OBJS_CPP:%.o=%.d): %.d: $(SRC_DIR)/%.cpp $(FILE_DEP)
	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.cpp=%.cpp)'
	$(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@

$(OBJS_MM:%.o=%.d): %.d: $(SRC_DIR)/%.mm $(FILE_DEP)
	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)'
	$(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@

$(OBJS_RC:%.o=%.d): %.d: $(SRC_DIR)/%.rc $(FILE_DEP)
	$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.rc=%.rc)'
	$(Q)touch $@

else
# The much faster, but can be wrong, dep-check
DEP_MASK :=
DEPS     := Makefile.dep

# Only include the deps if we are not cleaning
ifeq ($(filter $(ENDIAN_TARGETS) depend clean mrproper, $(MAKECMDGOALS)),)
-include Makefile.dep
endif

ifeq ("$(SRC_OBJS_DIR)/$(DEPEND)","$(MAKEDEPEND)")
DEP := $(MAKEDEPEND)
$(SRC_OBJS_DIR)/$(DEPEND): $(SRC_DIR)/depend/depend.cpp
	$(E) '$(STAGE) Compiling and linking $(DEPEND)'
	$(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $(LDFLAGS_BUILD) -o $@ $<
endif

# Make sure that only 'make depend' ALWAYS triggers a recheck
ifeq ($(filter depend, $(MAKECMDGOALS)),)
Makefile.dep: $(FILE_DEP) $(SRCS:%=$(SRC_DIR)/%) $(CONFIG_CACHE_SOURCE) $(DEP)
else
Makefile.dep: $(FILE_DEP) $(SRCS:%=$(SRC_DIR)/%) $(DEP) FORCE
endif
	$(E) '$(STAGE) DEP CHECK (all files)'
	$(Q)rm -f Makefile.dep.tmp
	$(Q)touch Makefile.dep.tmp

# Calculate the deps via makedepend
	$(Q)$(MAKEDEPEND) -f$(SRC_OBJS_DIR)/Makefile.dep.tmp -o.o -Y -v -- $(CFLAGS_MAKEDEP) -- $(SRCS:%=$(SRC_DIR)/%) 2>/dev/null

# Convert x:/... paths to /x/... for mingw
ifeq ($(OS), MINGW)
	@cat Makefile.dep.tmp | sed 's@/\([a-zA-Z]\):\/@\/\1\/@g' > Makefile.dep.tmp.mingw
	@cp Makefile.dep.tmp.mingw Makefile.dep.tmp
	@rm -f Makefile.dep.tmp.mingw
endif

# Remove all comments and includes that don't start with $(SRC_DIR)
# Remove $(SRC_DIR) from object-file-name
	@$(AWK) '                           \
	/^# DO NOT/ { print $$0 ; next}     \
	/^#/ {next}                         \
	/: / {                               \
		left = NF - 1;                    \
		for (n = 2; n <= NF; n++) {       \
			if (match($$n, "^$(ROOT_DIR)") == 0) { \
				$$n = "";                     \
				left--;                       \
			}                               \
		}                                 \
		gsub("$(SRC_DIR)/", "", $$1);     \
		if (left > 0) {                   \
			print $$0;                      \
			$$1 = "Makefile.dep:";          \
			print $$0;                      \
		}                                 \
		next                              \
	}                                   \
	{                                   \
		print $$0                         \
	}                                   \
	' < Makefile.dep.tmp | sed 's@  *@ @g;s@ $$@@' | $(SORT) > Makefile.dep

	$(Q)rm -f Makefile.dep.tmp Makefile.dep.tmp.bak

endif

# Avoid problems with deps if a .h/.hpp/.hpp.sq file is deleted without the deps
#  being updated. Now the Makefile continues, the deps are recreated
#  and all will be fine.
%.h %.hpp %.hpp.sq:
	@true


# Compile all the files according to the targets

$(OBJS_C): %.o: $(SRC_DIR)/%.c $(DEP_MASK) $(FILE_DEP)
	$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.c=%.c)'
	$(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $<

$(OBJS_CPP): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP)
	$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.cpp=%.cpp)'
	$(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -o $@ $<

$(OBJS_MM): %.o: $(SRC_DIR)/%.mm $(DEP_MASK) $(FILE_DEP)
	$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.mm=%.mm)'
	$(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $<

$(OBJS_RC): %.o: $(SRC_DIR)/%.rc $(FILE_DEP)
	$(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)'
	$(Q)$(WINDRES) -o $@ -I `basename $<` $<

$(BIN_DIR)/$(TTD): $(TTD)
	$(Q)cp $(TTD) $(BIN_DIR)/$(TTD)
ifeq ($(OS), UNIX)
	$(Q)cp $(MEDIA_DIR)/openttd.32.bmp $(BIN_DIR)/data/
endif
ifeq ($(OS), OSX)
	$(Q)cp $(ROOT_DIR)/os/macosx/splash.png $(BIN_DIR)/data/
endif

$(TTD): $(OBJS) $(CONFIG_CACHE_LINKER)
	$(E) '$(STAGE) Linking $@'
ifeq ($(OS), PSP)
	# Because of a bug in the PSP GCC tools, linking via CXX results
	#  in total chaos and more problems then you can handle. So we need
	#  CC to link OpenTTD for PSP
	$(Q)+$(CC_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
else
	$(Q)+$(CXX_HOST) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
endif
ifdef STRIP
	$(Q)$(STRIP) $@
endif
ifeq ($(OS), DOS)
	$(E) '$(STAGE) Adding CWSDPMI stub to $@'
	$(Q)$(ROOT_DIR)/os/dos/make_dos_binary_selfcontained.sh $(SRC_OBJS_DIR)/$@
endif

# The targets to compile the endian-code

endian_target.h: $(ENDIAN_CHECK) $(CONFIG_CACHE_ENDIAN)
	$(E) '$(STAGE) Testing endianness for target'
	$(Q)./$(ENDIAN_CHECK) $(ENDIAN_FORCE) > $@

$(ENDIAN_CHECK): $(SRC_DIR)/endian_check.cpp
	$(E) '$(STAGE) Compiling and Linking $@'
	$(Q)$(CXX_BUILD) $(CFLAGS_BUILD) $(CXXFLAGS_BUILD) $< -o $@

# Revision files

$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/rev.cpp.in
	$(Q)cat $(SRC_DIR)/rev.cpp.in      | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!MODIFIED!!@$(MODIFIED)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/rev.cpp

$(SRC_DIR)/os/windows/ottdres.rc: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/os/windows/ottdres.rc.in
	$(Q)cat $(SRC_DIR)/os/windows/ottdres.rc.in | sed "s@\!\!REVISION\!\!@$(REV_NR)@g;s@!!VERSION!!@$(REV)@g;s@!!DATE!!@`date +%d.%m.%y`@g" > $(SRC_DIR)/os/windows/ottdres.rc

FORCE:

depend: $(DEPS)

clean:
	$(E) '$(STAGE) Cleaning up object files'
	$(Q)rm -f $(DEPS) $(OBJS) $(TTD) $(DEPEND) $(TTD:%=$(BIN_DIR)/%) $(CONFIG_CACHE_COMPILER) $(CONFIG_CACHE_LINKER) $(CONFIG_CACHE_ENDIAN) $(CONFIG_CACHE_SOURCE) $(ENDIAN_TARGETS)

mrproper: clean
	$(Q)rm -f $(SRC_DIR)/rev.cpp $(SRC_DIR)/os/windows/ottdres.rc

%.o:
	@echo '$(STAGE) No such source-file: $(@:%.o=%).[c|cpp|mm|rc]'

.PHONY: all mrproper depend clean FORCE