[make] s/ocamlbuild/jbuilder/g

Summary:
Use jbuilder to build infer instead of ocamlbuild. This is mainly to get faster builds:

```
times in 10ms, ±differences measured in speedups, 4 cores
|                                   | ocb total |   jb | ±total | ocb user |   jb | ±user | ocb cpu |  jb | ±cpu | ocb sys |   jb | ±sys |
|-----------------------------------+-----------+------+--------+----------+------+-------+---------+-----+------+---------+------+------|
| byte from scratch                 |      6428 | 2456 |   2.62 |     7743 | 6662 |  1.16 |     138 | 331 | 2.40 |    1184 | 1477 | 0.80 |
| native from scratch               |      9841 | 4289 |   2.29 |     9530 | 8834 |  1.08 |     110 | 245 | 2.23 |    1373 | 1712 | 0.80 |
| byte after native                 |     29578 | 1602 |  18.46 |     4514 | 4640 |  0.97 |     170 | 325 | 1.91 |     543 |  576 | 0.94 |
| change infer.ml byte              |       344 |  282 |   1.22 |      292 |  215 |  1.36 |      96 |  99 | 1.03 |     040 |  066 | 0.61 |
| change infer.ml native            |       837 |  223 |   3.75 |      789 |  174 |  4.53 |      98 |  99 | 1.01 |     036 |   47 | 0.77 |
| change Config.ml byte             |       451 |  339 |   1.33 |      382 |  336 |  1.14 |      97 | 122 | 1.26 |     056 |   80 | 0.70 |
| change Config.ml native           |      4024 | 1760 |   2.29 |     4585 | 4225 |  1.09 |     127 | 276 | 2.17 |     559 |  644 | 0.87 |
| change cFrontend_config.ml byte   |       348 |  643 |   0.54 |      297 |  330 |  0.90 |      96 |  67 | 0.70 |     038 |  102 | 0.37 |
| change cFrontend_config.ml native |      1480 |  584 |   2.53 |     1435 |  906 |  1.58 |     106 | 185 | 1.75 |     136 |  178 | 0.76 |
#+TBLFM: $4=$2/$3;f2::$7=$5/$6;f2::$10=$9/$8;f2::$13=$11/$12;f2

50 cores
|                     | ocb total |   jb | ±total | ocb user |   jb | ±user | ocb cpu | jb | ±cpu | ocb sys |   jb | ±sys |
|---------------------+-----------+------+--------+----------+------+-------+---------+----+------+---------+------+------|
| byte from scratch   |      9114 | 2061 |   4.42 |     9334 | 5133 |  1.82 |         |    | 0/0  |    2566 | 1726 | 1.49 |
| native from scratch |     13481 | 3967 |   3.40 |    12291 | 7608 |  1.62 |         |    | 0/0  |    3003 | 2100 | 1.43 |
| byte after native   |      3467 | 1476 |   2.35 |     5067 | 3912 |  1.30 |         |    | 0/0  |     971 |  801 | 1.21 |
#+TBLFM: $4=$2/$3;f2::$7=$5/$6;f2::$10=$9/$8;f2::$13=$11/$12;f2
```

Menu:

1. Write a jbuild file, autogenerated from jbuild.in because we need to fill in
  some information at build-time (really, at configure time, but TODO), such as
  whether or not clang is enabled.
2. Nuke lots of stuff from infer/src/Makefile that is now in the jbuild file
3. The jbuild file lives in infer/src/ so it can see all the sources. If we put it somewhere else, eg, infer/, then `jbuilder` scans too many files (all irrelevant) and takes 2.5s to start instead of .8s. Adding irrelevant directories to jbuild-ignore does not help.
4. jbuilder does not support subdirectories, so resort to listing all the
  source files in the generated jbuild (only source directories need to be
  manually listed in jbuild.in though). Still, the generated .merlin is wrong
  and makes merlin find source files in _build, so manually tune it to get
  good merlin support. We also lose some of merlin for unit tests as it
  cannot see their build artefacts anymore.
5. checkCopyright gets its own jbuild because it's standalone. Also, remove
  some deprecation warnings in checkCopyright due to the new version of Core from
  a while ago.
6. Drop less-used Makefile features (they had regressed anyway) such as
  building individual modules. Also, building mod_dep.pdf now takes all the
  source files available so they better build (before, it would only take the
  source files from the config, eg with or without clang) (that's pretty minor).
7. The toplevel is now built as a custom toplevel because that was easier. It
  should soon be even easier: https://github.com/janestreet/jbuilder/issues/210
8. Move BUILTINS.mli to BUILTINS.ml because jbuilder is not happy about
  interface files without implementations.

In particular, I did not try to migrate too much of the Makefile logic to jbuilder,
more can be done in the future.

Reviewed By: jberdine

Differential Revision: D5573661

fbshipit-source-id: 4ca6d8f
master
Jules Villard 7 years ago committed by Facebook Github Bot
parent 61d6baaaee
commit 8de2b88783

11
.gitignore vendored

@ -16,7 +16,6 @@
# generated by build and tests # generated by build and tests
/_build /_build
/_build_logs /_build_logs
/infer/_build
/infer/tests/codetoanalyze/java/*/codetoanalyze /infer/tests/codetoanalyze/java/*/codetoanalyze
/dependencies/infer-deps-* /dependencies/infer-deps-*
_build_infer _build_infer
@ -93,8 +92,8 @@ buck-out/
#other #other
/infer/bin/infer /infer/bin/infer
/infer/bin/infer.byte /infer/bin/infer.bc
/infer/bin/infer.native /infer/bin/infer.exe
/infer/bin/infer-analyze /infer/bin/infer-analyze
/infer/bin/infer-capture /infer/bin/infer-capture
/infer/bin/infer-compile /infer/bin/infer-compile
@ -151,3 +150,9 @@ infer/src/.project
# generated by Maven # generated by Maven
/infer/annotations/target /infer/annotations/target
# jbuilder
/infer/src/_build
/infer/src/jbuild
/infer/src/jbuild-workspace
/infer/src/scripts/.merlin

@ -11,6 +11,11 @@ default: infer
ROOT_DIR = . ROOT_DIR = .
include $(ROOT_DIR)/Makefile.config include $(ROOT_DIR)/Makefile.config
ifneq ($(UTOP),no)
BUILD_SYSTEMS_TESTS += infertop
build_infertop_print build_infertop_replace build_infertop_test: toplevel_test
endif
ifeq ($(BUILD_C_ANALYZERS),yes) ifeq ($(BUILD_C_ANALYZERS),yes)
BUILD_SYSTEMS_TESTS += \ BUILD_SYSTEMS_TESTS += \
assembly \ assembly \
@ -81,8 +86,8 @@ endif
ifneq ($(BUCK),no) ifneq ($(BUCK),no)
BUILD_SYSTEMS_TESTS += buck genrule BUILD_SYSTEMS_TESTS += buck genrule
# do not run these two tests in parallel otherwise Buck has a bad time # do not run these two tests in parallel otherwise Buck has a bad time
build_genrule_test: build_buck_test build_genrule_test: | build_buck_test
build_genrule_print: build_buck_print build_genrule_print: | build_buck_print
endif endif
ifneq ($(MVN),no) ifneq ($(MVN),no)
BUILD_SYSTEMS_TESTS += mvn BUILD_SYSTEMS_TESTS += mvn
@ -149,14 +154,9 @@ byte: src_build_common
test_build: src_build_common 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
# toplevel build straight after it rather than in parallel. Note that both targets build files
# that the other doesn't.
$(QUIET)$(call silent_on_success,Testing Infer toplevel builds,\
$(MAKE) -C $(SRC_DIR) TEST=1 toplevel)
ifeq ($(IS_FACEBOOK_TREE),yes) ifeq ($(IS_FACEBOOK_TREE),yes)
byte src_build test_build: fb-setup byte src_build_common src_build test_build: fb-setup
endif endif
ifeq ($(BUILD_C_ANALYZERS),yes) ifeq ($(BUILD_C_ANALYZERS),yes)
@ -219,7 +219,7 @@ endif
.PHONY: ocaml_unit_test .PHONY: ocaml_unit_test
ocaml_unit_test: test_build ocaml_unit_test: test_build
$(QUIET)$(call silent_on_success,Running OCaml unit tests,\ $(QUIET)$(call silent_on_success,Running OCaml unit tests,\
$(BUILD_DIR)/test/infer/unit/inferunit.byte) $(BUILD_DIR)/test/inferunit.bc)
define silence_make define silence_make
($(1) 2> >(grep -v "warning: \(ignoring old\|overriding\) \(commands\|recipe\) for target") \ ($(1) 2> >(grep -v "warning: \(ignoring old\|overriding\) \(commands\|recipe\) for target") \
@ -296,15 +296,17 @@ check_missing_mli:
$(QUIET)for x in $$(find $(INFER_DIR)/src -name "*.ml"); do \ $(QUIET)for x in $$(find $(INFER_DIR)/src -name "*.ml"); do \
test -f "$$x"i || echo Missing "$$x"i; done test -f "$$x"i || echo Missing "$$x"i; done
.PHONY: toplevel # depend on test_build because jbuilder doesn't like running concurrently with itself
toplevel: clang_plugin src_build_common .PHONY: toplevel_test
$(QUIET)$(MAKE) -C $(SRC_DIR) toplevel toplevel_test: src_build_common | test_build
# build with TEST=1 as the infer_repl scripts expects to find the toplevel in the test build
$(QUIET)$(call silent_on_success,Building infer toplevel (test mode),\
$(MAKE) -C $(SRC_DIR) TEST=1 toplevel)
.PHONY: inferScriptMode_test .PHONY: toplevel
inferScriptMode_test: test_build toplevel: src_build_common
$(QUIET)$(call silent_on_success,Testing infer OCaml REPL,\ $(QUIET)$(call silent_on_success,Building infer toplevel,\
INFER_REPL_BINARY=ocaml TOPLEVEL_DIR=$(BUILD_DIR)/test/infer $(SCRIPT_DIR)/infer_repl \ $(MAKE) -C $(SRC_DIR) toplevel)
$(INFER_DIR)/tests/repl/infer_batch_script.mltop)
.PHONY: checkCopyright .PHONY: checkCopyright
checkCopyright: checkCopyright:
@ -342,8 +344,7 @@ else
endif endif
.PHONY: config_tests .PHONY: config_tests
config_tests: test_build ocaml_unit_test endtoend_test inferScriptMode_test \ config_tests: test_build ocaml_unit_test endtoend_test checkCopyright validate-skel
checkCopyright validate-skel
$(QUIET)$(call silent_on_success,Building Infer source dependency graph,\ $(QUIET)$(call silent_on_success,Building Infer source dependency graph,\
$(MAKE) -C $(SRC_DIR) mod_dep.dot) $(MAKE) -C $(SRC_DIR) mod_dep.dot)
@ -550,7 +551,10 @@ opam.lock: opam
$(QUIET)$(call silent_on_success,generating opam.lock,\ $(QUIET)$(call silent_on_success,generating opam.lock,\
$(OPAM) lock --pkg $(INFER_PKG_OPAMLOCK) > opam.lock) $(OPAM) lock --pkg $(INFER_PKG_OPAMLOCK) > opam.lock)
OPAM_DEV_DEPS = ocp-indent merlin tuareg # This is a magical version number that doesn't reinstall the world when added on top of what we
# have in opam.lock. To upgrade this version number, manually try to install several utop versions
# until you find one that doesn't recompile the world. TODO(t20828442): get rid of magic
OPAM_DEV_DEPS = ocp-indent merlin tuareg utop.2.0.0
.PHONY: devsetup .PHONY: devsetup
devsetup: Makefile.autoconf devsetup: Makefile.autoconf

@ -64,6 +64,7 @@ prefix = @prefix@
PYTHON_lxml = @PYTHON_lxml@ PYTHON_lxml = @PYTHON_lxml@
SHASUM = @SHASUM@ SHASUM = @SHASUM@
USER_JAVA_HOME = @USER_JAVA_HOME@ USER_JAVA_HOME = @USER_JAVA_HOME@
UTOP = @UTOP@
XCODE_SELECT = @XCODE_SELECT@ XCODE_SELECT = @XCODE_SELECT@
XCPRETTY = @XCPRETTY@ XCPRETTY = @XCPRETTY@

@ -45,7 +45,7 @@ JAVA_BUILTINS_DIR = $(MODELS_DIR)/java/builtins
JAVA_MODELS_DIR = $(MODELS_DIR)/java/src JAVA_MODELS_DIR = $(MODELS_DIR)/java/src
SRC_DIR = $(INFER_DIR)/src SRC_DIR = $(INFER_DIR)/src
BUILD_DIR = $(INFER_DIR)/_build BUILD_DIR = $(SRC_DIR)/_build
JAVA_LIB_DIR = $(LIB_DIR)/java JAVA_LIB_DIR = $(LIB_DIR)/java
SPECS_LIB_DIR = $(LIB_DIR)/specs SPECS_LIB_DIR = $(LIB_DIR)/specs

@ -187,6 +187,7 @@ AC_ASSERT_OCAML_PKG([biniou])
AC_ASSERT_OCAML_PKG([camlzip], [zip]) AC_ASSERT_OCAML_PKG([camlzip], [zip])
AC_ASSERT_OCAML_PKG([easy-format]) AC_ASSERT_OCAML_PKG([easy-format])
AC_ASSERT_OCAML_PKG([oUnit], [], [2.0.0]) AC_ASSERT_OCAML_PKG([oUnit], [], [2.0.0])
AC_CHECK_TOOL([UTOP], [utop], [no])
AC_ASSERT_OCAML_PKG([yojson]) AC_ASSERT_OCAML_PKG([yojson])
AC_ARG_VAR([CAML_LD_LIBRARY_PATH], AC_ARG_VAR([CAML_LD_LIBRARY_PATH],

@ -1,20 +0,0 @@
S src/**
B _build/infer/**
B _build/test/infer/unit/**
PKG ANSITerminal
PKG atdgen
PKG cmdliner
PKG core
PKG javalib
PKG oUnit
PKG parmap
PKG ppx_compare
PKG ptrees
PKG sawja
PKG str
PKG unix
PKG xmlm
PKG yojson
PKG zip
FLG -principal -safe-string -short-paths -strict-formats -strict-sequence
FLG -w +a-4-9-40-41-42-45-48

@ -0,0 +1,38 @@
B _build/default/**
PKG ANSITerminal
PKG atdgen
PKG cmdliner
PKG core
PKG javalib
PKG oUnit
PKG parmap
PKG ppx_compare
PKG ptrees
PKG sawja
PKG str
PKG unix
PKG xmlm
PKG yojson
PKG zip
FLG -principal -safe-string -short-paths -strict-formats -strict-sequence
FLG -w +a-4-9-40-41-42-45-48
FLG -open InferBaseStdlib -open InferGenerated -open InferModules
S backend
S base
S bufferoverrun
S checkers
S clang
S clang_plugin
S clang_stubs
S eradicate
S facebook
S harness
S integration
S IR
S java
S java_stubs
S labs
S opensource
S quandary
S scripts
S unit

@ -11,61 +11,20 @@ include $(ROOT_DIR)/Makefile.config
#### Global declarations #### #### Global declarations ####
ETC_DIR = $(INFER_DIR)/etc ETC_DIR = $(INFER_DIR)/etc
# paths to BUILD_DIR are relative because that's how jbuilder likes it
JBUILDER_BUILD_DEFAULT = _build/default
JBUILDER_BUILD_TEST = _build/test
ifeq ($(TEST),1) ifeq ($(TEST),1)
BASE_BUILD_DIR = $(BUILD_DIR)/test INFER_BUILD_DIR = $(JBUILDER_BUILD_TEST)
else else
BASE_BUILD_DIR = $(BUILD_DIR) INFER_BUILD_DIR = $(JBUILDER_BUILD_DEFAULT)
endif endif
INFER_BUILD_DIR = $(BASE_BUILD_DIR)/infer
ATDGEN_SUFFIXES = _t.ml _t.mli _j.ml _j.mli ATDGEN_SUFFIXES = _t.ml _t.mli _j.ml _j.mli
#### ocamlbuild options ####
GENERATED_OCAML_SOURCES_GLOB = <*{clang_plugin/*,backend/jsonbug_*,checkers/stacktree_*}>
OCAML_FATAL_WARNINGS = +3+5+6+8+10+11+12+18+19+20+21+23+26+29+27+32+33+34+35+37+38+39+50+52+57
# options for ocamlbuild
# Notice that use-ocamlfind is used here to avoid a linker bug in ocamlbuild when using -tag thread
OCAMLBUILD_OPTIONS = \
-r \
-use-menhir -menhir '$(MENHIR) --explain --strict'\
-use-ocamlfind \
-cflags -g -lflags -g \
-cflags -short-paths \
-cflags -safe-string \
-cflags -principal \
-cflags -strict-formats \
-cflags -strict-sequence \
-cflags -w,$(OCAML_FATAL_WARNINGS)-4-9-40-41-42-45-48 \
-tag-line "$(GENERATED_OCAML_SOURCES_GLOB): warn(-27-32-34-35-39)" \
-tag-line "not $(GENERATED_OCAML_SOURCES_GLOB) and <*/{,*/}*.{ml,re}{,i}>: package(ppx_compare)" \
-tag-line "not $(GENERATED_OCAML_SOURCES_GLOB) and not <*{base/IList,base/IStd}.*>: open(IStd)" \
-tag thread \
-pkgs ANSITerminal,atdgen,cmdliner,core,extlib,oUnit,parmap,str,unix,xmlm,yojson,zip
ifeq ($(ENABLE_OCAML_BINANNOT),yes)
OCAMLBUILD_OPTIONS += -cflags -bin-annot
endif
ifeq ($(ENABLE_OCAMLOPT_CUSTOM_CC),yes)
OCAMLBUILD_OPTIONS += -lflags -cc,$(CC) -cflags -cc,$(CC)
endif
ifneq (,$(findstring s,$(MAKEFLAGS)))
OCAMLBUILD_OPTIONS += -quiet
endif
ifeq ($(TEST),1)
OCAMLBUILD_OPTIONS += -cflags -warn-error,$(OCAML_FATAL_WARNINGS)
endif
export OCAMLFIND_IGNORE_DUPS_IN=$(shell $(OCAMLC) -where)/compiler-libs
#### Backend declarations #### #### Backend declarations ####
INFER_MAIN = backend/infer INFER_MAIN = infer
#### Checkers declarations #### #### Checkers declarations ####
@ -83,18 +42,16 @@ INFERPRINT_ATDGEN_STUBS = $(addprefix $(INFERPRINT_ATDGEN_STUB_BASE), $(ATDGEN_S
FACEBOOK_DIR = facebook FACEBOOK_DIR = facebook
INFER_CREATE_TRACEVIEW_LINKS_MODULE = InferCreateTraceViewLinks INFER_CREATE_TRACEVIEW_LINKS_MODULE = InferCreateTraceViewLinks
INFER_CREATE_TRACEVIEW_LINKS_MAIN = $(FACEBOOK_DIR)/$(INFER_CREATE_TRACEVIEW_LINKS_MODULE) INFER_CREATE_TRACEVIEW_LINKS_MAIN = $(INFER_CREATE_TRACEVIEW_LINKS_MODULE)
### InferUnit declarations ### ### InferUnit declarations ###
UNIT_SOURCES = unit UNIT_SOURCES = unit
INFERUNIT_MAIN = $(UNIT_SOURCES)/inferunit INFERUNIT_MAIN = inferunit
#### Java declarations #### #### Java declarations ####
JAVA_OCAMLBUILD_OPTIONS = -pkgs javalib,ptrees,sawja
JAVA_SOURCES = java JAVA_SOURCES = java
#### Clang declarations #### #### Clang declarations ####
@ -127,65 +84,44 @@ CLANG_BINIOU_DICT = $(ETC_DIR)/clang_ast.dict
SCRIPT_SOURCES = scripts SCRIPT_SOURCES = scripts
CHECKCOPYRIGHT_BIN = $(SCRIPT_DIR)/checkCopyright CHECKCOPYRIGHT_BIN = $(SCRIPT_DIR)/checkCopyright
CHECKCOPYRIGHT_MAIN = $(SCRIPT_SOURCES)/checkCopyright CHECKCOPYRIGHT_MAIN = checkCopyright
#### End of declarations #### #### End of declarations ####
ifeq ($(IS_FACEBOOK_TREE),yes) ifeq ($(ENABLE_OCAMLOPT_CUSTOM_CC),yes)
EXTRA_DEPS = facebook EXTRA_CFLAGS += -cc,$(CC)
else
EXTRA_DEPS = opensource
endif endif
DEPENDENCIES = \
absint backend base bufferoverrun checkers eradicate harness integration IR labs quandary unit \
$(EXTRA_DEPS)
# ocamlbuild command with options common to all build targets
OCAMLBUILD_BASE = \
$(OCAMLBUILD) $(OCAMLBUILD_OPTIONS) -j $(NCPU) $(addprefix -I , $(DEPENDENCIES)) \
# ocamlbuild with options necessary to build all targets at once, regardless of configure flags
OCAMLBUILD_ALL = $(OCAMLBUILD_BASE) $(JAVA_OCAMLBUILD_OPTIONS)
# configure-aware ocamlbuild commands and targets
OCAMLBUILD_CONFIG = $(OCAMLBUILD_BASE)
# list of ocamlbuild targets common to all build targets -- native version # list of ocamlbuild targets common to all build targets -- native version
INFER_CONFIG_TARGETS = $(INFER_MAIN).native INFER_CONFIG_TARGETS = $(INFER_BUILD_DIR)/$(INFER_MAIN).exe
ifeq ($(IS_FACEBOOK_TREE),yes) ifeq ($(IS_FACEBOOK_TREE),yes)
INFER_CONFIG_TARGETS += $(INFER_CREATE_TRACEVIEW_LINKS_MAIN).native INFER_CONFIG_TARGETS += $(INFER_BUILD_DIR)/$(INFER_CREATE_TRACEVIEW_LINKS_MAIN).exe
endif endif
ifeq ($(BUILD_JAVA_ANALYZERS),yes)
OCAMLBUILD_CONFIG += $(JAVA_OCAMLBUILD_OPTIONS)
DEPENDENCIES += java
else
DEPENDENCIES += java_stubs
endif
ifeq ($(BUILD_C_ANALYZERS),yes)
DEPENDENCIES += clang clang_plugin unit/clang
else
DEPENDENCIES += clang_stubs unit/clang_stubs
endif
ifeq ($(TEST),1) ifeq ($(TEST),1)
INFER_CONFIG_TARGETS += $(INFERUNIT_MAIN).native INFER_CONFIG_TARGETS += $(INFER_BUILD_DIR)/$(INFERUNIT_MAIN).exe
endif endif
OCAML_BASE_SOURCES = \ OCAML_SOURCES = \
$(wildcard $(DEPENDENCIES:=/[a-zA-Z]*.ml) $(DEPENDENCIES:=/[a-zA-Z]*.mli) \ $(wildcard */[a-zA-Z]*.ml */[a-zA-Z]*.ml[ily]) \
$(DEPENDENCIES:=/[a-zA-Z]*.mll) $(DEPENDENCIES:=/[a-zA-Z]*.mly) \ base/Version.ml $(STACKTREE_ATDGEN_STUBS) $(INFERPRINT_ATDGEN_STUBS)
$(DEPENDENCIES:=/[a-zA-Z]*.re) $(DEPENDENCIES:=/[a-zA-Z]*.rei)) \
$(STACKTREE_ATDGEN_STUBS) $(INFERPRINT_ATDGEN_STUBS)
OCAML_CONFIG_SOURCES = $(OCAML_BASE_SOURCES)
ifeq ($(BUILD_C_ANALYZERS),yes) ifeq ($(BUILD_C_ANALYZERS),yes)
OCAML_CONFIG_SOURCES += $(CLANG_ATDGEN_STUBS) $(CLANG_PLUGIN_MIRRORED_FILES) OCAML_SOURCES += $(CLANG_ATDGEN_STUBS) $(CLANG_PLUGIN_MIRRORED_FILES)
endif endif
OCAML_ALL_SOURCES = $(OCAML_BASE_SOURCES) $(CLANG_ATDGEN_STUBS) $(CLANG_PLUGIN_MIRRORED_FILES)
.PHONY: all .PHONY: all
all: infer all: infer
SRC_BUILD_COMMON = base/Version.ml $(OCAML_CONFIG_SOURCES) $(INFER_BUILD_DIR)/.ppx/ppx_compare/ppx.exe: jbuild jbuild-workspace $(OCAML_SOURCES)
# some voodoo to make jbuilder tolerate being run in parallel: force jbuilder to build its
# jbuild files and some files that have been seen to race otherwise
jbuilder build \
$(JBUILDER_BUILD_DEFAULT)/.ppx/ppx_compare/ppx.exe \
$(JBUILDER_BUILD_TEST)/.ppx/ppx_compare/ppx.exe
touch $@
SRC_BUILD_COMMON = $(INFER_BUILD_DIR)/.ppx/ppx_compare/ppx.exe $(OCAML_SOURCES)
ifeq ($(BUILD_C_ANALYZERS),yes) ifeq ($(BUILD_C_ANALYZERS),yes)
SRC_BUILD_COMMON += $(CLANG_BINIOU_DICT) SRC_BUILD_COMMON += $(CLANG_BINIOU_DICT)
endif endif
@ -193,12 +129,10 @@ endif
.PHONY: src_build_common .PHONY: src_build_common
src_build_common: $(SRC_BUILD_COMMON) src_build_common: $(SRC_BUILD_COMMON)
# single out infer.native as the source of truth for make, knowing that in fact several targets are # single out infer.exe 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: $(SRC_BUILD_COMMON) $(MAKEFILE_LIST) $(INFER_BUILD_DIR)/$(INFER_MAIN).exe: $(SRC_BUILD_COMMON) $(MAKEFILE_LIST)
$(MKDIR_P) $(BASE_BUILD_DIR) jbuilder build $(INFER_CONFIG_TARGETS)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) \
$(INFER_CONFIG_TARGETS)
# let make know that the target is up-to-date even if ocamlbuild cached it # let make know that the target is up-to-date even if ocamlbuild cached it
$(QUIET)touch $@ $(QUIET)touch $@
@ -210,59 +144,38 @@ $(INFER_BIN_ALIASES): Makefile
$(QUIET)cd $(@D) && $(LN_S) -f infer $(@F) $(QUIET)cd $(@D) && $(LN_S) -f infer $(@F)
$(QUIET)touch $@ $(QUIET)touch $@
$(INFER_BIN).native: $(INFER_BUILD_DIR)/$(INFER_MAIN).native $(INFER_BIN_ALIASES) $(INFER_BIN).exe: $(INFER_BUILD_DIR)/$(INFER_MAIN).exe $(INFER_BIN_ALIASES)
$(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_MAIN).native $(INFER_BIN) $(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_MAIN).exe $(INFER_BIN)
$(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_MAIN).native $(INFER_BIN).native $(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_MAIN).exe $(INFER_BIN).exe
ifeq ($(IS_FACEBOOK_TREE),yes) ifeq ($(IS_FACEBOOK_TREE),yes)
$(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_CREATE_TRACEVIEW_LINKS_MAIN).native \ $(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_CREATE_TRACEVIEW_LINKS_MAIN).exe \
$(INFER_CREATE_TRACEVIEW_LINKS_BIN) $(INFER_CREATE_TRACEVIEW_LINKS_BIN)
endif endif
.PHONY: infer .PHONY: infer
infer: $(INFER_BIN).native infer: $(INFER_BIN).exe
$(INFER_BUILD_DIR)/$(INFER_MAIN).byte: $(SRC_BUILD_COMMON) $(MAKEFILE_LIST) $(INFER_BUILD_DIR)/$(INFER_MAIN).bc: $(SRC_BUILD_COMMON) $(MAKEFILE_LIST)
$(MKDIR_P) $(BASE_BUILD_DIR) jbuilder build $(INFER_CONFIG_TARGETS:.exe=.bc)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) \
$(INFER_CONFIG_TARGETS:.native=.byte)
$(QUIET)touch $@ $(QUIET)touch $@
$(INFER_BIN).byte: $(INFER_BUILD_DIR)/$(INFER_MAIN).byte $(INFER_BIN_ALIASES) $(INFER_BIN).bc: $(INFER_BUILD_DIR)/$(INFER_MAIN).bc $(INFER_BIN_ALIASES)
$(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_MAIN).byte $(INFER_BIN) $(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_MAIN).bc $(INFER_BIN)
$(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_MAIN).byte $(INFER_BIN).byte $(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_MAIN).bc $(INFER_BIN).bc
ifeq ($(TEST),1) ifeq ($(TEST),1)
$(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFERUNIT_MAIN).byte $(INFERUNIT_BIN) $(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFERUNIT_MAIN).bc $(INFERUNIT_BIN)
endif endif
ifeq ($(IS_FACEBOOK_TREE),yes) ifeq ($(IS_FACEBOOK_TREE),yes)
$(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_CREATE_TRACEVIEW_LINKS_MAIN).byte \ $(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/$(INFER_CREATE_TRACEVIEW_LINKS_MAIN).bc \
$(INFER_CREATE_TRACEVIEW_LINKS_BIN) $(INFER_CREATE_TRACEVIEW_LINKS_BIN)
endif endif
.PHONY: byte .PHONY: byte
byte: $(INFER_BIN).byte byte: $(INFER_BIN).bc
.PHONY: byte_no_install .PHONY: byte_no_install
byte_no_install: $(INFER_BUILD_DIR)/$(INFER_MAIN).byte byte_no_install: $(INFER_BUILD_DIR)/$(INFER_MAIN).bc
# to build only the single module <Module> (and its dependencies) with extra flags execute:
# make MFLAGS=<flags> M=<Module>.cm{o,x} module
# for example, to build the assembly for the Ident module, execute
# make MFLAGS="-ocamlopt 'ocamlopt -S'" M=Ident.cmx module
M=
MFLAGS=
.PHONY: module
module: $(SRC_BUILD_COMMON) $(OCAML_ALL_SOURCES)
$(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_ALL) -build-dir $(INFER_BUILD_DIR) \
$(MFLAGS) \
$(M)
# to generate interface file.mli from implementation file.ml execute:
# make M=file mli
mli:
$(OCAMLFIND) ocamlc -package atdgen,oUnit,str,unix,yojson,zip $(addprefix -I $(INFER_BUILD_DIR),$(DEPENDENCIES)) -i $(M).ml > $(M).mli
roots:=Infer roots:=Infer
ifeq ($(IS_FACEBOOK_TREE),yes) ifeq ($(IS_FACEBOOK_TREE),yes)
@ -270,8 +183,8 @@ roots += $(INFER_CREATE_TRACEVIEW_LINKS_MODULE)
endif endif
clusters:=base clang java IR clusters:=base clang java IR
ml_src_files:=$(shell find $(DEPENDENCIES) -regex '.*\.ml\(i\)*') ml_src_files:=$(shell find . -regex '.*\.ml\(i\)*')
inc_flags:=$(foreach dir,$(DEPENDENCIES),-I $(dir)) inc_flags:=$(foreach dir,$(shell find . -type d),-I $(dir))
root_flags:=$(foreach root,$(roots),-r $(root)) root_flags:=$(foreach root,$(roots),-r $(root))
cluster_flags:=$(foreach cluster,$(clusters),-c $(cluster)) cluster_flags:=$(foreach cluster,$(clusters),-c $(cluster))
@ -279,7 +192,7 @@ mod_dep.dot: $(ml_src_files)
$(MAKE) -C $(DEPENDENCIES_DIR)/ocamldot $(MAKE) -C $(DEPENDENCIES_DIR)/ocamldot
ocamldep.opt $(inc_flags) $(ml_src_files) \ ocamldep.opt $(inc_flags) $(ml_src_files) \
| $(DEPENDENCIES_DIR)/ocamldot/ocamldot $(cluster_flags) $(root_flags) \ | $(DEPENDENCIES_DIR)/ocamldot/ocamldot $(cluster_flags) $(root_flags) \
| grep -v -e "\"IList\"\|\"Utils\"" \ | grep -v -e "\"IList\"\|\"Utils\"\|\"IStd\"\|\"Infertop\"" \
> mod_dep.dot > mod_dep.dot
mod_dep.pdf: mod_dep.dot mod_dep.pdf: mod_dep.dot
@ -289,47 +202,19 @@ mod_dep.pdf: mod_dep.dot
dsort: dsort:
$(QUIET)ocamldep.opt -sort $(inc_flags) $(ml_src_files) $(QUIET)ocamldep.opt -sort $(inc_flags) $(ml_src_files)
define to_ocaml_module $(INFER_BUILD_DIR)/infertop.bc: $(SRC_DIR)/infertop.ml $(SRC_BUILD_COMMON) $(MAKEFILE_LIST)
$(shell \ jbuilder build $@
echo $(basename $(1)) \
| awk 'BEGIN { FS = "/"; OFS = "/" } ; {$$NF=toupper(substr($$NF,1,1))substr($$NF,2); print $$0}')
endef
toplevel.mlpack: $(SRC_BUILD_COMMON) $(MAKEFILE_LIST)
# 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
# file containing namespaced modules.
# 1. we filter out roots because they execute code upon loading
# 2. each source file is converted to a module by capitalizing its first letter
# 3. we `echo` each module individually to avoid too long a command line
# 4. prevent race conditions by using a temp file
$(eval $@_tmp := $(shell mktemp $@.tmp.XXXX))
$(foreach module,\
$(filter-out $(foreach root,$(roots),%/$(root)),\
$(foreach source,\
$(filter-out unit/%,$(OCAML_CONFIG_SOURCES)),\
$(call to_ocaml_module,$(source)))),\
$(shell echo $(module) >> $($@_tmp)))
mv $($@_tmp) $@
$(INFER_BUILD_DIR)/toplevel.cmo: toplevel.mlpack
$(MKDIR_P) $(BASE_BUILD_DIR)
$(OCAMLBUILD_CONFIG) -build-dir $(INFER_BUILD_DIR) toplevel.cmo
$(QUIET)touch $@ $(QUIET)touch $@
.PHONY: toplevel .PHONY: toplevel
toplevel: $(INFER_BUILD_DIR)/toplevel.cmo toplevel: $(INFER_BUILD_DIR)/infertop.bc
.PHONY: checkCopyright .PHONY: checkCopyright
checkCopyright: $(CHECKCOPYRIGHT_BIN) checkCopyright: $(CHECKCOPYRIGHT_BIN)
$(CHECKCOPYRIGHT_BIN): $(CHECKCOPYRIGHT_MAIN).ml $(MAKEFILE_LIST) $(CHECKCOPYRIGHT_BIN): scripts/$(CHECKCOPYRIGHT_MAIN).ml $(MAKEFILE_LIST)
$(MKDIR_P) $(BASE_BUILD_DIR) jbuilder build $(INFER_BUILD_DIR)/scripts/$(CHECKCOPYRIGHT_MAIN).exe
$(OCAMLBUILD) -quiet -r -j $(NCPU) -build-dir $(BASE_BUILD_DIR)/checkCopyright \ $(INSTALL_PROGRAM) $(INFER_BUILD_DIR)/scripts/$(CHECKCOPYRIGHT_MAIN).exe $(CHECKCOPYRIGHT_BIN)
-cflags -g,-safe-string -lflags -g \
-pkgs core,str -tag thread -use-ocamlfind $(CHECKCOPYRIGHT_MAIN).native
$(INSTALL_PROGRAM) \
$(BASE_BUILD_DIR)/checkCopyright/$(CHECKCOPYRIGHT_MAIN).native $(CHECKCOPYRIGHT_BIN)
define gen_atdgen_rules define gen_atdgen_rules
# generate files using atdgen # generate files using atdgen
@ -376,24 +261,30 @@ $(CLANG_BINIOU_DICT): $(CLANG_ATDGEN_STUB_ATD)
| sort | uniq \ | sort | uniq \
> $@ > $@
base/Version.ml: base/Version.ml.in $(MAKEFILE_LIST) jbuild jbuild-workspace base/Version.ml: $(MAKEFILE_LIST)
TMPFILE=$$(mktemp $@.tmp.XXXX); \ TMPFILE=$$(mktemp $@.tmp.XXXX); \
INFER_GIT_COMMIT=$$(git --work-tree=$(ROOT_DIR) --git-dir=$(ROOT_DIR)/.git rev-parse --short HEAD || printf "unknown"); \ INFER_GIT_COMMIT=$$(git --work-tree=$(ROOT_DIR) --git-dir=$(ROOT_DIR)/.git rev-parse --short HEAD || printf "unknown"); \
INFER_GIT_BRANCH=$$(git --work-tree=$(ROOT_DIR) --git-dir=$(ROOT_DIR)/.git rev-parse --abbrev-ref HEAD || printf "unknown"); \ INFER_GIT_BRANCH=$$(git --work-tree=$(ROOT_DIR) --git-dir=$(ROOT_DIR)/.git rev-parse --abbrev-ref HEAD || printf "unknown"); \
sed \ sed \
-e 's|@EXTRA_CFLAGS[@]|$(EXTRA_CFLAGS)|g' \
-e 's|@INFER_MAJOR[@]|$(INFER_MAJOR)|g' \ -e 's|@INFER_MAJOR[@]|$(INFER_MAJOR)|g' \
-e 's|@INFER_MINOR[@]|$(INFER_MINOR)|g' \ -e 's|@INFER_MINOR[@]|$(INFER_MINOR)|g' \
-e 's|@INFER_PATCH[@]|$(INFER_PATCH)|g' \ -e 's|@INFER_PATCH[@]|$(INFER_PATCH)|g' \
-e 's|@IS_FACEBOOK_TREE[@]|$(IS_FACEBOOK_TREE)|g' \
-e 's|@IS_RELEASE_TREE[@]|$(IS_RELEASE_TREE)|g' \ -e 's|@IS_RELEASE_TREE[@]|$(IS_RELEASE_TREE)|g' \
-e "s|@INFER_GIT_COMMIT[@]|$$INFER_GIT_COMMIT|g" \ -e "s|@INFER_GIT_COMMIT[@]|$$INFER_GIT_COMMIT|g" \
-e "s|@INFER_GIT_BRANCH[@]|$$INFER_GIT_BRANCH|g" \ -e "s|@INFER_GIT_BRANCH[@]|$$INFER_GIT_BRANCH|g" \
-e "s|@BUILD_C_ANALYZERS[@]|$(BUILD_C_ANALYZERS)|g" \ -e "s|@BUILD_C_ANALYZERS[@]|$(BUILD_C_ANALYZERS)|g" \
-e "s|@BUILD_JAVA_ANALYZERS[@]|$(BUILD_JAVA_ANALYZERS)|g" \ -e "s|@BUILD_JAVA_ANALYZERS[@]|$(BUILD_JAVA_ANALYZERS)|g" \
-e "s|@OPAMSWITCH[@]|$(OPAMSWITCH)|g" \
-e "s|@XCODE_SELECT[@]|$(XCODE_SELECT)|g" \ -e "s|@XCODE_SELECT[@]|$(XCODE_SELECT)|g" \
-e "s|@INFER_MAN_LAST_MODIFIED[@]|$(INFER_MAN_LAST_MODIFIED)|g" \ -e "s|@INFER_MAN_LAST_MODIFIED[@]|$(INFER_MAN_LAST_MODIFIED)|g" \
$< > "$$TMPFILE"; \ $@.in > "$$TMPFILE"; \
cat "$$TMPFILE" > $@; \ cat "$$TMPFILE" > $@; \
$(REMOVE) "$$TMPFILE" $(REMOVE) "$$TMPFILE"
jbuild: jbuild.in
jbuild-workspace: jbuild-workspace.in
base/Version.ml: base/Version.ml.in
.PHONY: clean .PHONY: clean
clean: clean:
@ -401,13 +292,13 @@ clean:
$(REMOVE) toplevel.mlpack $(REMOVE) toplevel.mlpack
$(REMOVE_DIR) $(BUILD_DIR) $(REMOVE_DIR) $(BUILD_DIR)
$(REMOVE) $(ETC_DIR)/clang_ast.dict $(REMOVE) $(ETC_DIR)/clang_ast.dict
$(REMOVE) base/Version.ml $(REMOVE) base/Version.ml jbuild jbuild-workspace
$(REMOVE) base/Version.ml.tmp.* $(REMOVE) base/Version.ml.tmp.* jbuild.tmp.* jbuild-workspace.tmp.*
$(REMOVE) backend/jsonbug_{j,t}.ml{,i} $(REMOVE) backend/jsonbug_{j,t}.ml{,i}
$(REMOVE) checkers/stacktree_{j,t}.ml{,i} $(REMOVE) checkers/stacktree_{j,t}.ml{,i}
# be a bit more aggressive than needed with what we remove here so that stale binaries that # be a bit more aggressive than needed with what we remove here so that stale binaries that
# only existed in previous versions get removed as well # only existed in previous versions get removed as well
$(REMOVE) $(BIN_DIR)/Infer* $(BIN_DIR)/infer-* $(INFER_BIN){,.byte,.native} $(INFER_BIN_ALIASES) \ $(REMOVE) $(BIN_DIR)/Infer* $(BIN_DIR)/infer-* $(INFER_BIN){,.bc,.exe} $(INFER_BIN_ALIASES) \
$(INFERUNIT_BIN) $(CHECKCOPYRIGHT_BIN) $(INFERUNIT_BIN) $(CHECKCOPYRIGHT_BIN)
$(REMOVE) $(INFER_CREATE_TRACEVIEW_LINKS_BIN) $(REMOVE) $(INFER_CREATE_TRACEVIEW_LINKS_BIN)
$(REMOVE) $(CLANG_PLUGIN_MIRROR)/* $(REMOVE) $(CLANG_PLUGIN_MIRROR)/*

@ -0,0 +1,8 @@
The OCaml source files for infer live here. The Makefile is
responsible for building them, together with jbuild.in.
If you make changes to the build process, also update .merlin
accordingly. For instance, if you want to add a new source directory
you will need to:
- add it to jbuild.in
- add it to .merlin

@ -418,7 +418,7 @@ let mk_table list =
List.iter ~f:(function v, pn_id -> Hashtbl.replace map pn_id v) list ; List.iter ~f:(function v, pn_id -> Hashtbl.replace map pn_id v) list ;
map map
let this_file = __FILE__ let this_file = Filename.basename __FILE__
let annotated_table_nullable = mk_table annotated_list_nullable let annotated_table_nullable = mk_table annotated_list_nullable

@ -0,0 +1,9 @@
(*
* Copyright (c) 2017 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
;; UTop_main.main ()

@ -0,0 +1,9 @@
;; Do not let jbuilder generate .merlin files because it gets it
;; wrong. This is mainly due to the fact that source files live in
;; sub-directories and are copied into _build/ by our jbuild. jbuilder
;; wants to write "S ." in .merlin but that makes merlin use the
;; copied source files in _build/ instead of only using the original
;; files.
(context ((switch @OPAMSWITCH@) (name default)))
(context ((switch @OPAMSWITCH@) (name test)))

@ -0,0 +1,209 @@
(* -*- tuareg -*- *)
(* use strings so that it looks like OCaml even before substituting, e.g. to use ocamlformat *)
let is_yes = String.equal "yes"
let clang = is_yes "@BUILD_C_ANALYZERS@"
let java = is_yes "@BUILD_JAVA_ANALYZERS@"
let facebook = is_yes "@IS_FACEBOOK_TREE@"
let extra_cflags = if "@EXTRA_CFLAGS" = "" then [] else ["@EXTRA_CFLAGS@"]
let ( ^/ ) = Filename.concat
(* Compute the list of all the source files.
This is needed until jbuilder supports finding sources in subdirectories somehow
(https://github.com/janestreet/jbuilder/issues/34). *)
let sources =
let src_dirs =
let src_dir = "." in
(* if you update the list of source directories, do not forget to also update .merlin *)
src_dir
:: ( if facebook then
(* do not use the symlinks in src/facebook/: jbuilder will not detect that the files have changed if they are hidden behind a symlink *)
"../../facebook/skel/infer/src/facebook"
else src_dir ^/ "opensource" )
:: List.map (Filename.concat src_dir)
( ( if clang then ["clang"; "clang_plugin"; ("unit" ^/ "clang")]
else ["clang_stubs"; ("unit" ^/ "clang_stubs")] )
@ [ (if java then "java" else "java_stubs")
; "absint"
; "backend"
; "base"
; "bufferoverrun"
; "checkers"
; "eradicate"
; "harness"
; "integration"
; "IR"
; "labs"
; "quandary"
; "unit" ] )
in
let files = ref [] in
let ml_suffixes = [".ml"; ".mli"; ".mll"; ".mly"] in
let add_file dir file =
if List.exists (Filename.check_suffix file) ml_suffixes then files := (dir ^/ file) :: !files
in
let one_dir dir =
(* absolute path so that running jbuilder from any subdirectory (in particular from src/Makefile)
points at the right original files in ocamlc's error messages *)
let abs_dir = Sys.getcwd () ^/ dir in
Array.iter (add_file abs_dir) (Sys.readdir dir)
in
List.iter one_dir src_dirs ; !files
let common_cflags =
let fatal_warnings = "+3+5+6+8+10+11+12+18+19+20+21+23+26+29+27+33+34+35+37+38+39+50+52+57" in
let warnings = fatal_warnings ^ "-4-9-32-40-41-42-45-48" in
let common_flags =
[ "-g"
; "-short-paths"
; "-safe-string"
; "-principal"
; "-strict-formats"
; "-strict-sequence"
; "-bin-annot"
; "-w"
; warnings ]
in
match Jbuild_plugin.V1.context with
| "test"
-> "-warn-error" :: fatal_warnings :: common_flags
| "default"
-> common_flags
| ctx
-> invalid_arg ("unknown context: " ^ ctx)
(** Make a library that includes just IStd and IList. These files have different compilation flags
than infer (they don't include IStd!). *)
let inferBaseStdlib = "InferBaseStdlib"
let iStd = "IStd"
let inferBaseStdlib_modules = ["IList"; iStd]
let inferBaseStdlib_cflags = common_cflags
(** Generated code (eg, from atdgen) is also compiled using different flags, so pack it in a
separated library. *)
let inferGenerated = "InferGenerated"
let inferGenerated_modules =
( if clang then
[ "Clang_ast_b"
; "Clang_ast_j"
; "Clang_ast_t"
; "Clang_ast_v"
; "Clang_ast_proj"
; "Clang_ast_types"
; "Clang_ast_visit" ]
else [] )
@ ["Jsonbug_j"; "Jsonbug_t"; "Stacktree_j"; "Stacktree_t"]
let inferGenerated_cflags = common_cflags @ ["-w"; "-27-32-34-35-39"]
let infer_binaries =
["infer"; "inferunit"] @ if facebook then ["InferCreateTraceViewLinks"] else []
let infer_cflags =
common_cflags @ ["-open"; inferBaseStdlib; "-open"; iStd; "-open"; inferGenerated]
let common_libraries =
(if java then ["javalib"; "ptrees"; "sawja"] else [])
@ [ "ANSITerminal"
; "atdgen"
; "cmdliner"
; "core"
; "extlib"
; "oUnit"
; "parmap"
; "str"
; "unix"
; "xmlm"
; "yojson"
; "zip" ]
(** Return the best copy action for a given [source] file. That is, when possibly, use "copy#" so
that jump-to-defition and compiler errors go to the right original source file, otherwise do a
normal copy. *)
let copy_action_of_source source =
if Filename.check_suffix source ".mly" then
(* menhir doesn't support '# 1 "<source file>"' directives at the start of the file inserted by
copy# actions *)
"copy"
else "copy#"
(** The build stanzas to be passed to jbuilder *)
let stanzas =
( if clang then
["(ocamllex (types_lexer ctl_lexer))"; "(menhir ((modules (types_parser ctl_parser))))"]
else [] )
@ [ Format.sprintf
{|
(library
((name %s)
(flags (%s))
(modules (%s))
(libraries (atdgen))
))
|}
inferGenerated (String.concat " " inferGenerated_cflags)
(String.concat " " inferGenerated_modules)
; Format.sprintf
{|
(library
((name %s)
(flags (%s))
(modules (%s))
(libraries (%s))
))
|}
inferBaseStdlib (String.concat " " inferBaseStdlib_cflags)
(String.concat " " inferBaseStdlib_modules) (String.concat " " common_libraries)
; Format.sprintf
{|
(library
((name InferModules)
(flags (%s))
(libraries (%s %s %s))
(modules (:standard \ %s infertop %s %s))
(preprocess (pps (ppx_compare)))
))
|}
(String.concat " " infer_cflags) (String.concat " " common_libraries) inferBaseStdlib
inferGenerated (String.concat " " infer_binaries)
(String.concat " " inferBaseStdlib_modules) (String.concat " " inferGenerated_modules)
; Format.sprintf
{|
(executables
((names (%s))
(flags (%s -open InferModules))
(libraries (InferModules))
(modules (%s))
(preprocess (pps (ppx_compare)))
))
|}
(String.concat " " infer_binaries) (String.concat " " infer_cflags)
(String.concat " " infer_binaries)
; Format.sprintf
{|
(executable
((name infertop)
(flags (%s))
(libraries (utop InferModules))
(modules (:standard \ %s))
(link_flags (-linkall -warn-error -31))))
|}
(String.concat " " infer_cflags) (String.concat " " infer_binaries) ]
@ List.map
(fun source ->
Printf.sprintf "(rule (%s %s %s))" (copy_action_of_source source) source
(Filename.basename source))
sources
;; String.concat "\n" stanzas |> Jbuild_plugin.V1.send

@ -7,7 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*) *)
open! Core.Std open! Core
module F = Format module F = Format
let copyright_modified_exit_code = 1 let copyright_modified_exit_code = 1
@ -193,7 +193,7 @@ let copyright_has_changed mono fb_year com_style prefix cstart cend lines_arr =
let update_file fname mono fb_year com_style prefix cstart cend lines_arr = let update_file fname mono fb_year com_style prefix cstart cend lines_arr =
try try
let cout = open_out fname in let cout = Out_channel.create fname in
let fmt = F.formatter_of_out_channel cout in let fmt = F.formatter_of_out_channel cout in
for i = 0 to cstart - 1 do F.fprintf fmt "%s@." lines_arr.(i) done ; for i = 0 to cstart - 1 do F.fprintf fmt "%s@." lines_arr.(i) done ;
pp_copyright mono fb_year com_style fmt prefix ; pp_copyright mono fb_year com_style fmt prefix ;

@ -0,0 +1,7 @@
(jbuild_version 1)
(executable
((name checkCopyright)
(flags (:standard -g -short-paths -safe-string -principal -strict-formats -strict-sequence -bin-annot -w +3+5+6+8+10+11+12+18+19+20+21+23+26+29+27+33+34+35+37+38+39+50+52+57-4-9-32-40-41-42-45-48))
(libraries (core str))
))

@ -45,6 +45,9 @@ differences.exp.test: $(CLANG_DEPS) $(SOURCES) $(MAKEFILE_LIST)
) )
$(QUIET)$(REMOVE) capture_hash-1.sha capture_hash-2.sha $(QUIET)$(REMOVE) capture_hash-1.sha capture_hash-2.sha
.PHONY: print
print: differences.exp.test
.PHONY: test .PHONY: test
test: differences.exp.test test: differences.exp.test
$(QUIET)diff -u differences.exp $< $(QUIET)diff -u differences.exp $<

@ -0,0 +1,31 @@
# Copyright (c) 2017 - present Facebook, Inc.
# All rights reserved.
#
# This source code is licensed under the BSD style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.
TESTS_DIR = ../..
ROOT_DIR = $(TESTS_DIR)/../..
include $(TESTS_DIR)/base.make
toplevel.exp.test: $(BUILD_DIR)/test/infertop.bc
$(QUIET)$(call silent_on_success,Testing infer OCaml REPL,\
TOPLEVEL_DIR=$(BUILD_DIR)/test $(SCRIPT_DIR)/infer_repl \
$(INFER_DIR)/tests/repl/infer_batch_script.mltop > $@)
.PHONY: print
print: toplevel.exp.test
.PHONY: test
test: toplevel.exp.test
$(QUIET)diff -u toplevel.exp $<
.PHONY: replace
replace: toplevel.exp.test
$(QUIET)$(COPY) $< toplevel.exp
.PHONY: clean
clean:
$(QUIET)$(REMOVE) toplevel.exp.test

@ -0,0 +1,11 @@
Findlib has been successfully loaded. Additional directives:
#require "package";; to load a package
#list;; to list the available packages
#camlp4o;; to load camlp4 (standard syntax)
#camlp4r;; to load camlp4 (revised syntax)
#predicates "p,q,...";; to set these predicates
Topfind.reset();; to force that packages will be reloaded
#thread;; to enable threads
n$2
false

@ -27,11 +27,11 @@ codetoanalyze/java/eradicate/InconsistentSubclassAnnotation.java, String Inconsi
codetoanalyze/java/eradicate/InconsistentSubclassAnnotation.java, SubclassExample$T SubclassExample$B.foo(), 0, ERADICATE_INCONSISTENT_SUBCLASS_RETURN_ANNOTATION, [Method `SubclassExample$B.foo()` is annotated with `@Nullable` but overrides unannotated method `SubclassExample$A.foo()`.] codetoanalyze/java/eradicate/InconsistentSubclassAnnotation.java, SubclassExample$T SubclassExample$B.foo(), 0, ERADICATE_INCONSISTENT_SUBCLASS_RETURN_ANNOTATION, [Method `SubclassExample$B.foo()` is annotated with `@Nullable` but overrides unannotated method `SubclassExample$A.foo()`.]
codetoanalyze/java/eradicate/InconsistentSubclassAnnotation.java, SubclassExample$T SubclassExample$C.baz(), 0, ERADICATE_INCONSISTENT_SUBCLASS_RETURN_ANNOTATION, [Method `SubclassExample$C.baz()` is annotated with `@Nullable` but overrides unannotated method `SubclassExample$I.baz()`.] codetoanalyze/java/eradicate/InconsistentSubclassAnnotation.java, SubclassExample$T SubclassExample$C.baz(), 0, ERADICATE_INCONSISTENT_SUBCLASS_RETURN_ANNOTATION, [Method `SubclassExample$C.baz()` is annotated with `@Nullable` but overrides unannotated method `SubclassExample$I.baz()`.]
codetoanalyze/java/eradicate/InconsistentSubclassAnnotation.java, void SubclassExample$D.deref(SubclassExample$T), 0, ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION, [First parameter `t` of method `SubclassExample$D.deref(...)` is not `@Nullable` but is declared `@Nullable`in the parent class method `SubclassExample$A.deref(...)`.] codetoanalyze/java/eradicate/InconsistentSubclassAnnotation.java, void SubclassExample$D.deref(SubclassExample$T), 0, ERADICATE_INCONSISTENT_SUBCLASS_PARAMETER_ANNOTATION, [First parameter `t` of method `SubclassExample$D.deref(...)` is not `@Nullable` but is declared `@Nullable`in the parent class method `SubclassExample$A.deref(...)`.]
codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badAtomicReferenceDereference(AtomicReference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in eradicate/modelTables.ml at line 37)] codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badAtomicReferenceDereference(AtomicReference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in modelTables.ml at line 37)]
codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badPhantomReferenceDereference(PhantomReference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in eradicate/modelTables.ml at line 29)] codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badPhantomReferenceDereference(PhantomReference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in modelTables.ml at line 29)]
codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badReferenceDereference(Reference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in eradicate/modelTables.ml at line 21)] codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badReferenceDereference(Reference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in modelTables.ml at line 21)]
codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badSoftReferenceDereference(SoftReference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in eradicate/modelTables.ml at line 33)] codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badSoftReferenceDereference(SoftReference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in modelTables.ml at line 33)]
codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badWeakReferenceDereference(WeakReference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in eradicate/modelTables.ml at line 25)] codetoanalyze/java/eradicate/LibraryCalls.java, String LibraryCalls.badWeakReferenceDereference(WeakReference), 1, ERADICATE_NULL_METHOD_CALL, [origin,The value of `ref.get()` in the call to `toString()` could be null. (Origin: call to get() modelled in modelTables.ml at line 25)]
codetoanalyze/java/eradicate/NullFieldAccess.java, Object NullFieldAccess.arrayAccess(), 1, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `NullFieldAccess.objects` could be null when accessing element at index `0`. (Origin: field NullFieldAccess.objects at line 63)] codetoanalyze/java/eradicate/NullFieldAccess.java, Object NullFieldAccess.arrayAccess(), 1, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `NullFieldAccess.objects` could be null when accessing element at index `0`. (Origin: field NullFieldAccess.objects at line 63)]
codetoanalyze/java/eradicate/NullFieldAccess.java, int NullFieldAccess.arrayLength(), 1, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `NullFieldAccess.objects` could be null when accessing field `length`. (Origin: field NullFieldAccess.objects at line 59)] codetoanalyze/java/eradicate/NullFieldAccess.java, int NullFieldAccess.arrayLength(), 1, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `NullFieldAccess.objects` could be null when accessing field `length`. (Origin: field NullFieldAccess.objects at line 59)]
codetoanalyze/java/eradicate/NullFieldAccess.java, int NullFieldAccess.useInterface(NullFieldAccess$I), 2, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `c` could be null when accessing field `NullFieldAccess$C.n`. (Origin: field NullFieldAccess$I.c at line 52)] codetoanalyze/java/eradicate/NullFieldAccess.java, int NullFieldAccess.useInterface(NullFieldAccess$I), 2, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `c` could be null when accessing field `NullFieldAccess$C.n`. (Origin: field NullFieldAccess$I.c at line 52)]
@ -39,11 +39,11 @@ codetoanalyze/java/eradicate/NullFieldAccess.java, int NullFieldAccess.useX(), 2
codetoanalyze/java/eradicate/NullFieldAccess.java, int NullFieldAccess.useZ(), 2, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `c` could be null when accessing field `NullFieldAccess$C.n`. (Origin: field NullFieldAccess.z at line 47)] codetoanalyze/java/eradicate/NullFieldAccess.java, int NullFieldAccess.useZ(), 2, ERADICATE_NULL_FIELD_ACCESS, [origin,Object `c` could be null when accessing field `NullFieldAccess$C.n`. (Origin: field NullFieldAccess.z at line 47)]
codetoanalyze/java/eradicate/NullMethodCall.java, int NullMethodCall$Inner.outerField(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: field NullMethodCall.fld at line 71)] codetoanalyze/java/eradicate/NullMethodCall.java, int NullMethodCall$Inner.outerField(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: field NullMethodCall.fld at line 71)]
codetoanalyze/java/eradicate/NullMethodCall.java, int NullMethodCall$Inner.outerPrivateField(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: field NullMethodCall.pfld at line 82)] codetoanalyze/java/eradicate/NullMethodCall.java, int NullMethodCall$Inner.outerPrivateField(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: field NullMethodCall.pfld at line 82)]
codetoanalyze/java/eradicate/NullMethodCall.java, int NullMethodCall.testSystemGetenvBad(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `envValue` in the call to `length()` could be null. (Origin: call to getenv(...) modelled in eradicate/modelTables.ml at line 243)] codetoanalyze/java/eradicate/NullMethodCall.java, int NullMethodCall.testSystemGetenvBad(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `envValue` in the call to `length()` could be null. (Origin: call to getenv(...) modelled in modelTables.ml at line 243)]
codetoanalyze/java/eradicate/NullMethodCall.java, void NullMethodCall.callOnNull(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: null constant at line 22)] codetoanalyze/java/eradicate/NullMethodCall.java, void NullMethodCall.callOnNull(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: null constant at line 22)]
codetoanalyze/java/eradicate/NullMethodCall.java, void NullMethodCall.testExceptionPerInstruction(int), 6, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: null constant at line 183)] codetoanalyze/java/eradicate/NullMethodCall.java, void NullMethodCall.testExceptionPerInstruction(int), 6, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: null constant at line 183)]
codetoanalyze/java/eradicate/NullMethodCall.java, void NullMethodCall.testFieldAssignmentIfThenElse(String), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: null constant at line 174)] codetoanalyze/java/eradicate/NullMethodCall.java, void NullMethodCall.testFieldAssignmentIfThenElse(String), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: null constant at line 174)]
codetoanalyze/java/eradicate/NullMethodCall.java, void NullMethodCall.testSystemGetPropertyReturn(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: call to getProperty(...) modelled in eradicate/modelTables.ml at line 238)] codetoanalyze/java/eradicate/NullMethodCall.java, void NullMethodCall.testSystemGetPropertyReturn(), 2, ERADICATE_NULL_METHOD_CALL, [origin,The value of `s` in the call to `length()` could be null. (Origin: call to getProperty(...) modelled in modelTables.ml at line 238)]
codetoanalyze/java/eradicate/ParameterNotNullable.java, ParameterNotNullable$ConstructorCall.<init>(ParameterNotNullable,int), 1, ERADICATE_PARAMETER_NOT_NULLABLE, [origin,`ParameterNotNullable$ConstructorCall(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 102)] codetoanalyze/java/eradicate/ParameterNotNullable.java, ParameterNotNullable$ConstructorCall.<init>(ParameterNotNullable,int), 1, ERADICATE_PARAMETER_NOT_NULLABLE, [origin,`ParameterNotNullable$ConstructorCall(...)` needs a non-null value in parameter 2 but argument `null` can be null. (Origin: null constant at line 102)]
codetoanalyze/java/eradicate/ParameterNotNullable.java, String ParameterNotNullable.testSystemGetPropertyArgument(), 1, ERADICATE_PARAMETER_NOT_NULLABLE, [origin,`getProperty(...)` needs a non-null value in parameter 1 but argument `null` can be null. (Origin: null constant at line 71)] codetoanalyze/java/eradicate/ParameterNotNullable.java, String ParameterNotNullable.testSystemGetPropertyArgument(), 1, ERADICATE_PARAMETER_NOT_NULLABLE, [origin,`getProperty(...)` needs a non-null value in parameter 1 but argument `null` can be null. (Origin: null constant at line 71)]
codetoanalyze/java/eradicate/ParameterNotNullable.java, String ParameterNotNullable.testSystemGetenvBad(), 1, ERADICATE_PARAMETER_NOT_NULLABLE, [origin,`getenv(...)` needs a non-null value in parameter 1 but argument `null` can be null. (Origin: null constant at line 76)] codetoanalyze/java/eradicate/ParameterNotNullable.java, String ParameterNotNullable.testSystemGetenvBad(), 1, ERADICATE_PARAMETER_NOT_NULLABLE, [origin,`getenv(...)` needs a non-null value in parameter 1 but argument `null` can be null. (Origin: null constant at line 76)]
@ -67,4 +67,4 @@ codetoanalyze/java/eradicate/ReturnNotNullable.java, String ReturnNotNullable.re
codetoanalyze/java/eradicate/ReturnNotNullable.java, String ReturnNotNullable.returnNullable(String), 0, ERADICATE_RETURN_NOT_NULLABLE, [Method `returnNullable(...)` may return null but it is not annotated with `@Nullable`. (Origin: method parameter s)] codetoanalyze/java/eradicate/ReturnNotNullable.java, String ReturnNotNullable.returnNullable(String), 0, ERADICATE_RETURN_NOT_NULLABLE, [Method `returnNullable(...)` may return null but it is not annotated with `@Nullable`. (Origin: method parameter s)]
codetoanalyze/java/eradicate/ReturnNotNullable.java, String ReturnNotNullable.return_null_in_catch(), 0, ERADICATE_RETURN_NOT_NULLABLE, [origin,Method `return_null_in_catch()` may return null but it is not annotated with `@Nullable`. (Origin: null constant at line 111)] codetoanalyze/java/eradicate/ReturnNotNullable.java, String ReturnNotNullable.return_null_in_catch(), 0, ERADICATE_RETURN_NOT_NULLABLE, [origin,Method `return_null_in_catch()` may return null but it is not annotated with `@Nullable`. (Origin: null constant at line 111)]
codetoanalyze/java/eradicate/ReturnNotNullable.java, String ReturnNotNullable.return_null_in_catch_after_throw(), 0, ERADICATE_RETURN_NOT_NULLABLE, [origin,Method `return_null_in_catch_after_throw()` may return null but it is not annotated with `@Nullable`. (Origin: null constant at line 123)] codetoanalyze/java/eradicate/ReturnNotNullable.java, String ReturnNotNullable.return_null_in_catch_after_throw(), 0, ERADICATE_RETURN_NOT_NULLABLE, [origin,Method `return_null_in_catch_after_throw()` may return null but it is not annotated with `@Nullable`. (Origin: null constant at line 123)]
codetoanalyze/java/eradicate/ReturnNotNullable.java, URL ReturnNotNullable.getResourceNullable(Class,String), 0, ERADICATE_RETURN_NOT_NULLABLE, [origin,Method `getResourceNullable(...)` may return null but it is not annotated with `@Nullable`. (Origin: call to getResource(...) modelled in eradicate/modelTables.ml at line 128)] codetoanalyze/java/eradicate/ReturnNotNullable.java, URL ReturnNotNullable.getResourceNullable(Class,String), 0, ERADICATE_RETURN_NOT_NULLABLE, [origin,Method `getResourceNullable(...)` may return null but it is not annotated with `@Nullable`. (Origin: call to getResource(...) modelled in modelTables.ml at line 128)]

@ -34,6 +34,7 @@ depends: [
"ctypes" {>="0.9.2"} "ctypes" {>="0.9.2"}
"extlib-compat" "extlib-compat"
"javalib" {>="2.3.3"} "javalib" {>="2.3.3"}
"jbuilder" {build & >="1.0+beta11"}
"ocamlfind" {build} "ocamlfind" {build}
"ounit" {="2.0.0"} "ounit" {="2.0.0"}
"parmap" {>="1.0-rc8"} "parmap" {>="1.0-rc8"}

@ -1,20 +1,25 @@
#!/bin/bash #!/bin/bash
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" ## Wrapper around infertop. To build infertop, run `make toplevel`.
# where to find toplevel.cmo, can be overridden SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
TOPLEVEL_DIR=${TOPLEVEL_DIR:-"$SCRIPT_DIR"/../infer/_build/infer}
# how to load the toplevel; can be overridden (with "ocaml" for example) # where to find toplevel.bc, can be overridden
INFER_REPL_BINARY=${INFER_REPL_BINARY:-"utop"} TOPLEVEL_DIR=${TOPLEVEL_DIR:-"$SCRIPT_DIR"/../infer/src/_build/default}
# to build new toplevel, run `make toplevel` # The -init option is effective only in interactive mode.
# -init option is used only in interactive mode # In batch mode, scripts need to import toplevel_init themselves.
# in batch mode, scripts need to import toplevel_init themselves
# It can be done by adding #use "toplevel_init";; to the beginning # It can be done by adding #use "toplevel_init";; to the beginning
# of a script. # of a script.
# NOTE: $SCRIPT_DIR is added search path for batch scripts # NOTE: $SCRIPT_DIR is added search path for batch scripts
# so they can be located anywhere and still find toplevel_init # so they can be located anywhere and still find toplevel_init
# file. In interactive mode $SCRIPT_DIR isn't needed # file. In interactive mode $SCRIPT_DIR isn't needed
"$INFER_REPL_BINARY" -init "$SCRIPT_DIR"/toplevel_init -I "$TOPLEVEL_DIR" -I "$SCRIPT_DIR" $@ set -x
# infertop expects to be run from where jbuild is located
cd "$SCRIPT_DIR"/../infer
"$TOPLEVEL_DIR"/infertop.bc \
-init "$SCRIPT_DIR"/toplevel_init \
-I "$TOPLEVEL_DIR" \
-I "$SCRIPT_DIR" \
"$@"

@ -1,3 +1,5 @@
(* to be used with infertop, infer's custom toplevel *)
(* load dependencies *) (* load dependencies *)
#use "topfind";; #use "topfind";;
#thread;; #thread;;
@ -10,6 +12,5 @@
#require "xmlm";; #require "xmlm";;
#require "ANSITerminal";; #require "ANSITerminal";;
(* load infer code *) open InferModules;;
#load_rec "toplevel.cmo";; open InferBaseStdlib;;
open Toplevel;;

Loading…
Cancel
Save