]> Git — Sourcephile - ocaml/libocaml_make.git/blob - GNUmakefile
Modification : %/dynamic : -noautolink + s/-l%/-l:dll%.so/.
[ocaml/libocaml_make.git] / GNUmakefile
1 # ---------
2 # ocaml env
3 # ---------
4 OCAML_FLAGS?=-w @a-4-6-7-9-23-26-27-29
5 OCAMLCC_FLAGS?=-ccopt -Werror -ccopt -Wall -ccopt -Wextra
6 OCAMLCC_D_FLAGS?=-ccopt -Wno-error
7 override OCAMLDEP_FLAGS:=-ml-synonym .cmi -ml-synonym .mll
8 export OCAMLRUNPARAM
9
10 # --------
11 # make env
12 # --------
13 camlcase=$(shell pack=$1; printf %c $${pack} | tr '[a-z]' '[A-Z]'; printf %s $${pack\#?})
14 filter-flag=$(if $2 \
15 ,$(if $(patsubst $1,,$(firstword $2)), \
16 $(call filter-flag,$1,$(wordlist 2,$(words $2),$2)), \
17 $(wordlist 2,2,$2) $(call filter-flag,$1,$(wordlist 3,$(words $2),$2))) \
18 ,)
19 dllpath-pkg-recursive=$(call filter-flag,-dllpath,$(shell \
20 OCAMLPATH='$(OCAMLPATH)' \
21 OCAMLFIND_COMMANDS='ocamlc=echo' \
22 ocamlfind ocamlc -dllpath-all $1))
23 dirname=$(patsubst %/,%,$(dir $1))
24 filter-dir=$(patsubst %/.,%,$(wildcard $(patsubst %,%/.,$1)))
25 filter-dir-out=$(foreach x,$1,$(if $(call filter-dir,$x),,$x))
26 flock=flock $1 $2 -c "$(subst ",\",$(subst \,\\,$3))"
27 flocks=$(if $2,$(call \
28 flock,$1,$(firstword $2),$(call \
29 flocks,$1,$(wordlist 2,$(words $2),$2),$3)),$3)
30 GNUmakefile.inc?=GNUmakefile.inc
31 if_arg=$(if $2,$1 $2)
32 is_parallel=$(findstring j,$(value MAKEFLAGS))
33 map=$(foreach x,$2,$(call $1,$x))
34 mul=$(foreach p,$1,$(foreach s,$2,$p$s))
35 rev=$(if $1,$(call \
36 rev,$(wordlist 2,$(words $1),$1))) $(firstword $1)
37 uniq=$(if $1,$(call \
38 uniq,$(wordlist 2,$(words $1),$1),$2 $(if \
39 $(filter $(firstword $1),$2),,$(firstword $1)))\
40 ,$2)
41 ,:=,
42 .SECONDARY:
43 .SUFFIXES:
44 MAKEFLAGS += -r
45 .SHELLFLAGS += -e
46
47 # -----
48 # clean
49 # -----
50 rmw=$(call if_arg,rm,$(wildcard $1))
51 clean+=$(or $(filter c,$(MAKECMDGOALS)),$(filter %/c,$(MAKECMDGOALS)),$(filter clean,$(MAKECMDGOALS)),$(filter %/clean,$(MAKECMDGOALS)))
52 cleaner+=$(or $(filter cc,$(MAKECMDGOALS)),$(filter %/cc,$(MAKECMDGOALS)),$(filter cleaner,$(MAKECMDGOALS)),$(filter %/cleaner,$(MAKECMDGOALS)))
53 LIBOCAML_MAKE_NO_DEPS+=$(or $(clean),$(cleaner))
54 %.ml/clean: %.mll
55 $(call rmw,$(@:/clean=))
56 %.ml/clean:
57
58 %.o/clean:
59 $(call rmw,$(@:/clean=) $*.s $(if $(cleaner),$*.d))
60 %.a/clean: %.a.clean
61
62 lib%.a.clean: dll%.so.clean
63 $(call rmw,$(@:.clean=))
64 %.so/clean: %.so.clean
65
66 dll%.so.clean: lib%.so.clean
67 $(call rmw,$(@:.clean=))
68 lib%.so.clean:
69 $(call rmw,$(@:.clean=))
70 %.cm/clean %.cd/clean: %.ml/clean
71 $(call rmw,$*.cmo $*.cmx $*.cmxs $*.o $*.s $*.startup.s $*.cmi $(if $(cleaner),$*.d))
72 %.ca/clean:
73 $(call rmw,$*.cma $*.cmxa $*.a)
74 %.cb/clean:
75 $(call rmw,$*.byte $*.native)
76
77 # ---------------------
78 # ocaml GNUmakefile.inc
79 # ---------------------
80 define make_GNUmakefile.inc
81 d := $1
82 dir_ptr := $$(dir_ptr).level
83 dirstack_$$(dir_ptr) := $$d
84
85 Pack := $$(if $$(Pack),$$(Pack).)$$(call camlcase,$$(notdir $1))
86
87 targets :=
88
89 include $1/$(GNUmakefile.inc)
90
91 ifeq ($$(LIBOCAML_MAKE_NO_DEPS),)
92 -include $$(wildcard $$(o:.o=.d) $$(cm:.cm=.d) $$(cd:.cd=.d))
93 endif
94
95 dirs := $$(call filter-dir,$$(filter-out $1,$$(call uniq,$$(basename $$(targets)))))
96
97 $1/c $1/clean: clean:=clean
98 $1/cc $1/cleaner: cleaner:=cleaner
99 $1/b $1/byte: byte:=byte
100 $1/n $1/native: native:=native
101 $1/all: byte:=byte
102 $1/all: native:=native
103
104 # NOTE: no .PHONY: to trigger %/clean
105 $1/clean: $$(addsuffix /clean,$$(targets))
106 $1/cleaner: $1/clean
107 $1/c: $1/clean
108 $1/cc: $1/cleaner
109
110
111 ifeq ($$(LIBOCAML_MAKE_NO_DEPS),)
112 targets := $$(foreach t,$$(targets), \
113 $$t \
114 $$(if $$(filter %.o,$$t)$$(filter %.cm,$$t)$$(filter %.cd,$$t) \
115 ,$$(if $$(wildcard $$(basename $$t)),,$$(basename $$t).d)))
116 endif
117
118 $1/byte: $$(patsubst %.cb,%.byte, $$(patsubst %.ca,%.cma, $$(patsubst %.cm,%.cmo,$$(patsubst %.cd,%.cmo, $$(targets)))))
119 $1/native: $$(patsubst %.cb,%.native,$$(patsubst %.ca,%.cmxa,$$(patsubst %.cm,%.cmx,$$(patsubst %.cd,%.cmxs,$$(targets)))))
120 $1/all: $1/byte $1/native
121 $1/exec-byte: $$(cb:.cb=.byte.exec)
122 $1/exec-native: $$(cb:.cb=.native.exec)
123 $1/b: $1/byte
124 $1/n: $1/native
125 $1/xb: $1/exec-byte
126 $1/xn: $1/exec-native
127
128 $$(foreach d,$$(dirs), \
129 $$(eval $1/clean: $$d/clean) \
130 $$(eval $1/cleaner: $$d/cleaner) \
131 $$(eval $1/byte: $$d/byte) \
132 $$(eval $1/native: $$d/native) \
133 $$(eval $1/exec-byte: $$d/exec-byte) \
134 $$(eval $1/exec-native: $$d/exec-native) \
135 $$(call include_GNUmakefile.inc,$$d))
136
137 Pack := $$(if $$(findstring .,$$(Pack)),$$(basename $$(Pack)),)
138
139 d := $$(dirstack_$$(dir_ptr))
140 dir_ptr := $$(basename $$(dir_ptr))
141
142 endef
143 include_GNUmakefile.inc = $(eval $(call make_GNUmakefile.inc,$(or $1,.)))
144
145 # ----------
146 # ocaml deps
147 # ----------
148 %.d: %.ml
149 errnos=`{ { ocamlfind ocamldep $(OCAMLDEP_FLAGS) $(OCAML_DEPS_FLAGS) $< || echo >&3 0:$$?; } | \
150 { sed >$@ -e 's/^[^ ]*\.cmx/&s \\\\\n&/' -e 's/ :/:/' || echo >&3 1:$$?; } \
151 } 3>&1` && [ -z "$$errnos" ] || { rm $@ && false; }
152
153 # ------------
154 # ocaml object
155 # ------------
156 o=$(filter %.o,$(targets))
157 %.o: %.c
158 ocamlfind ocamlc -ccopt -o -ccopt $@ -c $(OCAML_FLAGS) $(foreach x,$(CFLAGS),-ccopt $x) $(foreach x,$(LDFLAGS),-cclib $x) $(OCAMLCC_FLAGS) $(if $(DEBUG),-ccopt -Wa$(,)-aln=$*.s) $<
159 %.d: %.c
160 ocamlfind ocamlc -ccopt -o -ccopt $@ -c -nostdlib -ccopt -MM -ccopt -MT"$@\\ $(@:d=o)" -ccopt -MF$@ $(OCAML_FLAGS) $(OCAMLCC_FLAGS) $(OCAMLCC_D_FLAGS) $<
161
162 # -----------
163 # ocaml lexer
164 # -----------
165 %.ml: %.mll
166 ocamllex $<
167 touch -r $< $@ # NOTE: to avoid rebuilding %.d
168
169 # ------------
170 # ocaml module
171 # ------------
172 cm=$(filter %.cm,$(targets))
173 cd=$(filter %.cd,$(targets))
174 lock_ro_cmi=$(if $(and $(byte),$(native),$(is_parallel)),$(call \
175 flocks,-s,$(patsubst %.cmx,%.cmi,$(patsubst %.cmo,%.cmi, \
176 $(filter %.cmi,$^) $(filter %.cmo,$^) $(filter %.cmx,$^))),$1),$1)
177 lock_rw_cmi=$(if $(and $(byte),$(native),$(is_parallel)),$(call \
178 flock,-x,$*.cmi,$(call \
179 flocks,-s,$(patsubst %.cmx,%.cmi,$(patsubst %.cmo,%.cmi, \
180 $(filter %.cmi,$^) $(filter %.cmo,$^) $(filter %.cmx,$^))),$1)),$1)
181 %.cmo %.cmi: %.ml
182 $(call lock_rw_cmi,ocamlfind ocamlc -c $(OCAML_FLAGS) $(OCAML_DEPS_FLAGS) $(OCAMLC_FLAGS) $(filter %.ml,$^))
183 %.cmx %cmi %.o: %.ml
184 $(call lock_rw_cmi,ocamlfind ocamlopt -o $*.cmx -c $(OCAML_FLAGS) $(OCAML_DEPS_FLAGS) $(OCAMLOPT_FLAGS) $(filter %.ml,$^))
185 %.cmxs %.cmx %.cmi %.o: %.ml
186 $(call lock_rw_cmi,ocamlfind ocamlopt -shared -o $*.cmxs $(OCAML_FLAGS) $(OCAML_DEPS_FLAGS) $(OCAMLOPT_FLAGS) $(filter %.ml,$^))
187 # NOTE : remember to install the .cmx files as they enable cross-module optimizations
188
189 # ----------
190 # ocaml pack
191 # ----------
192 %.cmo %.cmi: | %
193 $(call lock_rw_cmi,ocamlfind ocamlc -pack -o $*.cmo $(OCAML_FLAGS) $(OCAMLC_FLAGS) $(OCAMLC_PACK_FLAGS) $(filter %.cmo,$^))
194 %.cmx %.cmi %.o: | %
195 $(call lock_rw_cmi,ocamlfind ocamlopt -pack -o $*.cmx $(OCAML_FLAGS) $(OCAMLOPT_FLAGS) $(OCAMLOPT_PACK_FLAGS) $(filter %.cmx,$^))
196
197 # --------------
198 # object archive
199 # --------------
200 a=$(filter %.a,$(targets))
201 lock_rw_a=$(if $(is_parallel),$(call flock,-x,$(@D),$1),$1)
202 lib%.a dll%.so:
203 $(call lock_rw_a,ocamlfind ocamlmklib -oc $* -failsafe $(OCAMLMKLIB_FLAGS) $(OCAMLMKLIB_OBJECT_FLAGS) $(foreach x,$(LDFLAGS),-ldopt $x) $(filter %.o,$^) \
204 $(if $(STRIP), && strip --strip-unneeded $(STRIP_FLAGS) $(STRIP_LIB_FLAGS) $(@D)/lib$(*F).a \
205 && if [ -e '$(@D)/dll$(*F).so' ]; then strip $(STRIP_FLAGS) $(STRIP_DLL_FLAGS) $(@D)/dll$(*F).so; fi))
206
207 # -------------
208 # ocaml archive
209 # -------------
210 ca=$(filter %.ca,$(targets))
211 %.cma:
212 $(call lock_ro_cmi,ocamlfind ocamlmklib -o $* $(OCAMLMKLIB_FLAGS) $(OCAMLMKLIB_BYTE_FLAGS) $(filter %.cmo,$^))
213 %.cmxa:
214 $(call lock_ro_cmi,ocamlfind ocamlmklib -o $* $(OCAMLMKLIB_FLAGS) $(OCAMLMKLIB_NATIVE_FLAGS) $(filter %.cmx,$^))
215
216 # ------------
217 # ocaml binary
218 # ------------
219 cb=$(filter %.cb,$(targets))
220 %.byte:
221 $(call lock_ro_cmi,ocamlfind ocamlc -o $@ -linkpkg $(OCAML_FLAGS) $(OCAML_DEPS_FLAGS) $(OCAMLC_FLAGS) $(OCAML_BIN_FLAGS) $(OCAMLC_BIN_FLAGS) $(filter %.cmo,$^))
222 %.native:
223 $(call lock_ro_cmi,ocamlfind ocamlopt -o $@ -linkpkg $(OCAML_FLAGS) $(OCAML_DEPS_FLAGS) $(OCAMLOPT_FLAGS) $(OCAML_BIN_FLAGS) $(OCAMLOPT_BIN_FLAGS) $(filter %.cmx,$^) \
224 $(if $(STRIP), && strip $(STRIP_FLAGS) $(STRIP_NATIVE_FLAGS) $@))
225
226 # -------------
227 # ocaml linking
228 # -------------
229 ocaml_stublibs/=$(abspath $d/stublibs)
230 %/dynamic: export LINKING_MODE=dynamic
231 %/dynamic: ,ocaml-predicates= \
232 $(patsubst -thread,$(,)mt$(,)mt_posix threads.posix,$(filter -thread,$(OCAML_DEPS_FLAGS)))
233 %/dynamic: ocaml-packages= \
234 $(shell OCAMLPATH='$(OCAMLPATH)' ocamlfind query -recursive -format %p \
235 -predicates byte$(,ocaml-predicates) \
236 $(call filter-flag,-package,$(OCAML_DEPS_FLAGS)))
237 %/dynamic: ocaml-dll=$(shell ocamlobjinfo \
238 $$(OCAMLPATH='$(OCAMLPATH)' ocamlfind query -recursive -format %d/%a \
239 -predicates byte$(,ocaml-predicates) $(ocaml-packages)) | sed -n \
240 -e '/^Extra dynamically-loaded libraries:/{s/^[^:]*://;p}')
241 %/dynamic: \
242 override OCAMLOPT_BIN_FLAGS+= \
243 -noautolink \
244 -cclib -L$(shell ocamlfind printconf stdlib)/stublibs \
245 $(shell ocamlobjinfo \
246 $$(OCAMLPATH='$(OCAMLPATH)' ocamlfind query -recursive -format %d/%a \
247 -predicates native$(,ocaml-predicates) $(ocaml-packages) | \
248 { \
249 set --; \
250 while IFS= read -r line; \
251 do set -- "$$line" "$$@"; \
252 done; \
253 printf '%s\n' "$$@"; \
254 }) | sed -n \
255 -e '/^Extra C options:/{s/^[^:]*://;s/[^ ][^ ]*/-ccopt \0/g;p}' \
256 -e '/^Extra C object files:/{s/^[^:]*://; \
257 $(patsubst -l%,s/ -l\(%\)\( \|$$\)/ -l:dll\1.so /g;,$(ocaml-dll))s/[^ ][^ ]*/-cclib \0/g;p}')
258 # NOTE: the above rule enables the dynamic linking
259 # against dll*.so in native code, by rewriting
260 # the -l* flags for ocaml stubs (listed in .cma archives)
261 # embedded in *.cmxa archives, to -l:dll*.so flags.
262 # Beware that the paths where dll*.so are found at link-time
263 # will be used at runtime to load them.
264 # Note also that the gain in size is likely to be small
265 # and not worth the complexity of dynamic linking.
266 %/dynamic: %
267
268
269 %/static: export LINKING_MODE=static
270 %/static: override OCAMLMKLIB_FLAGS+=-custom
271 %/static: override OCAMLC_FLAGS+=-custom -ccopt -static -cclib -Wl,--start-group -cclib -ltermcap
272 # NOTE : with static linking -lcamlrun needs -ltermcap
273 # this unclosed (sic) --start-group is needed
274 # because ocamlc puts -lcamlrun after all the -cclib .
275 %/static: override OCAMLOPT_FLAGS+=-nodynlink -ccopt -static $(if $(filter x86_64,$(shell uname -m)),-fno-PIC)
276 %/static: %
277
278
279 %/strip: export STRIP=strip
280 %/strip: %
281
282
283 # -----------------
284 # binary capability
285 # -----------------
286 %.caps: setcap=$(shell PATH="$$PATH:/sbin"; which setcap)
287 %.caps: %
288 $(if $(caps),[ ! -x "$(setcap)" ] || $(setcap) "$(caps)" $*)
289
290 # ----------------
291 # binary execution
292 # ----------------
293 .PHONY: %.byte.exec %.native.exec
294 %.byte.exec: %.byte
295 PATH=".:$$PATH"; \
296 $< $(EXEC_FLAGS) $(EXEC_BYTE_FLAGS)
297 %.native.exec: %.native
298 PATH=".:$$PATH"; \
299 $< $(EXEC_FLAGS) $(EXEC_NATIVE_FLAGS)
300
301 # ---------------
302 # ocaml debugging
303 # ---------------
304 export DEBUG
305 %/debug: override OCAML_FLAGS+=-verbose
306 %/debug: override OCAMLC_FLAGS+=-g -principal
307 %/debug: override OCAMLCC_FLAGS+=-ccopt -ggdb3 -ccopt -rdynamic -ccopt -DDEBUG
308 %/debug: override OCAMLMKLIB_FLAGS+=-verbose
309 %/debug: override OCAMLOPT_FLAGS+=-ccopt -ggdb3 -ccopt -rdynamic
310 %/debug: override OCAMLRUNPARAM+=b
311 %/debug: override DEBUG:=debug
312 %/debug: %
313
314 #