|
| 1 | +# |
| 2 | +# Build rules common to ocaml-jst and flambda-backend |
| 3 | +# |
| 4 | + |
| 5 | +ws_boot = --root=. --workspace=duneconf/boot.ws |
| 6 | +ws_runstd = --root=. --workspace=duneconf/runtime_stdlib.ws |
| 7 | +ws_main = --root=. --workspace=duneconf/main.ws |
| 8 | + |
| 9 | +ifeq ($(coverage),yes) |
| 10 | + coverage_dune_flags=--instrument-with bisect_ppx |
| 11 | + ocaml_subdirs_to_ignore=otherlibs |
| 12 | +else |
| 13 | + coverage_dune_flags= |
| 14 | + ocaml_subdirs_to_ignore= |
| 15 | +endif |
| 16 | + |
| 17 | +define dune_boot_context |
| 18 | +(lang dune 2.8) |
| 19 | +; We need to call the boot context "default" so that dune selects it for merlin |
| 20 | +(context (default |
| 21 | + (name default) |
| 22 | + ; CR sdolan: profile dev might be faster, but the compiler currently fails to build in dev. |
| 23 | + (profile boot))) |
| 24 | +endef |
| 25 | + |
| 26 | +define dune_runtime_stdlib_context |
| 27 | +(lang dune 2.8) |
| 28 | +(context (default |
| 29 | + (name runtime_stdlib) |
| 30 | + (profile main) |
| 31 | + (paths |
| 32 | + (PATH ("$(CURDIR)/_build/_bootinstall/bin" :standard)) |
| 33 | + (OCAMLLIB ("$(CURDIR)/_build/_bootinstall/lib/ocaml"))) |
| 34 | + (env (_ (env-vars |
| 35 | + ("OCAMLPARAM" "$(BUILD_OCAMLPARAM)")))))) |
| 36 | +endef |
| 37 | + |
| 38 | +define dune_main_context |
| 39 | +(lang dune 2.8) |
| 40 | +(context (default |
| 41 | + (name main) |
| 42 | + (profile main) |
| 43 | + (paths |
| 44 | + (PATH ("$(CURDIR)/_build/_bootinstall/bin" :standard)) |
| 45 | + (OCAMLLIB ("$(CURDIR)/_build/install/runtime_stdlib/lib/ocaml_runtime_stdlib"))) |
| 46 | + (env (_ (env-vars |
| 47 | + ("OCAMLPARAM" "$(BUILD_OCAMLPARAM)")))))) |
| 48 | +endef |
| 49 | + |
| 50 | + |
| 51 | +.DEFAULT_GOAL := compiler |
| 52 | +.PHONY: boot-compiler boot-runtest runtime-stdlib compiler runtest |
| 53 | + |
| 54 | +boot-compiler: _build/_bootinstall |
| 55 | + $(dune) build $(ws_boot) $(coverage_dune_flags) \ |
| 56 | + $(boot_ocamlc) \ |
| 57 | + $(boot_ocamlopt) \ |
| 58 | + $(boot_ocamlmklib) \ |
| 59 | + $(boot_ocamldep) \ |
| 60 | + $(boot_ocamlobjinfo) |
| 61 | + |
| 62 | +boot-runtest: boot-compiler |
| 63 | + $(dune) runtest $(ws_boot) $(coverage_dune_flags) --force |
| 64 | + |
| 65 | +runtime-stdlib: boot-compiler |
| 66 | + $(dune) build $(ws_runstd) --only-package=ocaml_runtime_stdlib @install |
| 67 | +# dune does not believe the compiler can make .cmxs unless the following file exists |
| 68 | + @touch _build/install/runtime_stdlib/lib/ocaml_runtime_stdlib/dynlink.cmxa |
| 69 | + |
| 70 | +compiler: runtime-stdlib |
| 71 | + $(dune) build $(ws_main) --only-package=ocaml @install $(ocamldir)/ocamltest/ocamltest.byte |
| 72 | + |
| 73 | +runtest: compiler |
| 74 | + $(dune) runtest $(ws_main) |
| 75 | + |
| 76 | + |
| 77 | +# This Makefile supports old versions that don't have $(file), so we're using |
| 78 | +# environment var trickery to get a multiline string into a file |
| 79 | +duneconf/boot.ws: export contents = $(dune_boot_context) |
| 80 | +duneconf/runtime_stdlib.ws: export contents = $(dune_runtime_stdlib_context) |
| 81 | +duneconf/main.ws: export contents = $(dune_main_context) |
| 82 | +duneconf/%.ws: |
| 83 | + echo "$$contents" > $@ |
| 84 | + |
| 85 | +# We need to disable ocaml/otherlibs when compiling with coverage, because we |
| 86 | +# need to compile against the user's opam instead. Unfortunately, Dune gives us |
| 87 | +# no nicer way of declaring data_only_dirs differently in different workspaces, |
| 88 | +# so we have to output a file to be included in ocaml/dune. |
| 89 | +# |
| 90 | +# Also, Dune only allows one (data_only_dirs) declaration per file, so here we |
| 91 | +# have to account for the declaration that would already have been in |
| 92 | +# ocaml/dune. |
| 93 | +$(ocamldir)/duneconf/dirs-to-ignore.inc: |
| 94 | + echo "(data_only_dirs yacc $(ocaml_subdirs_to_ignore))" > $@ |
| 95 | + |
| 96 | +_build/_bootinstall: Makefile.config duneconf/boot.ws duneconf/runtime_stdlib.ws duneconf/main.ws \ |
| 97 | + $(ocamldir)/duneconf/dirs-to-ignore.inc \ |
| 98 | + $(ocamldir)/duneconf/jst-extra.inc \ |
| 99 | + dune-project |
| 100 | + |
| 101 | + echo -n '$(NATDYNLINKOPTS)' > $(ocamldir)/otherlibs/dynlink/natdynlinkops |
| 102 | + |
| 103 | +# flags.sexp |
| 104 | + echo '(:standard $(if $(filter true,$(FUNCTION_SECTIONS)),-function-sections,))' > ocamlopt_flags.sexp |
| 105 | + echo '( $(OC_CFLAGS) )' > oc_cflags.sexp |
| 106 | + echo '( $(OC_CPPFLAGS) )' > oc_cppflags.sexp |
| 107 | + echo '( $(SHAREDLIB_CFLAGS) )' > sharedlib_cflags.sexp |
| 108 | + |
| 109 | +# _build/_bootinstall: a minimal install directory for the boot compiler, |
| 110 | +# which is placed on PATH for subsequent builds |
| 111 | + rm -rf _build/_bootinstall |
| 112 | + mkdir -p _build/_bootinstall/{bin,lib/ocaml} |
| 113 | + cp $^ _build/_bootinstall/lib/ocaml |
| 114 | + ln -sf ../../default/$(boot_ocamlopt) _build/_bootinstall/bin/ocamlopt.opt |
| 115 | + ln -sf ../../default/$(boot_ocamlc) _build/_bootinstall/bin/ocamlc.opt |
| 116 | + ln -sf ../../default/$(boot_ocamlmklib) _build/_bootinstall/bin/ocamlmklib.opt |
| 117 | + ln -sf ../../default/$(boot_ocamldep) _build/_bootinstall/bin/ocamldep.opt |
| 118 | + ln -sf ../../default/$(boot_ocamlobjinfo) _build/_bootinstall/bin/ocamlobjinfo.opt |
| 119 | + ln -sf "`which ocamllex`" _build/_bootinstall/bin/ocamllex.opt |
| 120 | + for prog in ocamlopt ocamlc ocamllex ocamldep ocamlmklib; do \ |
| 121 | + ln -sf "$$prog.opt" "_build/_bootinstall/bin/$$prog"; \ |
| 122 | + done |
| 123 | + |
| 124 | +# save a bit of disk space in build trees by using cp -l on Linux |
| 125 | +# (not available on e.g. OS X) |
| 126 | +cpl=$(if $(filter linux,$(SYSTEM)),cp -l,cp -L) |
| 127 | + |
| 128 | +# Assemble the contents of the install directory in _install |
| 129 | +# This is needed to run the upstream testsuite (see runtest-upstream below) |
| 130 | +# We use a local directory rather than the final install path, since |
| 131 | +# the final install path may be on a different filesystem (and hence be |
| 132 | +# slow and/or unable to make hardlinks) |
| 133 | +.PHONY: _install install install_for_opam |
| 134 | +_install: compiler |
| 135 | + rm -rf _install |
| 136 | + mkdir -p _install/{bin,lib/ocaml} |
| 137 | + $(cpl) _build/install/{runtime_stdlib,main}/bin/* _install/bin/ |
| 138 | + ( cd _install/bin; for i in *.opt; do ln -s $$i $${i%.opt}; done ) |
| 139 | + $(cpl) -R _build/install/runtime_stdlib/lib/ocaml_runtime_stdlib/* _install/lib/ocaml/ |
| 140 | + rm -f _install/lib/ocaml/{META,dune-package,Makefile.config,dynlink.cmxa} |
| 141 | + $(cpl) -R _build/install/main/lib/ocaml/* _install/lib/ocaml/ |
| 142 | + rm -f _install/lib/ocaml/{META,dune-package} |
| 143 | + rm -f _install/lib/ocaml/compiler-libs/*.cmo |
| 144 | + $(cpl) {_build/install/main,_install}/lib/ocaml/compiler-libs/topstart.cmo |
| 145 | + for file in $(toplevels_installed); do \ |
| 146 | + cp -f _install/lib/ocaml/compiler-libs/$${file}dirs.{cmi,mli,cmt,cmti} _install/lib/ocaml; \ |
| 147 | + done |
| 148 | + shopt -s nullglob; for file in _build/main/$(ocamldir)/.ocaml{bytecomp,common,middleend,optcomp}.objs/{byte/*.{cmi,cma,cmt,cmti},native/*.{cmx,cmxa,cmxs}}; do \ |
| 149 | + $(cpl) $$file _install/lib/ocaml/compiler-libs/ ; \ |
| 150 | + done |
| 151 | + mkdir _install/lib/stublibs |
| 152 | + |
| 153 | + find _build/main/ \( -name "flambda2*.cmi" \ |
| 154 | + -or -name "flambda2*.cmti" -or -name "flambda2*.cmt" \) \ |
| 155 | + -exec cp -f {} _install/lib/ocaml/compiler-libs \; |
| 156 | + |
| 157 | +# Copy _install to the final install directory (no-op if they are the same) |
| 158 | +install: _install |
| 159 | + mkdir -p '$(prefix)' |
| 160 | + rsync --chmod=u+rw,go+r -rl _install/ '$(prefix)' |
| 161 | + |
| 162 | +# Same as above, but relies on a successfull earlier _install |
| 163 | +install_for_opam: |
| 164 | + mkdir -p '$(prefix)' |
| 165 | + rsync --chmod=u+rw,go+r -rl _install/ '$(prefix)' |
| 166 | + |
| 167 | +main_prefix = _build/install/main |
| 168 | +main_build = _build/main |
| 169 | + |
| 170 | +# The following horror will be removed when work to allow the testsuite to |
| 171 | +# run on an installed tree (led by David Allsopp) is completed. |
| 172 | +.PHONY: runtest-upstream |
| 173 | +runtest-upstream: _install |
| 174 | + rm -rf _runtest |
| 175 | + mkdir _runtest |
| 176 | + ln -s ../_install _runtest/_install |
| 177 | + cp -a $(ocamldir)/testsuite _runtest/testsuite |
| 178 | + # replace backend-specific testsuite/tools with their new versions |
| 179 | + rm _runtest/testsuite/tools/* |
| 180 | + cp -a testsuite/tools/* _runtest/testsuite/tools/ |
| 181 | + # replace backend-specific testsuite/tests/asmgen with their new versions |
| 182 | + rm _runtest/testsuite/tests/asmgen/* |
| 183 | + cp -a testsuite/tests/asmgen/* _runtest/testsuite/tests/asmgen/ |
| 184 | + |
| 185 | + ln -s ../$(ocamldir)/Makefile.tools _runtest/Makefile.tools |
| 186 | + ln -s ../$(ocamldir)/Makefile.build_config _runtest/Makefile.build_config |
| 187 | + ln -s ../$(ocamldir)/Makefile.config_if_required _runtest/Makefile.config_if_required |
| 188 | + ln -s ../$(ocamldir)/Makefile.config _runtest/Makefile.config |
| 189 | + |
| 190 | +# Create an OCaml directory laid out like the testsuite expects, |
| 191 | +# by copying and symlinking in bits from the install/build directory |
| 192 | + (cd _runtest; \ |
| 193 | + for exe in _install/bin/*; do ln -s $$exe; done; \ |
| 194 | + for exe in ocamlc ocamlopt ocamllex; do \ |
| 195 | + rm -f $$exe; ln -s $$exe.byte $$exe; \ |
| 196 | + done; \ |
| 197 | + ln -s _install/lib/ocaml stdlib; \ |
| 198 | + mkdir runtime; \ |
| 199 | + for f in ocamlrun* stdlib/caml stdlib/stublibs/*; do \ |
| 200 | + ln -s ../$$f runtime/`basename $$f`; \ |
| 201 | + done; \ |
| 202 | + ln -s . lex; ln -s . yacc; \ |
| 203 | + ln -s _install/lib/ocaml/compiler-libs compilerlibs; \ |
| 204 | + mkdir -p otherlibs/{unix,dynlink/native,str}; \ |
| 205 | + ln -s ../stdlib/threads otherlibs/systhreads; \ |
| 206 | + $(cpl) stdlib/{lib,}unix* otherlibs/unix; \ |
| 207 | + $(cpl) stdlib/dynlink* otherlibs/dynlink; \ |
| 208 | + $(cpl) stdlib/{lib,}str* otherlibs/str; \ |
| 209 | + ln -s ../_build/main/$(ocamldir)/toplevel/.ocamltoplevel.objs/byte toplevel; \ |
| 210 | + ) |
| 211 | + |
| 212 | + # Various directories are put on the -I paths by tools/Makefile; |
| 213 | + # utils/ is one such, so we just dump the .cm* files in there for |
| 214 | + # various things. |
| 215 | + mkdir _runtest/utils |
| 216 | + cp _install/lib/ocaml/compiler-libs/*.{cmi,cmx} _runtest/utils |
| 217 | + cp $(main_build)/$(ocamldir)/.ocamlcommon.objs/byte/*.cmo _runtest/utils |
| 218 | + rm -f _runtest/utils/{topdirs,opttopdirs}.cmi |
| 219 | + cp _install/lib/ocaml/*.{cmi,cma,a,cmxa} _runtest/utils |
| 220 | + cp $(main_build)/$(ocamldir)/.ocamlcommon.objs/native/config.o _runtest/utils |
| 221 | + # Needed for tests/warnings |
| 222 | + cp $(ocamldir)/utils/warnings.ml _runtest/utils |
| 223 | + # Suppress linker errors about -I directories not existing. |
| 224 | + for dir in asmcomp bytecomp driver file_formats lambda middle_end \ |
| 225 | + parsing typing; do ln -s utils _runtest/$$dir; done |
| 226 | + # stublibs |
| 227 | + mkdir -p _runtest/lib/ocaml/stublibs/ |
| 228 | + cp $(main_prefix)/lib/ocaml/stublibs/*.so _runtest/lib/ocaml/stublibs |
| 229 | + # ocamldebug |
| 230 | + mkdir _runtest/debugger |
| 231 | + ln -s ../ocamldebug _runtest/debugger |
| 232 | + cp $(main_build)/$(ocamldir)/debugger/.main.eobjs/byte/*.cm* \ |
| 233 | + _runtest/debugger |
| 234 | + # The ast_invariants test needs VERSION to be present. In fact ideally |
| 235 | + # we should have all the source files in _runtest too for this test, |
| 236 | + # but for the moment we accept it being a weaker check. We're not |
| 237 | + # working on parts of the compiler that deal with the AST anyway in |
| 238 | + # this repo. |
| 239 | + touch _runtest/VERSION |
| 240 | + # tools |
| 241 | + mkdir _runtest/tools |
| 242 | + ln -s ../_install/bin/ocamlmklib.byte _runtest/tools/ocamlmklib |
| 243 | + ln -s ../_install/bin/ocamlobjinfo.byte _runtest/tools/ocamlobjinfo |
| 244 | + # ocamltest itself |
| 245 | + mkdir _runtest/ocamltest |
| 246 | + cp $(main_build)/$(ocamldir)/ocamltest/ocamltest.byte _runtest/ocamltest/ocamltest |
| 247 | + if [ "$(middle_end)" = "flambda2" ]; then \ |
| 248 | + for dir in `cd ocaml/testsuite; ls -1 -d tests/*`; do \ |
| 249 | + if ! grep -q "^ $$dir " testsuite/flambda2-test-list; then \ |
| 250 | + echo " $$dir"; \ |
| 251 | + fi; \ |
| 252 | + done > _runtest/flambda2-test-list; \ |
| 253 | + fi |
| 254 | + (export OCAMLSRCDIR=$$(pwd)/_runtest; \ |
| 255 | + export CAML_LD_LIBRARY_PATH=$$(pwd)/_runtest/lib/ocaml/stublibs; \ |
| 256 | + if $$(which gfortran > /dev/null 2>&1); then \ |
| 257 | + export LIBRARY_PATH=$$(dirname $$(gfortran -print-file-name=libgfortran.a)); \ |
| 258 | + fi; \ |
| 259 | + cd _runtest/testsuite \ |
| 260 | + && if $$(which parallel > /dev/null 2>&1); \ |
| 261 | + then \ |
| 262 | + echo "Running testsuite in parallel (nproc=$$(nproc))"; \ |
| 263 | + if [ "$(middle_end)" = "flambda2" ]; then \ |
| 264 | + make --no-print-directory list-parallel FILE=$$(pwd)/../flambda2-test-list; \ |
| 265 | + else \ |
| 266 | + make --no-print-directory parallel; \ |
| 267 | + fi \ |
| 268 | + else \ |
| 269 | + echo "Running testsuite sequentially"; \ |
| 270 | + if [ "$(middle_end)" = "flambda2" ]; then \ |
| 271 | + make --no-print-directory list FILE=$$(pwd)/../flambda2-test-list; \ |
| 272 | + else \ |
| 273 | + make --no-print-directory all; \ |
| 274 | + fi \ |
| 275 | + fi) |
| 276 | + |
| 277 | +# This target is like a polling version of upstream "make ocamlopt" |
| 278 | +.PHONY: hacking |
| 279 | +hacking: _build/_bootinstall |
| 280 | + $(dune) build $(ws_boot) -w boot_ocamlopt.exe |
0 commit comments