# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
.PHONY : default
default : infer
ROOT_DIR = .
i n c l u d e $( ROOT_DIR ) / M a k e f i l e . c o n f i g
[RFC][build] Use dune environments and profiles instead of contexts
Summary:
With profiles and `(env ...)` stanza it's possible to consolidate
various ocamlc/ocamlopt/etc setups in a single place.
Where previously we needed to append `dune.common` to every dune file
and specify `flags` and `ocamlopt_flags` now the flags are specified
in `env` and applied accross the board.
This allows to
1. simplify build definitions,
2. avoid the need to generate dune files,
3. use plain sexps instead of OCaml and JBuilder plugin in build
files.
(I'll try to address 2 and 3 in the followup patches).
Existing `make` targets should continue working as before. Also, we
can use dune CLI like so:
```
infer/src$ dune printenv --profile opt # <- very useful for introspection
infer/src$ dune build check
infer/src$ dune build check --profile test
infer/src$ dune build infer.exe --profile dev
infer/src$ dune build infer.exe --profile opt
```
Also, with just 1 context something like `dune runtest` will run unit
tests only once instead of N times, where N is the number of contexts.
Now, there's one difference compared to the previous setup with
contexts:
- Previously, each context had its own build folder, and building infer
in opt context didn't invalidate any of the build artifacts in default
context. Therefore, alternating between `make` and `make opt` had low
overhead at the expense of having N copies of all build artifacts (1
for every context).
- Now, there's just 1 build folder and switching between profiles does
invalidate some artifacts (but not all) and rebuild takes a bit more
time.
So, if you're alternating like crazy between profiles your experience
may get worse (but not necessarily, more on that below). If you want
to trigger an opt build occasionally, you shouldn't notice much
difference.
For those who are concerned about slower build times when alternating
between different build profiles, there's a solution: [dune
cache](https://dune.readthedocs.io/en/stable/caching.html).
You can enable it by creating a file `~/.config/dune/config` with the
following contents:
```
(lang dune 2.0)
(cache enabled)
```
With cache enabled switching between different build profiles (but
also branches and commits) has ~0 overhead.
Dune cache works fine on Linux, but unfortunately there are [certain
problems with
MacOS](https://github.com/ocaml/dune/issues/3233) (hopefully, those
will be fixed soon and then there will be no downsides to using
profiles compared to contexts for our case).
Reviewed By: jvillard
Differential Revision: D20247864
fbshipit-source-id: 5f8afa0db
5 years ago
MAKE_SOURCE = $( MAKE) -C $( SRC_DIR)
[build] switch to 4.05.0+flambda by default
Summary:
With flambda (`-O3`), compilation time is ~5x slower, but the backend is ~25% faster!
To mitigate the atrocious compilation times, introduce a new `opt` build mode in the jbuilder files.
- build in "opt" mode by default from the toplevel (so that install scripts and external users get the fastest infer by default), in "default" mode by default from infer/src (since the latter is only called directly by infer devs, for faster builds)
- `make byte` is as fast as before in any mode
- `make test` will build "opt" by default, which is very slow. Solution for testing (or building the models) locally: `make BUILD_MODE=default test`.
- You can even change the default locally with `export BUILD_MODE=default`.
The benchmarks are to be taken with a sizable pinch of salt because I ran them only once and other stuff could be running in the background. That said, the perf win is consistent across all projects, with 15-20% win in wallclock time and around 25% win in total CPU time, ~9% win in sys time, and ~25% fewer minor allocations, and ~5-10% fewer overall allocations. This is only for the backend; the capture is by and large unaffected (either the same or a tad faster within noise range).
Here are the results running on OpenSSL 1.0.2d on osx (12 cores, 32G RAM)
=== base
infer binary: 26193088 bytes
compile time: 40s
capture:
```lang=text
real 1m7.513s
user 3m11.437s
sys 0m55.236s
```
analysis:
```lang=text
real 5m41.580s
user 61m37.855s
sys 1m12.870s
```
Memory profile:
```lang=json
{
...
"minor_gb": 0.1534719169139862,
"promoted_gb": 0.0038930922746658325,
"major_gb": 0.4546157643198967,
"allocated_gb": 0.6041945889592171,
"minor_collections": 78,
"major_collections": 23,
"compactions": 7,
"top_heap_gb": 0.07388687133789062,
"stack_kb": 0.3984375,
"minor_heap_kb": 8192.0,
...
}
```
=== flambda with stock options (no `-Oclassic`, just the same flags as base)
Exactly the same as base.
=== flambda `-O3`
infer binary: 56870376 bytes (2.17x bigger)
compile time: 191s (4.78x slower)
capture is the same as base:
```lang=text
real 1m9.203s
user 3m12.242s
sys 0m58.905s
```
analysis is ~20% wallclock time faster, ~25% CPU time faster:
```lang=text
real 4m32.656s
user 46m43.987s
sys 1m2.424s
```
memory usage is a bit lower too:
```lang=json
{
...
"minor_gb": 0.11583046615123749, // 75% of previous
"promoted_gb": 0.00363825261592865, // 93% of previous
"major_gb": 0.45415670424699783, // about same
"allocated_gb": 0.5663489177823067, // 94% of previous
"minor_collections": 73,
"major_collections": 22,
"compactions": 7,
"top_heap_gb": 0.07165145874023438,
"stack_kb": 0.3359375,
"minor_heap_kb": 8192.0,
...
}
```
=== flambda `-O2`
Not nearly as exciting as `-O3`, but the compilation cost is still quite high:
infer: 37826856 bytes
compilation of infer: 100s
Capture and analysis timings are mostly the same as base.
Reviewed By: jberdine
Differential Revision: D4867979
fbshipit-source-id: 99230b7
7 years ago
[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
7 years ago
i f n e q ( $( UTOP ) , n o )
BUILD_SYSTEMS_TESTS += infertop
[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
7 years ago
e n d i f
i f e q ( $( BUILD_C_ANALYZERS ) , y e s )
BUILD_SYSTEMS_TESTS += \
annotation-reachability-sources-override \
assembly \
backtrack_level \
ck_imports \
clang_compilation_db_escaped clang_compilation_db_relpath \
clang_multiple_files \
clang_translation \
clang_unknown_ext \
clang_with_block_listed_flags \
clang_with_E_flag \
clang_with_M_flag \
clang_with_MD_flag \
deduplicate_template_warnings \
delete_results_dir \
duplicate_symbols \
fail_on_issue \
j1 \
linters \
project_root_rel \
reactive \
results_xml \
tracebugs \
utf8_in_procname \
export_changed_functions \
incremental_analysis_remove_file \
incremental_analysis_change_procedure \
incremental_analysis_add_procedure \
COST_TESTS += \
c_performance \
DIRECT_TESTS += \
c_biabduction \
c_bufferoverrun \
c_frontend \
c_performance \
c_pulse \
c_pulse-isl \
c_purity \
c_uninit \
cpp_annotation-reachability \
cpp_biabduction \
cpp_bufferoverrun \
cpp_conflicts \
cpp_frontend \
cpp_impurity \
cpp_linters \
cpp_linters-for-test-only \
cpp_liveness \
cpp_performance \
cpp_pulse \
cpp_pulse-isl \
cpp_quandary \
cpp_racerd \
cpp_siof \
cpp_starvation \
cpp_uninit \
i f n e q ( $( BUCK ) , n o )
BUILD_SYSTEMS_TESTS += \
buck_block_list \
buck-clang-db \
buck_clang_test_determinator \
buck_flavors \
buck_flavors_diff \
buck_flavors_run \
buck_flavors_deterministic \
buck_export_changed_functions \
e n d i f
i f n e q ( $( CMAKE ) , n o )
BUILD_SYSTEMS_TESTS += clang_compilation_db cmake inferconfig inferconfig_not_strict
e n d i f
i f n e q ( $( NDKBUILD ) , n o )
BUILD_SYSTEMS_TESTS += ndk_build
e n d i f
i f e q ( $( HAS_OBJC ) , y e s )
BUILD_SYSTEMS_TESTS += \
clang_test_determinator \
objc_getters_setters \
objc_missing_fld \
objc_retain_cycles \
objc_retain_cycles_weak \
differential_of_costs_report_objc \
COST_TESTS += \
objc_autoreleasepool \
objc_performance \
DIRECT_TESTS += \
objc_autoreleasepool \
objc_bufferoverrun \
objc_biabduction \
objc_frontend \
objc_linters \
objc_linters-def-folder \
objc_linters-for-test-only \
objc_liveness \
objc_performance \
objc_pulse \
objc_quandary \
objc_self-in-block \
objc_uninit \
objcpp_biabduction \
objcpp_frontend \
objcpp_linters \
objcpp_linters-for-test-only \
objcpp_liveness \
objcpp_pulse \
objcpp_racerd \
objcpp_retain-cycles \
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
BUILD_SYSTEMS_TESTS += \
fb_differential_of_config_impact_report_objc
DIRECT_TESTS += \
objc_fb-config-impact \
objc_fb-gk-interaction
e n d i f
i f n e q ( $( XCODE_SELECT ) , n o )
BUILD_SYSTEMS_TESTS += xcodebuild_no_xcpretty
e n d i f
i f n e q ( $( XCPRETTY ) , n o )
BUILD_SYSTEMS_TESTS += xcodebuild
e n d i f
e n d i f # HAS_OBJC
e n d i f # BUILD_C_ANALYZERS
i f e q ( $( BUILD_ERLANG_ANALYZERS ) , y e s )
i f n e q ( $( REBAR 3) , n o )
DIRECT_TESTS += \
erlang_nonmatch \
erlang_topl \
erlang_features \
BUILD_SYSTEMS_TESTS += rebar3
e n d i f
e n d i f # BUILD_ERLANG_ANALYZERS
i f e q ( $( BUILD_JAVA_ANALYZERS ) , y e s )
BUILD_SYSTEMS_TESTS += \
differential_interesting_paths_filter \
differential_of_costs_report_java \
incremental_analysis_cost_change \
differential_skip_anonymous_class_renamings \
differential_skip_duplicated_types_on_filenames \
differential_skip_duplicated_types_on_filenames_with_renamings \
gradle \
java_source_parser \
java_test_determinator \
javac \
resource_leak_exception_lines \
racerd_dedup
COST_TESTS += \
java_hoistingExpensive \
java_performance \
java_performance-exclusive \
DIRECT_TESTS += \
java_annotreach \
java_biabduction \
java_bufferoverrun \
java_checkers \
java_hoisting \
java_hoistingExpensive \
java_impurity \
java_immutability \
java_inefficientKeysetIterator \
java_litho-required-props \
java_nullsafe \
java_nullsafe-annotation-graph \
java_performance \
java_performance-exclusive \
java_pulse \
java_pulse-isl \
java_purity \
java_quandary \
java_racerd \
java_starvation \
java_starvation-dedup \
java_starvation-whole-program \
java_topl \
# javac has trouble running in parallel on the same files
direct_java_pulse-isl_test : direct_java_pulse_test
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
BUILD_SYSTEMS_TESTS += \
fb_differential_of_config_impact_report_java
COST_TESTS += java_fb-performance
DIRECT_TESTS += \
java_fb-config-impact \
java_fb-gk-interaction \
java_fb-immutability \
java_fb-performance
e n d i f
i f n e q ( $( ANT ) , n o )
BUILD_SYSTEMS_TESTS += ant
e n d i f
i f n e q ( $( BUCK ) , n o )
BUILD_SYSTEMS_TESTS += buck_java_flavor
e n d i f
i f n e q ( $( MVN ) , n o )
BUILD_SYSTEMS_TESTS += mvn
e n d i f
e n d i f # BUILD_JAVA_ANALYZERS
DIRECT_TESTS += \
dotnet_arithmetic \
dotnet_array \
dotnet_bgeble \
dotnet_box \
dotnet_fieldderef \
dotnet_isinst \
dotnet_ldstr \
dotnet_logical \
dotnet_nullderef-interproc \
dotnet_nullderef-simple \
dotnet_nullparam \
dotnet_numcomparison \
dotnet_reference \
dotnet_resourceleak \
dotnet_starg
i f e q ( $( BUILD_C_ANALYZERS ) + $( BUILD_JAVA_ANALYZERS ) , y e s + y e s )
BUILD_SYSTEMS_TESTS += make utf8_in_pwd waf
e n d i f
i f e q ( $( IS_INFER_RELEASE ) , n o )
configure : configure .ac $( wildcard m 4/*.m 4)
# rerun ./autogen.sh in case of failure as the failure may be due to needing to rerun
# ./configure
$( QUIET) ( $( call silent_on_success,Generate ./configure,./autogen.sh) ) || \
./autogen.sh
Makefile.autoconf : configure Makefile .autoconf .in
# rerun ./configure with the flags that were used last time it was run (if available)
# retry in case of failure as the failure may be due to needing to rerun ./configure
$( QUIET) ( $( call silent_on_success,Running\
./configure $( shell ./config.status --config || true ) ,\
./configure $( shell ./config.status --config || true ) ) ) || \
./configure $( shell ./config.status --config || true )
e n d i f
.PHONY : fb -setup
fb-setup :
$( QUIET) $( call silent_on_success,Facebook setup,\
$( MAKE) -C facebook setup)
.PHONY : fmt
fmt :
parallel $( OCAMLFORMAT_EXE) $( OCAMLFORMAT_ARGS) -i ::: $$ ( git diff --name-only --diff-filter= ACMRU $$ ( git merge-base origin/master HEAD) | grep " \.mli\? $$ " )
DUNE_ML := $( shell find * -name 'dune*.in' | grep -v workspace | grep -v infer-source | grep -v infer/src/deadcode/dune.in)
.PHONY : fmt_dune
fmt_dune :
parallel $( OCAMLFORMAT_EXE) $( OCAMLFORMAT_ARGS) -i ::: $( DUNE_ML)
SRC_ML := $( shell find * \( -name _build -or -name facebook-clang-plugins -or -path facebook/dependencies -or -path sledge/llvm -or -path sledge/.llvm_build \) -not -prune -or -type f -and -name '*' .ml -or -name '*' .mli 2>/dev/null)
.PHONY : fmt_all
fmt_all :
parallel $( OCAMLFORMAT_EXE) $( OCAMLFORMAT_ARGS) -i ::: $( SRC_ML) $( DUNE_ML)
# pre-building these avoids race conditions when doing multiple builds in parallel
.PHONY : src_build_common
src_build_common :
$( QUIET) $( call silent_on_success,Generating source dependencies,\
[build] switch to 4.05.0+flambda by default
Summary:
With flambda (`-O3`), compilation time is ~5x slower, but the backend is ~25% faster!
To mitigate the atrocious compilation times, introduce a new `opt` build mode in the jbuilder files.
- build in "opt" mode by default from the toplevel (so that install scripts and external users get the fastest infer by default), in "default" mode by default from infer/src (since the latter is only called directly by infer devs, for faster builds)
- `make byte` is as fast as before in any mode
- `make test` will build "opt" by default, which is very slow. Solution for testing (or building the models) locally: `make BUILD_MODE=default test`.
- You can even change the default locally with `export BUILD_MODE=default`.
The benchmarks are to be taken with a sizable pinch of salt because I ran them only once and other stuff could be running in the background. That said, the perf win is consistent across all projects, with 15-20% win in wallclock time and around 25% win in total CPU time, ~9% win in sys time, and ~25% fewer minor allocations, and ~5-10% fewer overall allocations. This is only for the backend; the capture is by and large unaffected (either the same or a tad faster within noise range).
Here are the results running on OpenSSL 1.0.2d on osx (12 cores, 32G RAM)
=== base
infer binary: 26193088 bytes
compile time: 40s
capture:
```lang=text
real 1m7.513s
user 3m11.437s
sys 0m55.236s
```
analysis:
```lang=text
real 5m41.580s
user 61m37.855s
sys 1m12.870s
```
Memory profile:
```lang=json
{
...
"minor_gb": 0.1534719169139862,
"promoted_gb": 0.0038930922746658325,
"major_gb": 0.4546157643198967,
"allocated_gb": 0.6041945889592171,
"minor_collections": 78,
"major_collections": 23,
"compactions": 7,
"top_heap_gb": 0.07388687133789062,
"stack_kb": 0.3984375,
"minor_heap_kb": 8192.0,
...
}
```
=== flambda with stock options (no `-Oclassic`, just the same flags as base)
Exactly the same as base.
=== flambda `-O3`
infer binary: 56870376 bytes (2.17x bigger)
compile time: 191s (4.78x slower)
capture is the same as base:
```lang=text
real 1m9.203s
user 3m12.242s
sys 0m58.905s
```
analysis is ~20% wallclock time faster, ~25% CPU time faster:
```lang=text
real 4m32.656s
user 46m43.987s
sys 1m2.424s
```
memory usage is a bit lower too:
```lang=json
{
...
"minor_gb": 0.11583046615123749, // 75% of previous
"promoted_gb": 0.00363825261592865, // 93% of previous
"major_gb": 0.45415670424699783, // about same
"allocated_gb": 0.5663489177823067, // 94% of previous
"minor_collections": 73,
"major_collections": 22,
"compactions": 7,
"top_heap_gb": 0.07165145874023438,
"stack_kb": 0.3359375,
"minor_heap_kb": 8192.0,
...
}
```
=== flambda `-O2`
Not nearly as exciting as `-O3`, but the compilation cost is still quite high:
infer: 37826856 bytes
compilation of infer: 100s
Capture and analysis timings are mostly the same as base.
Reviewed By: jberdine
Differential Revision: D4867979
fbshipit-source-id: 99230b7
7 years ago
$( MAKE_SOURCE) src_build_common)
.PHONY : src_build
src_build : src_build_common
$( QUIET) $( call silent_on_success,Building native( $( BUILD_MODE) ) Infer,\
[build] switch to 4.05.0+flambda by default
Summary:
With flambda (`-O3`), compilation time is ~5x slower, but the backend is ~25% faster!
To mitigate the atrocious compilation times, introduce a new `opt` build mode in the jbuilder files.
- build in "opt" mode by default from the toplevel (so that install scripts and external users get the fastest infer by default), in "default" mode by default from infer/src (since the latter is only called directly by infer devs, for faster builds)
- `make byte` is as fast as before in any mode
- `make test` will build "opt" by default, which is very slow. Solution for testing (or building the models) locally: `make BUILD_MODE=default test`.
- You can even change the default locally with `export BUILD_MODE=default`.
The benchmarks are to be taken with a sizable pinch of salt because I ran them only once and other stuff could be running in the background. That said, the perf win is consistent across all projects, with 15-20% win in wallclock time and around 25% win in total CPU time, ~9% win in sys time, and ~25% fewer minor allocations, and ~5-10% fewer overall allocations. This is only for the backend; the capture is by and large unaffected (either the same or a tad faster within noise range).
Here are the results running on OpenSSL 1.0.2d on osx (12 cores, 32G RAM)
=== base
infer binary: 26193088 bytes
compile time: 40s
capture:
```lang=text
real 1m7.513s
user 3m11.437s
sys 0m55.236s
```
analysis:
```lang=text
real 5m41.580s
user 61m37.855s
sys 1m12.870s
```
Memory profile:
```lang=json
{
...
"minor_gb": 0.1534719169139862,
"promoted_gb": 0.0038930922746658325,
"major_gb": 0.4546157643198967,
"allocated_gb": 0.6041945889592171,
"minor_collections": 78,
"major_collections": 23,
"compactions": 7,
"top_heap_gb": 0.07388687133789062,
"stack_kb": 0.3984375,
"minor_heap_kb": 8192.0,
...
}
```
=== flambda with stock options (no `-Oclassic`, just the same flags as base)
Exactly the same as base.
=== flambda `-O3`
infer binary: 56870376 bytes (2.17x bigger)
compile time: 191s (4.78x slower)
capture is the same as base:
```lang=text
real 1m9.203s
user 3m12.242s
sys 0m58.905s
```
analysis is ~20% wallclock time faster, ~25% CPU time faster:
```lang=text
real 4m32.656s
user 46m43.987s
sys 1m2.424s
```
memory usage is a bit lower too:
```lang=json
{
...
"minor_gb": 0.11583046615123749, // 75% of previous
"promoted_gb": 0.00363825261592865, // 93% of previous
"major_gb": 0.45415670424699783, // about same
"allocated_gb": 0.5663489177823067, // 94% of previous
"minor_collections": 73,
"major_collections": 22,
"compactions": 7,
"top_heap_gb": 0.07165145874023438,
"stack_kb": 0.3359375,
"minor_heap_kb": 8192.0,
...
}
```
=== flambda `-O2`
Not nearly as exciting as `-O3`, but the compilation cost is still quite high:
infer: 37826856 bytes
compilation of infer: 100s
Capture and analysis timings are mostly the same as base.
Reviewed By: jberdine
Differential Revision: D4867979
fbshipit-source-id: 99230b7
7 years ago
$( MAKE_SOURCE) infer)
.PHONY : byte
byte : src_build_common
$( QUIET) $( call silent_on_success,Building byte Infer,\
[build] switch to 4.05.0+flambda by default
Summary:
With flambda (`-O3`), compilation time is ~5x slower, but the backend is ~25% faster!
To mitigate the atrocious compilation times, introduce a new `opt` build mode in the jbuilder files.
- build in "opt" mode by default from the toplevel (so that install scripts and external users get the fastest infer by default), in "default" mode by default from infer/src (since the latter is only called directly by infer devs, for faster builds)
- `make byte` is as fast as before in any mode
- `make test` will build "opt" by default, which is very slow. Solution for testing (or building the models) locally: `make BUILD_MODE=default test`.
- You can even change the default locally with `export BUILD_MODE=default`.
The benchmarks are to be taken with a sizable pinch of salt because I ran them only once and other stuff could be running in the background. That said, the perf win is consistent across all projects, with 15-20% win in wallclock time and around 25% win in total CPU time, ~9% win in sys time, and ~25% fewer minor allocations, and ~5-10% fewer overall allocations. This is only for the backend; the capture is by and large unaffected (either the same or a tad faster within noise range).
Here are the results running on OpenSSL 1.0.2d on osx (12 cores, 32G RAM)
=== base
infer binary: 26193088 bytes
compile time: 40s
capture:
```lang=text
real 1m7.513s
user 3m11.437s
sys 0m55.236s
```
analysis:
```lang=text
real 5m41.580s
user 61m37.855s
sys 1m12.870s
```
Memory profile:
```lang=json
{
...
"minor_gb": 0.1534719169139862,
"promoted_gb": 0.0038930922746658325,
"major_gb": 0.4546157643198967,
"allocated_gb": 0.6041945889592171,
"minor_collections": 78,
"major_collections": 23,
"compactions": 7,
"top_heap_gb": 0.07388687133789062,
"stack_kb": 0.3984375,
"minor_heap_kb": 8192.0,
...
}
```
=== flambda with stock options (no `-Oclassic`, just the same flags as base)
Exactly the same as base.
=== flambda `-O3`
infer binary: 56870376 bytes (2.17x bigger)
compile time: 191s (4.78x slower)
capture is the same as base:
```lang=text
real 1m9.203s
user 3m12.242s
sys 0m58.905s
```
analysis is ~20% wallclock time faster, ~25% CPU time faster:
```lang=text
real 4m32.656s
user 46m43.987s
sys 1m2.424s
```
memory usage is a bit lower too:
```lang=json
{
...
"minor_gb": 0.11583046615123749, // 75% of previous
"promoted_gb": 0.00363825261592865, // 93% of previous
"major_gb": 0.45415670424699783, // about same
"allocated_gb": 0.5663489177823067, // 94% of previous
"minor_collections": 73,
"major_collections": 22,
"compactions": 7,
"top_heap_gb": 0.07165145874023438,
"stack_kb": 0.3359375,
"minor_heap_kb": 8192.0,
...
}
```
=== flambda `-O2`
Not nearly as exciting as `-O3`, but the compilation cost is still quite high:
infer: 37826856 bytes
compilation of infer: 100s
Capture and analysis timings are mostly the same as base.
Reviewed By: jberdine
Differential Revision: D4867979
fbshipit-source-id: 99230b7
7 years ago
$( MAKE_SOURCE) byte)
.PHONY : check
check : src_build_common
$( QUIET) $( call silent_on_success,Building artifacts for tooling support,\
$( MAKE_SOURCE) check)
# deadcode analysis: only do the deadcode detection on Facebook builds and if GNU sed is available
.PHONY : real_deadcode
real_deadcode : src_build_common
$( QUIET) $( call silent_on_success,Building all OCaml code,\
$( MAKE_SOURCE) build_all)
$( QUIET) $( call silent_on_success,Testing there is no dead OCaml code,\
$( MAKE) -C $( SRC_DIR) /deadcode)
.PHONY : deadcode
deadcode :
i f e q ( $( IS_FACEBOOK_TREE ) , n o )
$( QUIET) echo "Deadcode detection only works in Facebook builds, skipping"
e n d i f
i f e q ( $( GNU_SED ) , n o )
$( QUIET) echo "Deadcode detection only works with GNU sed installed, skipping"
e n d i f
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
i f n e q ( $( GNU_SED ) , n o )
deadcode : real_deadcode
e n d i f
e n d i f
.PHONY : toplevel toplevel_test
toplevel toplevel_test : src_build_common
toplevel :
$( QUIET) $( call silent_on_success,Building Infer REPL,\
$( MAKE_SOURCE) toplevel)
$( QUIET) echo
$( QUIET) echo "You can now use the infer REPL:"
$( QUIET) echo " \" $( ABSOLUTE_ROOT_DIR) /scripts/infer_repl\" "
[RFC][build] Use dune environments and profiles instead of contexts
Summary:
With profiles and `(env ...)` stanza it's possible to consolidate
various ocamlc/ocamlopt/etc setups in a single place.
Where previously we needed to append `dune.common` to every dune file
and specify `flags` and `ocamlopt_flags` now the flags are specified
in `env` and applied accross the board.
This allows to
1. simplify build definitions,
2. avoid the need to generate dune files,
3. use plain sexps instead of OCaml and JBuilder plugin in build
files.
(I'll try to address 2 and 3 in the followup patches).
Existing `make` targets should continue working as before. Also, we
can use dune CLI like so:
```
infer/src$ dune printenv --profile opt # <- very useful for introspection
infer/src$ dune build check
infer/src$ dune build check --profile test
infer/src$ dune build infer.exe --profile dev
infer/src$ dune build infer.exe --profile opt
```
Also, with just 1 context something like `dune runtest` will run unit
tests only once instead of N times, where N is the number of contexts.
Now, there's one difference compared to the previous setup with
contexts:
- Previously, each context had its own build folder, and building infer
in opt context didn't invalidate any of the build artifacts in default
context. Therefore, alternating between `make` and `make opt` had low
overhead at the expense of having N copies of all build artifacts (1
for every context).
- Now, there's just 1 build folder and switching between profiles does
invalidate some artifacts (but not all) and rebuild takes a bit more
time.
So, if you're alternating like crazy between profiles your experience
may get worse (but not necessarily, more on that below). If you want
to trigger an opt build occasionally, you shouldn't notice much
difference.
For those who are concerned about slower build times when alternating
between different build profiles, there's a solution: [dune
cache](https://dune.readthedocs.io/en/stable/caching.html).
You can enable it by creating a file `~/.config/dune/config` with the
following contents:
```
(lang dune 2.0)
(cache enabled)
```
With cache enabled switching between different build profiles (but
also branches and commits) has ~0 overhead.
Dune cache works fine on Linux, but unfortunately there are [certain
problems with
MacOS](https://github.com/ocaml/dune/issues/3233) (hopefully, those
will be fixed soon and then there will be no downsides to using
profiles compared to contexts for our case).
Reviewed By: jvillard
Differential Revision: D20247864
fbshipit-source-id: 5f8afa0db
5 years ago
toplevel_test :
$( QUIET) $( call silent_on_success,Building Infer REPL,\
$( MAKE_SOURCE) toplevel)
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
byte src_build_common src_build : fb -setup
e n d i f
i f e q ( $( BUILD_C_ANALYZERS ) , y e s )
byte src_build src_build_common : clang_plugin
e n d i f
i f n e q ( $( NINJA ) , n o )
FCP_COMPILE_ARGS = --ninja --sequential-link
e n d i f
$(INFER_COMMAND_MANUALS) : src_build $( MAKEFILE_LIST )
$( QUIET) $( MKDIR_P) $( @D)
$( QUIET) $( INFER_BIN) $( patsubst infer-%.1,%,$( @F) ) --help-scrubbed --help-format= groff > $@
$(INFER_COMMAND_TEXT_MANUALS) : src_build $( MAKEFILE_LIST )
$( QUIET) $( MKDIR_P) $( @D)
$( QUIET) $( INFER_BIN) $( patsubst infer-%.txt,%,$( @F) ) --help-scrubbed --help-format= plain > $@
$(INFER_MANUAL) : src_build $( MAKEFILE_LIST )
$( QUIET) $( MKDIR_P) $( @D)
$( QUIET) $( INFER_BIN) --help-scrubbed --help-format= groff > $@
$(INFER_TEXT_MANUAL) : src_build $( MAKEFILE_LIST )
$( QUIET) $( MKDIR_P) $( @D)
$( QUIET) $( INFER_BIN) --help-scrubbed --help-format= plain > $@
$(INFER_FULL_TEXT_MANUAL) : src_build $( MAKEFILE_LIST )
$( QUIET) $( MKDIR_P) $( @D)
$( QUIET) $( INFER_BIN) --help-scrubbed-full --help-format= plain > $@
$(INFER_GROFF_MANUALS_GZIPPED) : %.gz : %
$( QUIET) $( REMOVE) $@
gzip $<
manuals :
$( QUIET) $( call silent_on_success,Building Infer manuals,\
$( MAKE) $( INFER_MANUALS) )
infer_models : src_build
i f e q ( $( BUILD_JAVA_ANALYZERS ) , y e s )
[RFC][build] Use dune environments and profiles instead of contexts
Summary:
With profiles and `(env ...)` stanza it's possible to consolidate
various ocamlc/ocamlopt/etc setups in a single place.
Where previously we needed to append `dune.common` to every dune file
and specify `flags` and `ocamlopt_flags` now the flags are specified
in `env` and applied accross the board.
This allows to
1. simplify build definitions,
2. avoid the need to generate dune files,
3. use plain sexps instead of OCaml and JBuilder plugin in build
files.
(I'll try to address 2 and 3 in the followup patches).
Existing `make` targets should continue working as before. Also, we
can use dune CLI like so:
```
infer/src$ dune printenv --profile opt # <- very useful for introspection
infer/src$ dune build check
infer/src$ dune build check --profile test
infer/src$ dune build infer.exe --profile dev
infer/src$ dune build infer.exe --profile opt
```
Also, with just 1 context something like `dune runtest` will run unit
tests only once instead of N times, where N is the number of contexts.
Now, there's one difference compared to the previous setup with
contexts:
- Previously, each context had its own build folder, and building infer
in opt context didn't invalidate any of the build artifacts in default
context. Therefore, alternating between `make` and `make opt` had low
overhead at the expense of having N copies of all build artifacts (1
for every context).
- Now, there's just 1 build folder and switching between profiles does
invalidate some artifacts (but not all) and rebuild takes a bit more
time.
So, if you're alternating like crazy between profiles your experience
may get worse (but not necessarily, more on that below). If you want
to trigger an opt build occasionally, you shouldn't notice much
difference.
For those who are concerned about slower build times when alternating
between different build profiles, there's a solution: [dune
cache](https://dune.readthedocs.io/en/stable/caching.html).
You can enable it by creating a file `~/.config/dune/config` with the
following contents:
```
(lang dune 2.0)
(cache enabled)
```
With cache enabled switching between different build profiles (but
also branches and commits) has ~0 overhead.
Dune cache works fine on Linux, but unfortunately there are [certain
problems with
MacOS](https://github.com/ocaml/dune/issues/3233) (hopefully, those
will be fixed soon and then there will be no downsides to using
profiles compared to contexts for our case).
Reviewed By: jvillard
Differential Revision: D20247864
fbshipit-source-id: 5f8afa0db
5 years ago
$( QUIET) $( call silent_on_success,Building infer annotations,\
$( MAKE) -C $( ANNOTATIONS_DIR) )
e n d i f
[RFC][build] Use dune environments and profiles instead of contexts
Summary:
With profiles and `(env ...)` stanza it's possible to consolidate
various ocamlc/ocamlopt/etc setups in a single place.
Where previously we needed to append `dune.common` to every dune file
and specify `flags` and `ocamlopt_flags` now the flags are specified
in `env` and applied accross the board.
This allows to
1. simplify build definitions,
2. avoid the need to generate dune files,
3. use plain sexps instead of OCaml and JBuilder plugin in build
files.
(I'll try to address 2 and 3 in the followup patches).
Existing `make` targets should continue working as before. Also, we
can use dune CLI like so:
```
infer/src$ dune printenv --profile opt # <- very useful for introspection
infer/src$ dune build check
infer/src$ dune build check --profile test
infer/src$ dune build infer.exe --profile dev
infer/src$ dune build infer.exe --profile opt
```
Also, with just 1 context something like `dune runtest` will run unit
tests only once instead of N times, where N is the number of contexts.
Now, there's one difference compared to the previous setup with
contexts:
- Previously, each context had its own build folder, and building infer
in opt context didn't invalidate any of the build artifacts in default
context. Therefore, alternating between `make` and `make opt` had low
overhead at the expense of having N copies of all build artifacts (1
for every context).
- Now, there's just 1 build folder and switching between profiles does
invalidate some artifacts (but not all) and rebuild takes a bit more
time.
So, if you're alternating like crazy between profiles your experience
may get worse (but not necessarily, more on that below). If you want
to trigger an opt build occasionally, you shouldn't notice much
difference.
For those who are concerned about slower build times when alternating
between different build profiles, there's a solution: [dune
cache](https://dune.readthedocs.io/en/stable/caching.html).
You can enable it by creating a file `~/.config/dune/config` with the
following contents:
```
(lang dune 2.0)
(cache enabled)
```
With cache enabled switching between different build profiles (but
also branches and commits) has ~0 overhead.
Dune cache works fine on Linux, but unfortunately there are [certain
problems with
MacOS](https://github.com/ocaml/dune/issues/3233) (hopefully, those
will be fixed soon and then there will be no downsides to using
profiles compared to contexts for our case).
Reviewed By: jvillard
Differential Revision: D20247864
fbshipit-source-id: 5f8afa0db
5 years ago
$( QUIET) $( call silent_on_success,Building infer models,\
$( MAKE) -C $( MODELS_DIR) all)
.PHONY : infer byte_infer
[RFC][build] Use dune environments and profiles instead of contexts
Summary:
With profiles and `(env ...)` stanza it's possible to consolidate
various ocamlc/ocamlopt/etc setups in a single place.
Where previously we needed to append `dune.common` to every dune file
and specify `flags` and `ocamlopt_flags` now the flags are specified
in `env` and applied accross the board.
This allows to
1. simplify build definitions,
2. avoid the need to generate dune files,
3. use plain sexps instead of OCaml and JBuilder plugin in build
files.
(I'll try to address 2 and 3 in the followup patches).
Existing `make` targets should continue working as before. Also, we
can use dune CLI like so:
```
infer/src$ dune printenv --profile opt # <- very useful for introspection
infer/src$ dune build check
infer/src$ dune build check --profile test
infer/src$ dune build infer.exe --profile dev
infer/src$ dune build infer.exe --profile opt
```
Also, with just 1 context something like `dune runtest` will run unit
tests only once instead of N times, where N is the number of contexts.
Now, there's one difference compared to the previous setup with
contexts:
- Previously, each context had its own build folder, and building infer
in opt context didn't invalidate any of the build artifacts in default
context. Therefore, alternating between `make` and `make opt` had low
overhead at the expense of having N copies of all build artifacts (1
for every context).
- Now, there's just 1 build folder and switching between profiles does
invalidate some artifacts (but not all) and rebuild takes a bit more
time.
So, if you're alternating like crazy between profiles your experience
may get worse (but not necessarily, more on that below). If you want
to trigger an opt build occasionally, you shouldn't notice much
difference.
For those who are concerned about slower build times when alternating
between different build profiles, there's a solution: [dune
cache](https://dune.readthedocs.io/en/stable/caching.html).
You can enable it by creating a file `~/.config/dune/config` with the
following contents:
```
(lang dune 2.0)
(cache enabled)
```
With cache enabled switching between different build profiles (but
also branches and commits) has ~0 overhead.
Dune cache works fine on Linux, but unfortunately there are [certain
problems with
MacOS](https://github.com/ocaml/dune/issues/3233) (hopefully, those
will be fixed soon and then there will be no downsides to using
profiles compared to contexts for our case).
Reviewed By: jvillard
Differential Revision: D20247864
fbshipit-source-id: 5f8afa0db
5 years ago
infer byte_infer : infer_models
infer : src_build
byte_infer : byte
.PHONY : opt
opt :
$( QUIET) $( MAKE) BUILD_MODE = opt infer
PLUGIN_SETUP_SCRIPT ?= setup.sh
.PHONY : clang_setup
clang_setup :
# if clang is already built then let the user know they might not need to rebuild clang
$( QUIET) export CC = " $( CC) " CFLAGS = " $( CFLAGS) " ; \
export CXX = " $( CXX) " CXXFLAGS = " $( CXXFLAGS) " ; \
export CPP = " $( CPP) " LDFLAGS = " $( LDFLAGS) " LIBS = " $( LIBS) " ; \
$( FCP_DIR) /clang/$( PLUGIN_SETUP_SCRIPT) --only-check-install || { \
if [ -x '$(FCP_DIR)' /clang/install/bin/clang ] ; then \
echo '$(TERM_INFO)*** Now building clang, this will take a while...$(TERM_RESET)' >& 2; \
echo '$(TERM_INFO)*** If you believe that facebook-clang-plugins/clang/install is up-to-date you can$(TERM_RESET)' >& 2; \
echo '$(TERM_INFO)*** interrupt the compilation (Control-C) and run this to prevent clang from being rebuilt:$(TERM_RESET)' >& 2; \
echo >& 2 ; \
echo '$(TERM_INFO) $(FCP_DIR)/clang/$(PLUGIN_SETUP_SCRIPT) --only-record-install$(TERM_RESET)' >& 2; \
echo >& 2 ; \
echo '$(TERM_INFO)(TIP: you can also force a clang rebuild by removing $(FCP_DIR)/clang/installed.version)$(TERM_RESET)' >& 2; \
echo >& 2 ; \
fi ; \
$( FCP_DIR) /clang/$( PLUGIN_SETUP_SCRIPT) $( FCP_COMPILE_ARGS) ; \
}
.PHONY : clang_plugin
clang_plugin : clang_setup
$( QUIET) $( call silent_on_success,Building clang plugin,\
$( MAKE) -C $( FCP_DIR) /libtooling all \
CC = " $( CC) " CXX = " $( CXX) " \
CFLAGS = " $( CFLAGS) " CXXFLAGS = " $( CXXFLAGS) " \
CPP = " $( CPP) " LDFLAGS = " $( LDFLAGS) " LIBS = " $( LIBS) " \
LOCAL_CLANG = $( CLANG_PREFIX) /bin/clang \
CLANG_PREFIX = $( CLANG_PREFIX) \
CLANG_INCLUDES = $( CLANG_INCLUDES) \
SDKPATH = $( XCODE_ISYSROOT) \
)
$( QUIET) $( call silent_on_success,Building clang plugin OCaml interface,\
$( MAKE) -C $( FCP_DIR) /clang-ocaml all \
build/clang_ast_proj.ml build/clang_ast_proj.mli \
CC = $( CC) CXX = $( CXX) \
CFLAGS = " $( CFLAGS) " CXXFLAGS = " $( CXXFLAGS) " \
CPP = " $( CPP) " LDFLAGS = " $( LDFLAGS) " LIBS = " $( LIBS) " \
LOCAL_CLANG = $( CLANG_PREFIX) /bin/clang \
CLANG_PREFIX = $( CLANG_PREFIX) \
CLANG_INCLUDES = $( CLANG_INCLUDES) \
SDKPATH = $( XCODE_ISYSROOT) \
)
.PHONY : clang_plugin_test
clang_plugin_test : clang_setup
$( QUIET) $( call silent_on_success,Running facebook-clang-plugins/libtooling/ tests,\
$( MAKE) -C $( FCP_DIR) /libtooling test \
CC = $( CC) CXX = $( CXX) \
CFLAGS = " $( CFLAGS) " CXXFLAGS = " $( CXXFLAGS) " \
CPP = " $( CPP) " LDFLAGS = " $( LDFLAGS) " LIBS = " $( LIBS) " \
LOCAL_CLANG = $( CLANG_PREFIX) /bin/clang \
CLANG_PREFIX = $( CLANG_PREFIX) \
CLANG_INCLUDES = $( CLANG_INCLUDES) \
SDKPATH = $( XCODE_ISYSROOT) \
)
$( QUIET) $( call silent_on_success,Running facebook-clang-plugins/clang-ocaml/ tests,\
$( MAKE) -C $( FCP_DIR) /clang-ocaml test \
CC = $( CC) CXX = $( CXX) \
CFLAGS = " $( CFLAGS) " CXXFLAGS = " $( CXXFLAGS) " \
CPP = " $( CPP) " LDFLAGS = " $( LDFLAGS) " LIBS = " $( LIBS) " \
LOCAL_CLANG = $( CLANG_PREFIX) /bin/clang \
CLANG_PREFIX = $( CLANG_PREFIX) \
CLANG_INCLUDES = $( CLANG_INCLUDES) \
SDKPATH = $( XCODE_ISYSROOT) \
)
.PHONY : clang_plugin_test_replace
clang_plugin_test_replace : clang_setup
$( QUIET) $( call silent_on_success,Running facebook-clang-plugins/libtooling/ record tests,\
$( MAKE) -C $( FCP_DIR) /libtooling record-test-outputs \
CC = $( CC) CXX = $( CXX) \
CFLAGS = " $( CFLAGS) " CXXFLAGS = " $( CXXFLAGS) " \
CPP = " $( CPP) " LDFLAGS = " $( LDFLAGS) " LIBS = " $( LIBS) " \
LOCAL_CLANG = $( CLANG_PREFIX) /bin/clang \
CLANG_PREFIX = $( CLANG_PREFIX) \
CLANG_INCLUDES = $( CLANG_INCLUDES) \
SDKPATH = $( XCODE_ISYSROOT) \
)
$( QUIET) $( call silent_on_success,Running facebook-clang-plugins/clang-ocaml/ record tests,\
$( MAKE) -C $( FCP_DIR) /clang-ocaml record-test-outputs \
CC = $( CC) CXX = $( CXX) \
CFLAGS = " $( CFLAGS) " CXXFLAGS = " $( CXXFLAGS) " \
CPP = " $( CPP) " LDFLAGS = " $( LDFLAGS) " LIBS = " $( LIBS) " \
LOCAL_CLANG = $( CLANG_PREFIX) /bin/clang \
CLANG_PREFIX = $( CLANG_PREFIX) \
CLANG_INCLUDES = $( CLANG_INCLUDES) \
SDKPATH = $( XCODE_ISYSROOT) \
)
.PHONY : ocaml_unit_test
ocaml_unit_test : src_build_common infer_models
$( QUIET) $( call silent_on_success,Running OCaml unit tests,\
$( MAKE_SOURCE) unit)
d e f i n e s i l e n c e _ m a k e
$( 1) 2> >( grep -v 'warning: \(ignoring old\|overriding\) \(commands\|recipe\) for target' )
e n d e f
.PHONY : $( DIRECT_TESTS :%=direct_ %_test )
$(DIRECT_TESTS : %=direct_ %_test ): infer
$( QUIET) $( call silent_on_success,Running test: $( subst _, ,$@ ) ,\
$( call silence_make,\
$( MAKE) -C \
$( INFER_DIR) /tests/codetoanalyze/$( shell printf $@ | cut -f 2 -d _) /$( shell printf $@ | cut -f 3 -d _) \
test ) )
.PHONY : $( DIRECT_TESTS :%=direct_ %_print )
$(DIRECT_TESTS : %=direct_ %_print ): infer
$( QUIET) $( call silent_on_success,Running: $( subst _, ,$@ ) ,\
$( call silence_make,\
$( MAKE) -C \
$( INFER_DIR) /tests/codetoanalyze/$( shell printf $@ | cut -f 2 -d _) /$( shell printf $@ | cut -f 3 -d _) \
print) )
.PHONY : $( DIRECT_TESTS :%=direct_ %_clean )
$(DIRECT_TESTS : %=direct_ %_clean ):
$( QUIET) $( call silent_on_success,Cleaning: $( subst _, ,$@ ) ,\
$( call silence_make,\
$( MAKE) -C \
$( INFER_DIR) /tests/codetoanalyze/$( shell printf $@ | cut -f 2 -d _) /$( shell printf $@ | cut -f 3 -d _) \
clean) )
.PHONY : $( DIRECT_TESTS :%=direct_ %_replace )
$(DIRECT_TESTS : %=direct_ %_replace ): infer
$( QUIET) $( call silent_on_success,Recording: $( subst _, ,$@ ) ,\
$( call silence_make,\
$( MAKE) -C \
$( INFER_DIR) /tests/codetoanalyze/$( shell printf $@ | cut -f 2 -d _) /$( shell printf $@ | cut -f 3 -d _) \
replace) )
.PHONY : direct_tests
direct_tests : $( DIRECT_TESTS :%=direct_ %_test )
.PHONY : cost_tests
cost_tests : $( COST_TESTS :%=direct_ %_test )
.PHONY : cost_tests_clean
cost_tests_clean : $( COST_TESTS :%=direct_ %_clean )
.PHONY : cost_tests_replace
cost_tests_replace : $( COST_TESTS :%=direct_ %_replace )
.PHONY : cost_tests_print
cost_tests_print : $( COST_TESTS :%=direct_ %_print )
.PHONY : $( BUILD_SYSTEMS_TESTS :%=build_ %_test )
$(BUILD_SYSTEMS_TESTS : %=build_ %_test ): infer
$( QUIET) $( call silent_on_success,Running test: $( subst _, ,$@ ) ,\
$( call silence_make,\
$( MAKE) -C $( INFER_DIR) /tests/build_systems/$( patsubst build_%_test,%,$@ ) test ) )
.PHONY : $( BUILD_SYSTEMS_TESTS :%=build_ %_print )
$(BUILD_SYSTEMS_TESTS : %=build_ %_print ): infer
$( QUIET) $( call silent_on_success,Running: $( subst _, ,$@ ) ,\
$( call silence_make,\
$( MAKE) -C $( INFER_DIR) /tests/build_systems/$( patsubst build_%_print,%,$@ ) print) )
.PHONY : $( BUILD_SYSTEMS_TESTS :%=build_ %_clean )
$(BUILD_SYSTEMS_TESTS : %=build_ %_clean ):
$( QUIET) $( call silent_on_success,Cleaning: $( subst _, ,$@ ) ,\
$( call silence_make,\
$( MAKE) -C $( INFER_DIR) /tests/build_systems/$( patsubst build_%_clean,%,$@ ) clean) )
.PHONY : $( BUILD_SYSTEMS_TESTS :%=build_ %_replace )
$(BUILD_SYSTEMS_TESTS : %=build_ %_replace ): infer
$( QUIET) $( call silent_on_success,Recording: $( subst _, ,$@ ) ,\
$( call silence_make,\
$( MAKE) -C $( INFER_DIR) /tests/build_systems/$( patsubst build_%_replace,%,$@ ) replace) )
build_infertop_print build_infertop_test build_infertop_replace : toplevel_test
.PHONY : build_systems_tests
build_systems_tests : $( BUILD_SYSTEMS_TESTS :%=build_ %_test )
.PHONY : endtoend_test
endtoend_test : $( BUILD_SYSTEMS_TESTS :%=build_ %_test ) $( DIRECT_TESTS :%=direct_ %_test )
.PHONY : check_missing_mli
check_missing_mli :
$( QUIET) for x in $$ ( find $( INFER_DIR) /src -name "*.ml" ) ; do \
test -f " $$ x " i || echo Missing " $$ x " i; done
.PHONY : checkCopyright
checkCopyright : src_build_common
$( QUIET) $( call silent_on_success,Building checkCopyright,\
$( MAKE) -C $( SRC_DIR) checkCopyright)
.PHONY : validate -skel
validate-skel :
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
$( QUIET) $( call silent_on_success,Validating facebook/,\
$( MAKE) -C facebook validate)
e n d i f
.PHONY : crash_if_not_all_analyzers_enabled
crash_if_not_all_analyzers_enabled :
i f n e q ( $( BUILD_C_ANALYZERS ) + $( BUILD_JAVA_ANALYZERS ) , y e s + y e s )
i f n e q ( $( BUILD_C_ANALYZERS ) , y e s )
@echo '*** ERROR: Cannot run the full tests: the Clang analyzers are disabled.'
@echo '*** ERROR: You can run clang-only tests with:'
@echo '*** ERROR:'
@echo '*** ERROR: make config_tests'
@echo '*** ERROR:'
e n d i f
i f n e q ( $( BUILD_JAVA_ANALYZERS ) , y e s )
@echo '*** ERROR: Cannot run the full tests: the Java analyzers are disabled.'
@echo '*** ERROR: You can run Java-only tests with:'
@echo '*** ERROR:'
@echo '*** ERROR: make config_tests'
@echo '*** ERROR:'
e n d i f
@echo '*** ERROR: To run the full set of tests, please enable all the analyzers.'
@exit 1
e l s e
@:
e n d i f
.PHONY : mod_dep
mod_dep : src_build_common
$( QUIET) $( call silent_on_success,Building Infer source dependency graph,\
$( MAKE) -C $( SRC_DIR) mod_dep.dot)
.PHONY : config_tests
config_tests : ocaml_unit_test validate -skel mod_dep
[RFC][build] Use dune environments and profiles instead of contexts
Summary:
With profiles and `(env ...)` stanza it's possible to consolidate
various ocamlc/ocamlopt/etc setups in a single place.
Where previously we needed to append `dune.common` to every dune file
and specify `flags` and `ocamlopt_flags` now the flags are specified
in `env` and applied accross the board.
This allows to
1. simplify build definitions,
2. avoid the need to generate dune files,
3. use plain sexps instead of OCaml and JBuilder plugin in build
files.
(I'll try to address 2 and 3 in the followup patches).
Existing `make` targets should continue working as before. Also, we
can use dune CLI like so:
```
infer/src$ dune printenv --profile opt # <- very useful for introspection
infer/src$ dune build check
infer/src$ dune build check --profile test
infer/src$ dune build infer.exe --profile dev
infer/src$ dune build infer.exe --profile opt
```
Also, with just 1 context something like `dune runtest` will run unit
tests only once instead of N times, where N is the number of contexts.
Now, there's one difference compared to the previous setup with
contexts:
- Previously, each context had its own build folder, and building infer
in opt context didn't invalidate any of the build artifacts in default
context. Therefore, alternating between `make` and `make opt` had low
overhead at the expense of having N copies of all build artifacts (1
for every context).
- Now, there's just 1 build folder and switching between profiles does
invalidate some artifacts (but not all) and rebuild takes a bit more
time.
So, if you're alternating like crazy between profiles your experience
may get worse (but not necessarily, more on that below). If you want
to trigger an opt build occasionally, you shouldn't notice much
difference.
For those who are concerned about slower build times when alternating
between different build profiles, there's a solution: [dune
cache](https://dune.readthedocs.io/en/stable/caching.html).
You can enable it by creating a file `~/.config/dune/config` with the
following contents:
```
(lang dune 2.0)
(cache enabled)
```
With cache enabled switching between different build profiles (but
also branches and commits) has ~0 overhead.
Dune cache works fine on Linux, but unfortunately there are [certain
problems with
MacOS](https://github.com/ocaml/dune/issues/3233) (hopefully, those
will be fixed soon and then there will be no downsides to using
profiles compared to contexts for our case).
Reviewed By: jvillard
Differential Revision: D20247864
fbshipit-source-id: 5f8afa0db
5 years ago
$( MAKE) endtoend_test checkCopyright
$( MAKE) manuals
i f n e q ( $( filter endtoend_test ,$ ( MAKECMDGOALS ) ) , )
[RFC][build] Use dune environments and profiles instead of contexts
Summary:
With profiles and `(env ...)` stanza it's possible to consolidate
various ocamlc/ocamlopt/etc setups in a single place.
Where previously we needed to append `dune.common` to every dune file
and specify `flags` and `ocamlopt_flags` now the flags are specified
in `env` and applied accross the board.
This allows to
1. simplify build definitions,
2. avoid the need to generate dune files,
3. use plain sexps instead of OCaml and JBuilder plugin in build
files.
(I'll try to address 2 and 3 in the followup patches).
Existing `make` targets should continue working as before. Also, we
can use dune CLI like so:
```
infer/src$ dune printenv --profile opt # <- very useful for introspection
infer/src$ dune build check
infer/src$ dune build check --profile test
infer/src$ dune build infer.exe --profile dev
infer/src$ dune build infer.exe --profile opt
```
Also, with just 1 context something like `dune runtest` will run unit
tests only once instead of N times, where N is the number of contexts.
Now, there's one difference compared to the previous setup with
contexts:
- Previously, each context had its own build folder, and building infer
in opt context didn't invalidate any of the build artifacts in default
context. Therefore, alternating between `make` and `make opt` had low
overhead at the expense of having N copies of all build artifacts (1
for every context).
- Now, there's just 1 build folder and switching between profiles does
invalidate some artifacts (but not all) and rebuild takes a bit more
time.
So, if you're alternating like crazy between profiles your experience
may get worse (but not necessarily, more on that below). If you want
to trigger an opt build occasionally, you shouldn't notice much
difference.
For those who are concerned about slower build times when alternating
between different build profiles, there's a solution: [dune
cache](https://dune.readthedocs.io/en/stable/caching.html).
You can enable it by creating a file `~/.config/dune/config` with the
following contents:
```
(lang dune 2.0)
(cache enabled)
```
With cache enabled switching between different build profiles (but
also branches and commits) has ~0 overhead.
Dune cache works fine on Linux, but unfortunately there are [certain
problems with
MacOS](https://github.com/ocaml/dune/issues/3233) (hopefully, those
will be fixed soon and then there will be no downsides to using
profiles compared to contexts for our case).
Reviewed By: jvillard
Differential Revision: D20247864
fbshipit-source-id: 5f8afa0db
5 years ago
checkCopyright : src_build
toplevel_test : checkCopyright
e n d i f
.PHONY : test
test : crash_if_not_all_analyzers_enabled config_tests
i f e q ( , $( findstring s ,$ ( MAKEFLAGS ) ) )
$( QUIET) echo " $( TERM_INFO) ALL TESTS PASSED $( TERM_RESET) "
e n d i f
.PHONY : test -replace
test-replace : $( BUILD_SYSTEMS_TESTS :%=build_ %_replace ) $( DIRECT_TESTS :%=direct_ %_replace ) \
clang_plugin_test_replace
.PHONY : uninstall
uninstall :
$( REMOVE_DIR) $( DESTDIR) $( libdir) /infer/
$( REMOVE) $( DESTDIR) $( bindir) /infer
$( REMOVE) $( INFER_COMMANDS:%= $( DESTDIR) $( bindir) /%)
$( REMOVE) $( foreach manual,$( INFER_GROFF_MANUALS_GZIPPED) ,\
$( DESTDIR) $( mandir) /man1/$( notdir $( manual) ) )
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
$( MAKE) -C facebook uninstall
e n d i f
.PHONY : test_clean
test_clean : $( DIRECT_TESTS :%=direct_ %_clean ) $( BUILD_SYSTEMS_TESTS :%=build_ %_clean )
.PHONY : install
install : infer $( INFER_GROFF_MANUALS_GZIPPED )
# create directory structure
test -d '$(DESTDIR)$(bindir)' || \
$( MKDIR_P) '$(DESTDIR)$(bindir)'
test -d '$(DESTDIR)$(mandir)/man1' || \
$( MKDIR_P) '$(DESTDIR)$(mandir)/man1'
test -d '$(DESTDIR)$(libdir)/infer/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/'
i f e q ( $( BUILD_C_ANALYZERS ) , y e s )
test -d '$(DESTDIR)$(libdir)/infer/facebook-clang-plugins/libtooling/build/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/facebook-clang-plugins/libtooling/build/'
find facebook-clang-plugins/clang/install/. -type d -print0 | xargs -0 -n 1 \
$( SHELL) -x -c " test -d ' $( DESTDIR) $( libdir) '/infer/\$ $1 || \
$( MKDIR_P) '$(DESTDIR)$(libdir)' /infer/\$ $1 " --
test -d '$(DESTDIR)$(libdir)/infer/infer/lib/clang_wrappers/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/infer/lib/clang_wrappers/'
test -d '$(DESTDIR)$(libdir)/infer/infer/lib/linter_rules/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/infer/lib/linter_rules/'
test -d '$(DESTDIR)$(libdir)/infer/infer/etc/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/infer/etc'
e n d i f
i f e q ( $( BUILD_JAVA_ANALYZERS ) , y e s )
test -d '$(DESTDIR)$(libdir)/infer/infer/lib/java/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/infer/lib/java/'
e n d i f
test -d '$(DESTDIR)$(libdir)/infer/infer/annotations/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/infer/annotations/'
test -d '$(DESTDIR)$(libdir)/infer/infer/lib/wrappers/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/infer/lib/wrappers/'
test -d '$(DESTDIR)$(libdir)/infer/infer/bin/' || \
$( MKDIR_P) '$(DESTDIR)$(libdir)/infer/infer/bin/'
# copy files
$( INSTALL_DATA) -C 'infer/lib/models.sql' \
'$(DESTDIR)$(libdir)/infer/infer/lib/models.sql'
i f e q ( $( BUILD_C_ANALYZERS ) , y e s )
$( INSTALL_DATA) -C 'facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib' \
'$(DESTDIR)$(libdir)/infer/facebook-clang-plugins/libtooling/build/FacebookClangPlugin.dylib'
# do not use "install" for symbolic links as this will copy the destination file instead
find facebook-clang-plugins/clang/install/. -not -type d -not -type l -not -name '*.a' -print0 \
| xargs -0 -I \{ \} $( INSTALL_PROGRAM) -C \{ \} '$(DESTDIR)$(libdir)' /infer/\{ \}
# all the symlinks in clang are relative and safe to brutally copy over
find facebook-clang-plugins/clang/install/. -type l -not -name '*.a' -print0 \
| xargs -0 -I \{ \} $( COPY) -a \{ \} '$(DESTDIR)$(libdir)' /infer/\{ \}
find infer/lib/clang_wrappers/* -print0 | xargs -0 -I \{ \} \
$( INSTALL_PROGRAM) -C \{ \} '$(DESTDIR)$(libdir)' /infer/\{ \}
# only for files that point to infer
( cd '$(DESTDIR)$(libdir)/infer/infer/lib/wrappers/' && \
$( foreach cc,$( shell find '$(LIB_DIR)/wrappers' -type l) , \
[ $( cc) -ef '$(INFER_BIN)' ] && \
$( REMOVE) '$(notdir $(cc))' && \
$( LN_S) ../../bin/infer '$(notdir $(cc))' ; ) )
$( INSTALL_DATA) -C 'infer/lib/linter_rules/linters.al' \
'$(DESTDIR)$(libdir)/infer/infer/lib/linter_rules/linters.al'
$( INSTALL_DATA) -C 'infer/etc/clang_ast.dict' \
'$(DESTDIR)$(libdir)/infer/infer/etc/clang_ast.dict'
e n d i f
i f e q ( $( BUILD_JAVA_ANALYZERS ) , y e s )
$( INSTALL_DATA) -C 'infer/annotations/annotations.jar' \
'$(DESTDIR)$(libdir)/infer/infer/annotations/annotations.jar'
find infer/lib/java/*.jar -print0 | xargs -0 -I \{ \} \
$( INSTALL_DATA) -C \{ \} '$(DESTDIR)$(libdir)' /infer/\{ \}
$( INSTALL_PROGRAM) -C '$(LIB_DIR)' /wrappers/javac \
'$(DESTDIR)$(libdir)' /infer/infer/lib/wrappers/
e n d i f
$( INSTALL_PROGRAM) -C '$(INFER_BIN)' '$(DESTDIR)$(libdir)' /infer/infer/bin/
( cd '$(DESTDIR)$(bindir)/' && \
$( REMOVE) infer && \
$( LN_S) '$(libdir_relative_to_bindir)' /infer/infer/bin/infer infer)
[CLI] switch to infer-<command> (symlinks) executables
Summary:
Introduce `infer-<command>` for each command, except for internal commands
(only `infer-clang` for now) which are not exported. Install these executables
(which are just symlinks to `infer`) on `make install`. The main executable
looks at the name it was invoked with to figure out if it should behave as a
particular command.
Get rid of `InferClang`, `InferAnalyze`, and `InferPrint`. As a bonus, we now
only need to build one executable: `infer`, which should be a few seconds
faster (less link time).
`InferAnalyze` is now `infer-analyze` and `InferPrint` is `infer-print`. To run
`InferClang`, use a symlink named `clang`, `clang++`, etc. to `infer`. There
are such symlinks available in "infer/lib/wrappers/" already.
I also noticed that the scripts in xcodebuild_wrappers/ don't seem useful
anymore, so use wrappers/ instead, as for `make`.
Reviewed By: mbouaziz
Differential Revision: D5036495
fbshipit-source-id: 4a90030
8 years ago
for alias in $( INFER_COMMANDS) ; do \
( cd '$(DESTDIR)$(bindir)' / && \
$( REMOVE) " $$ alias " && \
$( LN_S) infer " $$ alias " ) ; done
[CLI] switch to infer-<command> (symlinks) executables
Summary:
Introduce `infer-<command>` for each command, except for internal commands
(only `infer-clang` for now) which are not exported. Install these executables
(which are just symlinks to `infer`) on `make install`. The main executable
looks at the name it was invoked with to figure out if it should behave as a
particular command.
Get rid of `InferClang`, `InferAnalyze`, and `InferPrint`. As a bonus, we now
only need to build one executable: `infer`, which should be a few seconds
faster (less link time).
`InferAnalyze` is now `infer-analyze` and `InferPrint` is `infer-print`. To run
`InferClang`, use a symlink named `clang`, `clang++`, etc. to `infer`. There
are such symlinks available in "infer/lib/wrappers/" already.
I also noticed that the scripts in xcodebuild_wrappers/ don't seem useful
anymore, so use wrappers/ instead, as for `make`.
Reviewed By: mbouaziz
Differential Revision: D5036495
fbshipit-source-id: 4a90030
8 years ago
for alias in $( INFER_COMMANDS) ; do \
( cd '$(DESTDIR)$(libdir)' /infer/infer/bin && \
$( REMOVE) " $$ alias " && \
$( LN_S) infer " $$ alias " ) ; done
$( foreach man,$( INFER_GROFF_MANUALS_GZIPPED) , \
$( INSTALL_DATA) -C $( man) '$(DESTDIR)$(mandir)/man1/$(notdir $(man))' ; )
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
i f d e f D E S T D I R
ifeq (,$(findstring : /, :$( DESTDIR ) ))
# DESTDIR is set and relative
$( MAKE) -C facebook install 'DESTDIR=../$(DESTDIR)'
e l s e
# DESTDIR is set and absolute
$( MAKE) -C facebook install
e n d i f
e l s e
# DESTDIR not set
$( MAKE) -C facebook install
e n d i f
e n d i f
# install dynamic libraries
# use this if you want to distribute infer binaries
install-with-libs : install
test -d '$(DESTDIR)$(libdir)' /infer/infer/libso || \
$( MKDIR_P) '$(DESTDIR)$(libdir)' /infer/infer/libso
i f n e q ( $( LDD ) , n o )
i f n e q ( $( PATCHELF ) , n o )
# this sort of assumes Linux
# figure out where libgmp, libmpfr, and libsqlite3 are using ldd
set -x; \
for lib in $$ ( $( LDD) $( INFER_BIN) \
| cut -d ' ' -f 3 \
| grep -e 'lib\(gmp\|mpfr\|sqlite\)' ) ; do \
$( INSTALL_PROGRAM) -C " $$ lib " '$(DESTDIR)$(libdir)' /infer/infer/libso/; \
done
# update rpath of executables
for sofile in '$(DESTDIR)$(libdir)' /infer/infer/libso/*.so*; do \
$( PATCHELF) --set-rpath '$$ORIGIN' --force-rpath " $$ sofile " ; \
done
$( PATCHELF) --set-rpath '$$ORIGIN/../libso' --force-rpath '$(DESTDIR)$(libdir)' /infer/infer/bin/infer
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
$( PATCHELF) --set-rpath '$$ORIGIN/../libso' --force-rpath '$(DESTDIR)$(libdir)' /infer/infer/bin/InferCreateTraceViewLinks
e n d i f
e l s e # ldd found but not patchelf
echo "ERROR: ldd (Linux?) found but not patchelf, please install patchelf" >& 2; exit 1
e n d i f
e l s e # ldd not found
i f n e q ( $( OTOOL ) , n o )
i f n e q ( $( INSTALL_NAME_TOOL ) , n o )
# this sort of assumes osx
# figure out where libgmp, libmpfr, and libsqlite3 are using otool
set -e; \
set -x; \
for lib in $$ ( $( OTOOL) -L $( INFER_BIN) \
| cut -d ' ' -f 1 | tr -d '\t' \
| grep -e 'lib\(gmp\|mpfr\|sqlite\)' ) ; do \
$( INSTALL_PROGRAM) -C " $$ lib " '$(DESTDIR)$(libdir)' /infer/infer/libso/; \
done
set -x; \
for sofile in '$(DESTDIR)$(libdir)' /infer/infer/libso/*.dylib; do \
$( INSTALL_NAME_TOOL) -add_rpath "@executable_path" " $$ sofile " ; \
scripts/set_libso_path.sh '$(DESTDIR)$(libdir)' /infer/infer/libso " $$ sofile " ; \
done
$( INSTALL_NAME_TOOL) -add_rpath '@executable_path/../libso' '$(DESTDIR)$(libdir)' /infer/infer/bin/infer
scripts/set_libso_path.sh '$(DESTDIR)$(libdir)' /infer/infer/libso '$(DESTDIR)$(libdir)' /infer/infer/bin/infer
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
$( INSTALL_NAME_TOOL) -add_rpath '@executable_path/../libso' '$(DESTDIR)$(libdir)' /infer/infer/bin/InferCreateTraceViewLinks
scripts/set_libso_path.sh '$(DESTDIR)$(libdir)' /infer/infer/libso '$(DESTDIR)$(libdir)' /infer/infer/bin/InferCreateTraceViewLinks
e n d i f
e l s e # install_name_tool not found
echo "ERROR: otool (OSX?) found but not install_name_tool, please install install_name_tool" >& 2; exit 1
e n d i f
e l s e # otool not found
echo "ERROR: need ldd + patchelf (Linux) or otool + install_name_tool (OSX) available" >& 2; exit 1
e n d i f
e n d i f # ldd
# Nuke objects built from OCaml. Useful when changing the OCaml compiler, for instance.
.PHONY : ocaml_clean
ocaml_clean :
i f e q ( $( BUILD_C_ANALYZERS ) , y e s )
$( QUIET) $( call silent_on_success,Cleaning facebook-clang-plugins OCaml build,\
$( MAKE) -C $( FCP_DIR) /clang-ocaml clean)
e n d i f
$( QUIET) $( call silent_on_success,Cleaning infer OCaml build,\
$( MAKE) -C $( SRC_DIR) clean)
$( QUIET) $( call silent_on_success,Cleaning ocamldot,\
$( MAKE) -C $( DEPENDENCIES_DIR) /ocamldot clean)
.PHONY : clean
clean : ocaml_clean test_clean
i f e q ( $( BUILD_C_ANALYZERS ) , y e s )
$( QUIET) $( call silent_on_success,Cleaning facebook-clang-plugins C++ build,\
$( MAKE) -C $( FCP_DIR) clean)
e n d i f
$( QUIET) $( call silent_on_success,Cleaning Java annotations,\
$( MAKE) -C $( ANNOTATIONS_DIR) clean)
$( QUIET) $( call silent_on_success,Cleaning infer models,\
$( MAKE) -C $( MODELS_DIR) clean)
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
$( QUIET) $( call silent_on_success,Cleaning facebook/,\
$( MAKE) -C facebook clean)
e n d i f
$( QUIET) $( call silent_on_success,Removing *.o and *.o.sh,\
find $( INFER_DIR) /tests \( -name '*.o' -o -name '*.o.sh' \) -delete)
$( QUIET) $( call silent_on_success,Removing build logs,\
$( REMOVE_DIR) _build_logs)
.PHONY : conf -clean
conf-clean : clean
$( REMOVE) .buckjavaversion
$( REMOVE) .buck-java11
$( REMOVE) Makefile.autoconf
$( REMOVE) acinclude.m4
$( REMOVE) aclocal.m4
$( REMOVE_DIR) autom4te.cache/
$( REMOVE) config.log
$( REMOVE) config.status
$( REMOVE) configure
$( REMOVE_DIR) $( MODELS_DIR) /c/out/
$( REMOVE_DIR) $( MODELS_DIR) /cpp/out/
$( REMOVE_DIR) $( MODELS_DIR) /java/infer-out/
$( REMOVE_DIR) $( MODELS_DIR) /objc/out/
# phony because it depends on opam's internal state
.PHONY : opam /infer .opam .locked
opam/infer.opam.locked : opam /infer .opam
# allow users to not force a run of opam update since it's very slow
i f e q ( $( NO_OPAM_UPDATE ) , )
$( QUIET) $( call silent_on_success,opam update,$( OPAM) update)
e n d i f
$( QUIET) $( call silent_on_success,generating opam/infer.opam.locked,\
$( OPAM) lock opam/infer.opam)
OPAM_DEV_DEPS = ocp-indent merlin utop webbrowser
i f n e q ( $( EMACS ) , n o )
OPAM_DEV_DEPS += tuareg
e n d i f
.PHONY : devsetup
devsetup : Makefile .autoconf
$( QUIET) [ $( OPAM) != "no" ] || ( echo 'No `opam` found, aborting setup.' >& 2; exit 1)
$( QUIET) $( call silent_on_success,installing $( OPAM_DEV_DEPS) ,\
OPAMSWITCH = $( OPAMSWITCH) ; $( OPAM) install --yes --no-checksum user-setup $( OPAM_DEV_DEPS) )
$( QUIET) echo '$(TERM_INFO)*** Running `opam user-setup`$(TERM_RESET)' >& 2
$( QUIET) OPAMSWITCH = $( OPAMSWITCH) ; OPAMYES = 1; $( OPAM) user-setup install
$( QUIET) if [ " $( PLATFORM) " = "Darwin" ] && [ x" $( GNU_SED) " = x"no" ] ; then \
echo '$(TERM_INFO)*** Installing GNU sed$(TERM_RESET)' >& 2; \
brew install gnu-sed; \
fi
$( QUIET) if [ " $( PLATFORM) " = "Darwin" ] && ! $$ ( parallel -h | grep -q GNU) ; then \
echo '$(TERM_INFO)*** Installing GNU parallel$(TERM_RESET)' >& 2; \
brew install parallel; \
fi
$( QUIET) if [ ! -d " $$ HOME " /.parallel ] ; then mkdir " $$ HOME " /.parallel; fi
$( QUIET) touch " $$ HOME " /.parallel/will-cite
# expand all occurrences of "~" in PATH and MANPATH
$( QUIET) infer_repo_is_in_path = $$ ( echo $$ { PATH//\~ /$$ HOME} | grep -q " $( ABSOLUTE_ROOT_DIR) " /infer/bin; echo $$ ?) ; \
infer_repo_is_in_manpath = $$ ( echo $$ { MANPATH//\~ /$$ HOME} | grep -q " $( ABSOLUTE_ROOT_DIR) " /infer/man; echo $$ ?) ; \
shell_config_file = "<could not auto-detect, please fill in yourself>" ; \
if [ $$ ( basename " $( ORIG_SHELL) " ) = "bash" ] ; then \
if [ " $( PLATFORM) " = "Linux" ] ; then \
shell_config_file = " $$ HOME " /.bashrc; \
else \
shell_config_file = " $$ HOME " /.bash_profile; \
fi ; \
elif [ $$ ( basename " $( ORIG_SHELL) " ) = "zsh" ] ; then \
shell_config_file = " $$ HOME " /.zshrc; \
fi ; \
if [ " $$ infer_repo_is_in_path " != "0" ] || [ " $$ infer_repo_is_in_manpath " != "0" ] ; then \
echo >& 2; \
echo '$(TERM_INFO)*** NOTE: `infer` is not in your PATH or MANPATH. If you are hacking on infer, you may$(TERM_RESET)' >& 2; \
echo '$(TERM_INFO)*** NOTE: want to make infer executables and manuals available in your terminal. Type$(TERM_RESET)' >& 2; \
echo '$(TERM_INFO)*** NOTE: the following commands to configure the current terminal and record the$(TERM_RESET)' >& 2; \
printf '$(TERM_INFO)*** NOTE: changes in your shell configuration file (%s):$(TERM_RESET)\n' " $$ shell_config_file " >& 2; \
echo >& 2; \
if [ " $$ infer_repo_is_in_path " != "0" ] ; then \
printf '$(TERM_INFO) export PATH="%s/infer/bin":$$PATH$(TERM_RESET)\n' " $( ABSOLUTE_ROOT_DIR) " >& 2; \
fi ; \
if [ " $$ infer_repo_is_in_manpath " != "0" ] ; then \
printf '$(TERM_INFO) export MANPATH="%s/infer/man":$$MANPATH$(TERM_RESET)\n' " $( ABSOLUTE_ROOT_DIR) " >& 2; \
fi ; \
if [ " $$ infer_repo_is_in_path " != "0" ] ; then \
printf " $( TERM_INFO) echo 'export PATH=\"%s/infer/bin\":\$ $PATH ' >> \" $$ shell_config_file\" $( TERM_RESET) \n " " $( ABSOLUTE_ROOT_DIR) " >& 2; \
fi ; \
if [ " $$ infer_repo_is_in_manpath " != "0" ] ; then \
printf " $( TERM_INFO) echo 'export MANPATH=\"%s/infer/man\":\$ $MANPATH ' >> \" $$ shell_config_file\" $( TERM_RESET) \n " " $( ABSOLUTE_ROOT_DIR) " >& 2; \
fi ; \
fi
$( QUIET) PATH = '$(ORIG_SHELL_PATH)' ; if [ " $$ (ocamlc -where 2>/dev/null) " != " $$ ( $( OCAMLC) -where) " ] ; then \
echo >& 2; \
echo '$(TERM_INFO)*** NOTE: The current shell is not set up for the right opam switch.$(TERM_RESET)' >& 2; \
echo '$(TERM_INFO)*** NOTE: Please run:$(TERM_RESET)' >& 2; \
echo >& 2; \
echo " $( TERM_INFO) eval \$ $( $( OPAM) env) $( TERM_RESET) " >& 2; \
fi
GHPAGES ?= no
.PHONY : doc
doc : src_build_common
$( QUIET) $( call silent_on_success,Generating infer documentation,\
$( MAKE_SOURCE) doc)
# do not call the browser if we are publishing the docs
i f n e q ( $( NO_BROWSE_DOC ) , y e s )
$( QUIET) $( call silent_on_success,Opening in browser,\
browse $( INFER_DIR) /_build/default/_doc/_html/index.html)
$( QUIET) echo "Tip: you can generate the doc for all the opam dependencies of infer like this:"
$( QUIET) echo
$( QUIET) echo " odig odoc # takes a while, run it only when the dependencies change"
$( QUIET) echo " odig doc"
e n d i f
.PHONY : doc -publish
doc-publish :
i f e q ( $( IS_FACEBOOK_TREE ) , y e s )
$( QUIET) $( call silent_on_success,Cleaning up FB-only files,\
$( MAKE) -C $( SRC_DIR) clean; \
$( MAKE) -C facebook clean)
e n d i f
$( QUIET) $( call silent_on_success,Building infer and manuals,\
$( MAKE) IS_FACEBOOK_TREE = no $( INFER_GROFF_MANUALS) )
$( QUIET) $( MKDIR_P) " $( WEBSITE_DIR) " /static/man/next " $( WEBSITE_DIR) " /static/odoc/next
$( QUIET) $( call silent_on_success,Copying man pages,\
$( REMOVE) " $( WEBSITE_DIR) " /static/man/*; \
for man in $( INFER_GROFF_MANUALS) ; do \
groff -Thtml " $$ man " \
| grep -v '^<!-- CreationDate: .*>$$' \
> " $( WEBSITE_DIR) " /static/man/next/$$ ( basename " $$ man " ) .html; \
done )
$( QUIET) $( call silent_on_success,Building OCaml modules documentation,\
$( MAKE) IS_FACEBOOK_TREE = no NO_BROWSE_DOC = yes doc)
$( QUIET) $( call silent_on_success,Copying OCaml modules documentation,\
rsync -a --delete $( BUILD_DIR) /default/_doc/_html/ " $( WEBSITE_DIR) " /static/odoc/next/)
$( QUIET) $( call silent_on_success,Building infer,\
$( MAKE) IS_FACEBOOK_TREE = no src_build)
$( QUIET) $( call silent_on_success,Calling 'infer help --write-website' ,\
$( INFER_BIN) help --write-website " $( WEBSITE_DIR) " )
.PHONY : new -website -version
# note: deletes already-created new version if already there to make it easier to update new
# versions while preparing a release
new-website-version : doc -publish
# this will version docs/ appropriately
cd $( WEBSITE_DIR) && \
rm -rf versioned_*/version-$( INFER_MAJOR) .$( INFER_MINOR) .$( INFER_PATCH) * ; \
sed -i -e '/"$(INFER_MAJOR).$(INFER_MINOR).$(INFER_PATCH)"/d' versions.json ; \
yarn run docusaurus docs:version $( INFER_MAJOR) .$( INFER_MINOR) .$( INFER_PATCH)
# copy static versioned resources
cd $( WEBSITE_DIR) /static/man && \
rm -fr $( INFER_MAJOR) .$( INFER_MINOR) .$( INFER_PATCH) / ; \
cp -a next/ $( INFER_MAJOR) .$( INFER_MINOR) .$( INFER_PATCH) /
cd $( WEBSITE_DIR) /static/odoc && \
rm -fr $( INFER_MAJOR) .$( INFER_MINOR) .$( INFER_PATCH) / ; \
cp -a next/ $( INFER_MAJOR) .$( INFER_MINOR) .$( INFER_PATCH) /
# adjust intra-doc paths in new doc version
cd $( WEBSITE_DIR) /versioned_docs/version-$( INFER_MAJOR) .$( INFER_MINOR) .$( INFER_PATCH) / && \
find . -type f -not -name versions.md \
-exec sed -i -e 's#/docs/next/#/docs/#g' \{ \} \+
# adjust paths to static versioned resources in new doc version
cd $( WEBSITE_DIR) /versioned_docs/version-$( INFER_MAJOR) .$( INFER_MINOR) .$( INFER_PATCH) / && \
find . -type f -not -name versions.md \
-exec sed -i -e 's#/next/#/$(INFER_MAJOR).$(INFER_MINOR).$(INFER_PATCH)/#g' \{ \} \+
# adjust intra-doc links in the previous "latest" version: /docs/foo -> /docs/<oldlatest>/foo
# select the first version that is not the one we are creating (in case this target is run
# multiple times)
old_latest = $$ ( jq 'map(select(. != "$(INFER_MAJOR).$(INFER_MINOR).$(INFER_PATCH)"))[0]' < $( WEBSITE_DIR) /versions.json | tr -d '"' ) ; \
cd $( WEBSITE_DIR) /versioned_docs/version-$$ { old_latest} / && \
find . -type f -not -name versions.md \
-exec sed -i -e " s#(/docs/\([^ $$ (echo $$ old_latest | cut -b 1)]\)#(/docs/ $$ {old_latest}/\1#g " \{ \} \+
# adjust versions.md, the page where users can navigate to other versions of the docs, unless
# it was already changed by an earlier run of this rule
cd $( WEBSITE_DIR) / && \
grep -q -F 'latest released version ($(INFER_MAJOR).$(INFER_MINOR).$(INFER_PATCH))' docs/versions.md || \
find docs versioned_docs -name versions.md \
-exec sed -i -e 's#^- \[latest released version (\([^)]*\))\](/docs/getting-started)$$#- [latest released version ($(INFER_MAJOR).$(INFER_MINOR).$(INFER_PATCH))](/docs/getting-started)\n- [previous version (\1)](/docs/\1/getting-started)#' \{ \} \+
# print list of targets
.PHONY : show -targets
show-targets :
$( QUIET) $( MAKE) -pqrR . | grep --only-matching -e '^[a-zA-Z0-9][^ ]*:' | cut -d ':' -f 1 | sort