summaryrefslogtreecommitdiff
path: root/rules/build-prog.mk
blob: d362d4299f1c235d03b495d9dc8b5f74bb36ba46 (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
311
312
313
# -----------------------------------------------------------------------------
#
# (c) 2009 The University of Glasgow
#
# This file is part of the GHC build system.
#
# To understand how the build system works and how to modify it, see
#      http://hackage.haskell.org/trac/ghc/wiki/Building/Architecture
#      http://hackage.haskell.org/trac/ghc/wiki/Building/Modifying
#
# -----------------------------------------------------------------------------


# Build a program.  Invoke like this:
#
# utils/genapply_MODULES = Main
# utils/genapply_HC_OPTS = -package Cabal
# utils/genapply_dist_PROGNAME = genapply
#
# $(eval $(call build-prog,utils/genapply,dist-install,1))

define build-prog
$(call trace, build-prog($1,$2,$3))
$(call profStart, build-prog($1,$2,$3))
# $1 = dir
# $2 = distdir
# $3 = GHC stage to use (0 == bootstrapping compiler)

ifneq "$$(CLEANING)" "YES"
ifeq "$$($1_$2_PROGNAME)" ""
$$(error $1_$2_PROGNAME is not set)
endif
ifneq "$$($1_$2_PROG)" ""
$$(error $1_$2_PROG is set)
endif
$1_$2_PROG = $$($1_$2_PROGNAME)$$(exeext$3)
endif

ifeq "$$(findstring $3,0 1 2)" ""
$$(error $1/$2: stage argument to build-prog should be 0, 1, or 2)
endif

$(call clean-target,$1,$2,$1/$2)

$$(eval $$(call build-prog-vars,$1,$2,$3))

ifneq "$$($1_$2_NOT_NEEDED)" "YES"
$$(eval $$(call build-prog-helper,$1,$2,$3))
endif
$(call profEnd, build-prog($1,$2,$3))
endef


define build-prog-vars
# $1 = dir
# $2 = distdir
# $3 = GHC stage to use (0 == bootstrapping compiler)

ifeq "$$($1_USES_CABAL)" "YES"
$1_$2_USES_CABAL = YES
endif

ifeq "$$(Windows_Host)" "YES"
$1_$2_WANT_INPLACE_WRAPPER = NO
else ifneq "$$($1_$2_INSTALL_INPLACE)" "YES"
$1_$2_WANT_INPLACE_WRAPPER = NO
else ifeq "$$($1_$2_SHELL_WRAPPER)" "YES"
$1_$2_WANT_INPLACE_WRAPPER = YES
else ifeq "$$(DYNAMIC_GHC_PROGRAMS)" "YES"
$1_$2_WANT_INPLACE_WRAPPER = YES
else
$1_$2_WANT_INPLACE_WRAPPER = NO
endif

ifeq "$$(Windows_Host)" "YES"
$1_$2_WANT_INSTALLED_WRAPPER = NO
else ifneq "$$($1_$2_INSTALL)" "YES"
$1_$2_WANT_INSTALLED_WRAPPER = NO
else ifeq "$$($1_$2_SHELL_WRAPPER)" "YES"
$1_$2_WANT_INSTALLED_WRAPPER = YES
else
$1_$2_WANT_INSTALLED_WRAPPER = NO
endif

$1_$2_depfile_base = $1/$2/build/.depend

ifeq "$$($1_$2_INSTALL_INPLACE)" "NO"
ifeq "$(findstring clean,$(MAKECMDGOALS))" ""
$1_$2_INPLACE = $$(error $1_$2 should not be installed inplace, but INPLACE var evaluated)
else
$1_$2_INPLACE =
endif
else
ifeq "$(findstring clean,$(MAKECMDGOALS))" ""
ifneq "$$($$($1_$2_PROGNAME)_INPLACE)" ""
$$(error $$($1_$2_PROGNAME)_INPLACE defined twice)
endif
endif
ifeq "$$($1_$2_TOPDIR)" "YES"
$$($1_$2_PROGNAME)_INPLACE = $$(INPLACE_TOPDIR)/$$($1_$2_PROG)
else
$$($1_$2_PROGNAME)_INPLACE = $$(INPLACE_BIN)/$$($1_$2_PROG)
endif
# Where do we install the inplace version?
ifeq "$$($1_$2_WANT_INPLACE_WRAPPER)" "YES"
$1_$2_INPLACE = $$(INPLACE_LIB)/bin/$$($1_$2_PROG)
else
$1_$2_INPLACE = $$($$($1_$2_PROGNAME)_INPLACE)
endif
endif

endef

define build-prog-helper
# $1 = dir
# $2 = distdir
# $3 = GHC stage to use (0 == bootstrapping compiler)

$(call package-config,$1,$2,$3)

ifeq "$$($1_$2_USES_CABAL)" "YES"
$(call build-package-data,$1,$2,$3)
ifneq "$$(NO_INCLUDE_PKGDATA)" "YES"
ifeq "$3" "0"
include $1/$2/package-data.mk
else ifeq "$(phase)" "final"
include $1/$2/package-data.mk
endif
endif
endif

$(call all-target,$1,all_$1_$2)
$(call all-target,$1_$2,$1/$2/build/tmp/$$($1_$2_PROG))

# INPLACE_BIN might be empty if we're distcleaning
ifeq "$(findstring clean,$(MAKECMDGOALS))" ""
ifeq "$$($1_$2_INSTALL_INPLACE)" "YES"
$$($1_$2_INPLACE) : $1/$2/build/tmp/$$($1_$2_PROG) | $$$$(dir $$$$@)/.
	"$$(CP)" -p $$< $$@
endif
endif

$(call shell-wrapper,$1,$2)

ifeq "$$($1_$2_PROGRAM_WAY)" ""
ifeq "$3" "0"
$1_$2_PROGRAM_WAY = v
else ifeq "$$(DYNAMIC_GHC_PROGRAMS)" "YES"
$1_$2_PROGRAM_WAY = dyn
else
$1_$2_PROGRAM_WAY = v
endif
endif

$1_$2_WAYS = $$($1_$2_PROGRAM_WAY)

$1_$2_DYNAMIC_TOO = NO

$(call hs-sources,$1,$2)
$(call c-sources,$1,$2)

# --- IMPLICIT RULES

$(call distdir-opts,$1,$2,$3)
$(call distdir-way-opts,$1,$2,$$($1_$2_PROGRAM_WAY),$3)

ifeq "$3" "0"
# For stage 0, we use GHC to compile C sources so that we don't have to
# worry about where the RTS header files are
$(call c-suffix-rules,$1,$2,$$($1_$2_PROGRAM_WAY),YES)
else
ifeq "$$($1_$2_UseGhcForCC)" "YES"
$(call c-suffix-rules,$1,$2,$$($1_$2_PROGRAM_WAY),YES)
else
$(call c-suffix-rules,$1,$2,$$($1_$2_PROGRAM_WAY),NO)
endif
endif

$$(foreach dir,$$($1_$2_HS_SRC_DIRS),\
  $$(eval $$(call hs-suffix-rules-srcdir,$1,$2,$$(dir))))
$(call hs-suffix-way-rules,$1,$2,$$($1_$2_PROGRAM_WAY))

$(call c-objs,$1,$2,$$($1_$2_PROGRAM_WAY))
$(call hs-objs,$1,$2,$$($1_$2_PROGRAM_WAY))

$1_$2_LINK_WITH_GCC = NO

ifeq "$$($1_$2_$$($1_$2_PROGRAM_WAY)_HS_OBJS)" ""
# We don't want to link the GHC RTS into C-only programs. There's no
# point, and it confuses the test that all GHC-compiled programs
# were compiled with the right GHC.
$1_$2_$$($1_$2_PROGRAM_WAY)_GHC_LD_OPTS += -no-auto-link-packages -no-hs-main
endif

ifneq "$$(BINDIST)" "YES"
# The quadrupled $'s here are because the _<way>_LIB variables aren't
# necessarily set when this part of the makefile is read
$1/$2/build/tmp/$$($1_$2_PROG) $1/$2/build/tmp/$$($1_$2_PROG).dll : \
    $$(foreach dep,$$($1_$2_DEPS),\
        $$(if $$(filter ghc%,$$(dep)),\
            $(if $(filter 0,$3),$$(compiler_stage1_PROGRAM_DEP_LIB),\
            $(if $(filter 1,$3),$$(compiler_stage2_PROGRAM_DEP_LIB),\
            $(if $(filter 2,$3),$$(compiler_stage2_PROGRAM_DEP_LIB),\
            $$(error Bad build stage)))),\
        $$$$($$(dep)_dist-$(if $(filter 0,$3),boot,install)_PROGRAM_DEP_LIB)))

$1_$2_PROG_NEEDS_C_WRAPPER = NO
ifeq "$$(Windows_Host) $$($1_$2_PROGRAM_WAY)" "YES dyn"
ifneq "$$($1_$2_HS_SRCS)" ""
$1_$2_PROG_NEEDS_C_WRAPPER = YES
endif
endif

ifeq "$$($1_$2_PROG_NEEDS_C_WRAPPER)" "YES"

$1_$2_RTS_OPTS_FLAG = $$(lastword $$(filter -rtsopts -rtsopts=all -rtsopts=some -rtsopts=none -no-rtsopts,$$($1_$2_$$($1_$2_PROGRAM_WAY)_ALL_HC_OPTS)))
ifeq "$$($1_$2_RTS_OPTS_FLAG)" "-rtsopts"
$1_$2_RTS_OPTS = RtsOptsAll
else ifeq "$$($1_$2_RTS_OPTS_FLAG)" "-rtsopts=all"
$1_$2_RTS_OPTS = RtsOptsAll
else ifeq "$$($1_$2_RTS_OPTS_FLAG)" "-rtsopts=some"
$1_$2_RTS_OPTS = RtsOptsSafeOnly
else ifeq "$$($1_$2_RTS_OPTS_FLAG)" "-rtsopts=none"
$1_$2_RTS_OPTS = RtsOptsNone
else ifeq "$$($1_$2_RTS_OPTS_FLAG)" "-no-rtsopts"
$1_$2_RTS_OPTS = RtsOptsNone
else
$1_$2_RTS_OPTS = RtsOptsSafeOnly
endif

$1/$2/build/tmp/$$($1_$2_PROG)-inplace-wrapper.c: driver/utils/dynwrapper.c | $$$$(dir $$$$@)/.
	$$(call removeFiles,$$@)
	echo '#include <Windows.h>' >> $$@
	echo '#include "Rts.h"' >> $$@
	echo 'LPTSTR path_dirs[] = {' >> $$@
	$$(foreach d,$$($1_$2_DEP_LIB_REL_DIRS),$$(call make-command,echo '    TEXT("$$d")$$(comma)' >> $$@))
	echo '    TEXT("$1/$2/build/tmp/"),' >> $$@
	echo '    NULL};' >> $$@
	echo 'LPTSTR progDll = TEXT("../../$1/$2/build/tmp/$$($1_$2_PROG).dll");' >> $$@
	echo 'LPTSTR rtsDll = TEXT("$$($$(WINDOWS_DYN_PROG_RTS))");' >> $$@
	echo 'int rtsOpts = $$($1_$2_RTS_OPTS);' >> $$@
	cat driver/utils/dynwrapper.c >> $$@

$1/$2/build/tmp/$$($1_$2_PROG) : $1/$2/build/tmp/$$($1_$2_PROG)-inplace-wrapper.c $1/$2/build/tmp/$$($1_$2_PROG).dll | $$$$(dir $$$$@)/.
	$$(call cmd,$1_$2_HC) -no-hs-main -optc-g -optc-O0 $$< -o $$@

$1/$2/build/tmp/$$($1_$2_PROG).dll : $$($1_$2_$$($1_$2_PROGRAM_WAY)_HS_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_C_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_S_OBJS) $$($1_$2_OTHER_OBJS) | $$$$(dir $$$$@)/.
	$$(call build-dll,$1,$2,$$($1_$2_PROGRAM_WAY),,$$($1_$2_$$($1_$2_PROGRAM_WAY)_HS_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_C_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_S_OBJS) $$($1_$2_OTHER_OBJS),$$@)
else
ifeq "$$($1_$2_LINK_WITH_GCC)" "NO"
$1/$2/build/tmp/$$($1_$2_PROG) : $$($1_$2_$$($1_$2_PROGRAM_WAY)_HS_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_C_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_S_OBJS) $$($1_$2_OTHER_OBJS) | $$$$(dir $$$$@)/.
	$$(call cmd,$1_$2_HC) -o $$@ $$($1_$2_$$($1_$2_PROGRAM_WAY)_ALL_HC_OPTS) $$(LD_OPTS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_GHC_LD_OPTS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_HS_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_C_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_S_OBJS) $$($1_$2_OTHER_OBJS) $$(addprefix -l,$$($1_$2_EXTRA_LIBRARIES))
ifeq "$$(TargetOS_CPP)" "darwin"
ifneq "$3" "0"
ifeq "$$($1_$2_PROGRAM_WAY)" "dyn"
# Use relative paths for all the libraries
ifneq "$$($1_$2_TRANSITIVE_DEP_NAMES)" ""
	install_name_tool $$(foreach d,$$($1_$2_TRANSITIVE_DEP_NAMES), -change $$(TOP)/$$($$($$d_INSTALL_INFO)_dyn_LIB) @loader_path/../$$d-$$($$($$d_INSTALL_INFO)_VERSION)/$$($$($$d_INSTALL_INFO)_dyn_LIB_NAME)) $$@
endif
# Use relative paths for the RTS. Rather than try to work out which RTS
# way is being linked, we just change it for all ways
	install_name_tool $$(foreach w,$$(rts_WAYS), -change $$(TOP)/$$(rts_$$w_LIB) @loader_path/../rts-$$(rts_VERSION)/$$(rts_$$w_LIB_NAME)) $$@
endif
endif
endif
else
$1/$2/build/tmp/$$($1_$2_PROG) : $$($1_$2_$$($1_$2_PROGRAM_WAY)_HS_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_C_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_S_OBJS) $$($1_$2_OTHER_OBJS) | $$$$(dir $$$$@)/.
	$$(call cmd,$1_$2_CC) -o $$@ $$($1_$2_$$($1_$2_PROGRAM_WAY)_ALL_CC_OPTS) $$(LD_OPTS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_HS_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_C_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_S_OBJS) $$($1_$2_OTHER_OBJS) $$($1_$2_$$($1_$2_PROGRAM_WAY)_EXTRA_CC_OPTS) $$(addprefix -l,$$($1_$2_EXTRA_LIBRARIES))
endif
endif

# Note [lib-depends] if this program is built with stage1 or greater, we
# need to depend on the libraries too.  NB. since $(ALL_STAGE1_LIBS) and
# $(ALL_RTS_LIBS) are not defined until after libraries/*/ghc.mk have
# been included, this introduces an ordering dependency.
ifneq "$$(CLEANING)" "YES"
ifneq "$3" "0"
ifneq "$$($1_$2_HS_SRCS)" ""
ifeq "$$(strip $$(ALL_STAGE1_LIBS))" ""
$$(error ordering failure in $1 ($2): ALL_STAGE1_LIBS is empty)
endif
$1/$2/build/tmp/$$($1_$2_PROG) : $$(ALL_STAGE1_LIBS) $$(ALL_RTS_LIBS) $$(OTHER_LIBS)
endif
endif
endif
endif

ifneq "$$($1_$2_INSTALL_INPLACE)" "NO"
$(call all-target,$1_$2,$$($1_$2_INPLACE))
endif
$(call clean-target,$1,$2_inplace,$$($1_$2_INPLACE))

ifeq "$$($1_$2_INSTALL)" "YES"
ifeq "$$($1_$2_WANT_INSTALLED_WRAPPER)" "YES"
INSTALL_LIBEXECS += $1/$2/build/tmp/$$($1_$2_PROG)
else ifeq "$$($1_$2_TOPDIR)" "YES"
INSTALL_TOPDIRS  += $1/$2/build/tmp/$$($1_$2_PROG)
else
INSTALL_BINS     += $1/$2/build/tmp/$$($1_$2_PROG)
endif
endif

$(call dependencies,$1,$2,$3)

# The Main module of a program implicitly depends on GHC.TopHandler
# so we need to add a dependency for that. As we don't know which
# module contains Main, we just make all modules in the program
# depend on it.
ifneq "$3" "0"
$$(foreach o,$$($1_$2_$$($1_$2_PROGRAM_WAY)_HS_OBJS),$$(eval $$(call add-dependency,$$o,libraries/base/dist-install/build/GHC/TopHandler.$$($$($1_$2_PROGRAM_WAY)_osuf))))
endif

endef