[build] avoid race condition, and do not run atdgen twice, add ocaml_clean

Summary:
Fixes 2 issues with the build:
- The OCaml dependencies (Version.ml, atdgen-generated stuff, ...) would be generated twice when running `make -j test` from a clean tree, because `make` has no inter-Makefile visibility over common dependencies.
- We would run `atdgen` twice: once for the .ml, once for the .mli, even though one invocation is enough for both.

Add `make ocaml_clean` to nuke only the OCaml code (in particular because
rebuilding the C++ code in the plugin is slow when all I want to get rid of the
OCaml stuff).

Reviewed By: mbouaziz

Differential Revision: D5415318

fbshipit-source-id: 16f42c6
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent d07c8a0403
commit 5dd4b1c870

@ -123,18 +123,24 @@ SRC_ML:=$(shell find * \( -name _build -or -name facebook-clang-plugins -or -pat
fmt_all: fmt_all:
parallel $(OCAMLFORMAT_EXE) --no-warn-error -i ::: $(SRC_ML) parallel $(OCAMLFORMAT_EXE) --no-warn-error -i ::: $(SRC_ML)
# pre-building these avoids race conditions when building, eg src_build and test_build in parallel
.PHONY: src_build_common
src_build_common:
$(QUIET)$(call silent_on_success,Generating source dependencies,\
$(MAKE) -C $(SRC_DIR) src_build_common)
.PHONY: src_build .PHONY: src_build
src_build: src_build: src_build_common
$(QUIET)$(call silent_on_success,Building native Infer,\ $(QUIET)$(call silent_on_success,Building native Infer,\
$(MAKE) -C $(SRC_DIR) infer) $(MAKE) -C $(SRC_DIR) infer)
.PHONY: byte .PHONY: byte
byte: byte: src_build_common
$(QUIET)$(call silent_on_success,Building byte Infer,\ $(QUIET)$(call silent_on_success,Building byte Infer,\
$(MAKE) -C $(SRC_DIR) byte) $(MAKE) -C $(SRC_DIR) byte)
.PHONY: test_build .PHONY: test_build
test_build: test_build: src_build_common
$(QUIET)$(call silent_on_success,Testing Infer builds without warnings,\ $(QUIET)$(call silent_on_success,Testing Infer builds without warnings,\
$(MAKE) -C $(SRC_DIR) TEST=1 byte_no_install) $(MAKE) -C $(SRC_DIR) TEST=1 byte_no_install)
# byte_no_install builds most of what toplevel needs, so it's more efficient to run the # byte_no_install builds most of what toplevel needs, so it's more efficient to run the
@ -148,7 +154,7 @@ byte src_build test_build: fb-setup
endif endif
ifeq ($(BUILD_C_ANALYZERS),yes) ifeq ($(BUILD_C_ANALYZERS),yes)
byte src_build test_build: clang_plugin byte src_build src_build_common test_build: clang_plugin
endif endif
$(INFER_COMMAND_MANUALS): src_build Makefile $(INFER_COMMAND_MANUALS): src_build Makefile
@ -313,7 +319,7 @@ check_missing_mli:
test -f "$$x"i || echo Missing "$$x"i; done test -f "$$x"i || echo Missing "$$x"i; done
.PHONY: toplevel .PHONY: toplevel
toplevel: clang_plugin toplevel: clang_plugin src_build_common
$(QUIET)$(MAKE) -C $(SRC_DIR) toplevel $(QUIET)$(MAKE) -C $(SRC_DIR) toplevel
.PHONY: inferScriptMode_test .PHONY: inferScriptMode_test
@ -496,21 +502,29 @@ ifeq ($(IS_FACEBOOK_TREE),yes)
$(QUIET)$(MAKE) -C facebook install $(QUIET)$(MAKE) -C facebook install
endif endif
.PHONY: clean # Nuke objects built from OCaml. Useful when changing the OCaml compiler, for instance.
clean: test_clean .PHONY: ocaml_clean
ocaml_clean:
ifeq ($(IS_RELEASE_TREE),no) ifeq ($(IS_RELEASE_TREE),no)
ifeq ($(BUILD_C_ANALYZERS),yes) ifeq ($(BUILD_C_ANALYZERS),yes)
$(QUIET)$(MAKE) -C $(FCP_DIR) clean
$(QUIET)$(MAKE) -C $(FCP_DIR)/clang-ocaml clean $(QUIET)$(MAKE) -C $(FCP_DIR)/clang-ocaml clean
endif endif
endif endif
$(QUIET)$(MAKE) -C $(SRC_DIR) clean $(QUIET)$(MAKE) -C $(SRC_DIR) clean
$(QUIET)$(MAKE) -C $(DEPENDENCIES_DIR)/ocamldot clean
.PHONY: clean
clean: test_clean ocaml_clean
ifeq ($(IS_RELEASE_TREE),no)
ifeq ($(BUILD_C_ANALYZERS),yes)
$(QUIET)$(MAKE) -C $(FCP_DIR) clean
endif
endif
$(QUIET)$(MAKE) -C $(ANNOTATIONS_DIR) clean $(QUIET)$(MAKE) -C $(ANNOTATIONS_DIR) clean
$(QUIET)$(MAKE) -C $(MODELS_DIR) clean $(QUIET)$(MAKE) -C $(MODELS_DIR) clean
ifeq ($(IS_FACEBOOK_TREE),yes) ifeq ($(IS_FACEBOOK_TREE),yes)
$(QUIET)$(MAKE) -C facebook clean $(QUIET)$(MAKE) -C facebook clean
endif endif
$(QUIET)$(MAKE) -C $(DEPENDENCIES_DIR)/ocamldot clean
find $(INFER_DIR)/tests \( -name '*.o' -o -name '*.o.sh' \) -delete find $(INFER_DIR)/tests \( -name '*.o' -o -name '*.o.sh' \) -delete
$(QUIET)$(REMOVE_DIR) _build_logs $(MAN_DIR) $(QUIET)$(REMOVE_DIR) _build_logs $(MAN_DIR)

@ -185,10 +185,16 @@ OCAML_ALL_SOURCES = $(OCAML_BASE_SOURCES) $(CLANG_ATDGEN_STUBS) $(CLANG_PLUGIN_M
.PHONY: all .PHONY: all
all: infer all: infer
.PHONY: src_build_common
src_build_common: base/Version.ml $(OCAML_CONFIG_SOURCES)
ifeq ($(BUILD_C_ANALYZERS),yes)
src_build_common: $(CLANG_BINIOU_DICT)
endif
# single out infer.native as the source of truth for make, knowing that in fact several targets are # single out infer.native as the source of truth for make, knowing that in fact several targets are
# produced by the build # produced by the build
$(INFER_BUILD_DIR)/$(INFER_MAIN).native: base/Version.ml $(OCAML_CONFIG_SOURCES) \ $(INFER_BUILD_DIR)/$(INFER_MAIN).native: src_build_common $(MAKEFILE_LIST)
$(MAKEFILE_LIST)
$(MKDIR_P) $(BASE_BUILD_DIR) $(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) \ $(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) \
$(INFER_CONFIG_TARGETS) $(INFER_CONFIG_TARGETS)
@ -215,12 +221,7 @@ endif
.PHONY: infer .PHONY: infer
infer: $(INFER_BIN).native infer: $(INFER_BIN).native
ifeq ($(BUILD_C_ANALYZERS),yes) $(INFER_BUILD_DIR)/$(INFER_MAIN).byte: src_build_common $(MAKEFILE_LIST)
infer: $(CLANG_BINIOU_DICT)
endif
$(INFER_BUILD_DIR)/$(INFER_MAIN).byte: base/Version.ml $(OCAML_CONFIG_SOURCES) \
$(MAKEFILE_LIST)
$(MKDIR_P) $(BASE_BUILD_DIR) $(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) \ $(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) \
$(INFER_CONFIG_TARGETS:.native=.byte) $(INFER_CONFIG_TARGETS:.native=.byte)
@ -251,7 +252,7 @@ M=
MFLAGS= MFLAGS=
.PHONY: module .PHONY: module
module: base/Version.ml $(OCAML_ALL_SOURCES) module: src_build_common $(OCAML_ALL_SOURCES)
$(MKDIR_P) $(BASE_BUILD_DIR) $(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_ALL) -build-dir $(INFER_BUILD_DIR) \ $(OCAMLBUILD_ALL) -build-dir $(INFER_BUILD_DIR) \
$(MFLAGS) \ $(MFLAGS) \
@ -293,7 +294,7 @@ $(shell \
| awk 'BEGIN { FS = "/"; OFS = "/" } ; {$$NF=toupper(substr($$NF,1,1))substr($$NF,2); print $$0}') | awk 'BEGIN { FS = "/"; OFS = "/" } ; {$$NF=toupper(substr($$NF,1,1))substr($$NF,2); print $$0}')
endef endef
toplevel.mlpack: base/Version.ml $(OCAML_CONFIG_SOURCES) $(MAKEFILE_LIST) toplevel.mlpack: src_build_common $(MAKEFILE_LIST)
# We need to pack all the infer modules into another module to avoid name clashes with some # We need to pack all the infer modules into another module to avoid name clashes with some
# of them coming from ocaml libraries (Ident for example). To do that, we generate a .mlpack # of them coming from ocaml libraries (Ident for example). To do that, we generate a .mlpack
# file containing namespaced modules. # file containing namespaced modules.
@ -332,11 +333,11 @@ $(CHECKCOPYRIGHT_BIN): $(CHECKCOPYRIGHT_MAIN).ml $(MAKEFILE_LIST)
define gen_atdgen_rules define gen_atdgen_rules
# generate files using atdgen # generate files using atdgen
# parameters: # parameters:
# 1. the .atd file to generate .ml{,i} files from # 1. the .atd file to generate .ml{,i} files from, e.g. foo.atd
# 2. the base name of .ml{,i} files # 2. the base name of .ml{,i} files, e.g. foo
# 3. the type of files to generate: b, j, t, or v # 3. the type of files to generate: b, j, t, or v
$(2)_$(3).ml $(2)_$(3).mli: $(1) $(2)_$(3).mli: $(1)
$(ATDGEN) -$(3) $$< -o $(2) $(ATDGEN) -$(3) $$< -o $(2)
# the .ml depends on the corresponding .mli to avoid running atdgen # the .ml depends on the corresponding .mli to avoid running atdgen

Loading…
Cancel
Save