diff options
Diffstat (limited to 'build/build-infer')
-rw-r--r-- | build/build-infer/README | 36 | ||||
-rwxr-xr-x | build/build-infer/build-infer.py | 152 | ||||
-rw-r--r-- | build/build-infer/infer-linux64.json | 5 |
3 files changed, 193 insertions, 0 deletions
diff --git a/build/build-infer/README b/build/build-infer/README new file mode 100644 index 0000000000..af11d9af3c --- /dev/null +++ b/build/build-infer/README @@ -0,0 +1,36 @@ +build-infer.py +============== + +A script to build infer from source. + +``` +usage: build-infer.py [-h] -c CONFIG [--clean] + +optional arguments: + -h, --help show this help message and exit + -c CONFIG, --config CONFIG + infer configuration file + --clean Clean the build directory +``` + +Pre-requisites +-------------- +* Working build toolchain. +* ocam +* git +* autoconf +* libsqlite-dev +* CMake +* Ninja +* Python 2.7 + +Please use the latest available CMake for your platform to avoid surprises. + +Config file format +------------------ + +build-clang.py accepts a JSON config format with the following fields: + +* infer_revision: The infer revision to build. +* infer_repo: git repository for infer. +* patches: Optional list of patches to apply.
\ No newline at end of file diff --git a/build/build-infer/build-infer.py b/build/build-infer/build-infer.py new file mode 100755 index 0000000000..e9a4804ce0 --- /dev/null +++ b/build/build-infer/build-infer.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import subprocess +import json +import argparse +import sys +import shutil +from functools import reduce + + +def check_run(args, path): + print(" ".join(args) + " in " + path, file=sys.stderr) + subprocess.run(args, cwd=path, check=True) + + +def run_in(path, args, extra_env=None): + """ + Runs the given commands in the directory specified by <path>. + """ + env = dict(os.environ) + env.update(extra_env or {}) + check_run(args, path) + subprocess.run(args, cwd=path) + + +def build_tar_package(tar, name, base, directories): + name = os.path.realpath(name) + run_in( + base, + [tar, "-c", "-%s" % ("J" if ".xz" in name else "j"), "-f", name] + directories, + ) + + +def is_git_repo(dir): + """Check whether the given directory is a git repository.""" + from subprocess import CalledProcessError + + try: + check_run(["git", "rev-parse"], dir) + return True + except CalledProcessError: + return False + + +def git_clone(main_dir, url, clone_dir, commit): + """ + Clones the repository from <url> into <clone_dir>, and brings the + repository to the state of <commit>. + """ + run_in(main_dir, ["git", "clone", url, clone_dir]) + run_in(clone_dir, ["git", "checkout", commit]) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument( + "-c", + "--config", + required=True, + type=argparse.FileType("r"), + help="Infer configuration file", + ) + parser.add_argument( + "-b", "--base-dir", help="Base directory for code and build artifacts" + ) + parser.add_argument( + "--clean", action="store_true", help="Clean the build directory" + ) + parser.add_argument( + "--skip-tar", action="store_true", help="Skip tar packaging stage" + ) + + args = parser.parse_args() + + # The directories end up in the debug info, so the easy way of getting + # a reproducible build is to run it in a know absolute directory. + # We use a directory that is registered as a volume in the Docker image. + if args.base_dir: + base_dir = args.base_dir + else: + base_dir = reduce( + os.path.join, [os.sep + "builds", "worker", "workspace", "moz-toolchain"] + ) + infer_dir = os.path.join(base_dir, "infer") + source_dir = os.path.join(infer_dir, "src") + build_dir = os.path.join(infer_dir, "build") + + if args.clean: + shutil.rmtree(build_dir) + os.sys.exit(0) + + config = json.load(args.config) + infer_revision = config["infer_revision"] + infer_repo = config["infer_repo"] + + for folder in [infer_dir, source_dir, build_dir]: + os.makedirs(folder, exist_ok=True) + + # clone infer + if not is_git_repo(source_dir): + # git doesn't like cloning into a non-empty folder. If src is not a git + # repo then just remove it in order to reclone + shutil.rmtree(source_dir) + git_clone(infer_dir, infer_repo, source_dir, infer_revision) + # apply a few patches + dir_path = os.path.dirname(os.path.realpath(__file__)) + # clean the git directory by reseting all changes + git_commands = [["clean", "-f"], ["reset", "--hard"]] + for command in git_commands: + run_in(source_dir, ["git"] + command) + for p in config.get("patches", []): + run_in(source_dir, ["git", "apply", os.path.join(dir_path, p)]) + # configure opam + run_in(source_dir, ["opam", "init", "--no-setup", "--disable-sandboxing"]) + # build infer + run_in(source_dir, ["./build-infer.sh", "java"], extra_env={"NO_CMAKE_STRIP": "1"}) + + package_name = "infer" + infer_package = os.path.join(os.getcwd(), package_name) + # We need to create a package with all of the depended libraries injected in it + run_in( + source_dir, + [ + "make", + "install-with-libs", + "BUILD_MODE=opt", + "PATCHELF=patchelf", + "DESTDIR={}".format(infer_package), + "libdir_relative_to_bindir=../lib", + ], + ) + + infer_package_with_pref = os.path.join(infer_package, "usr") + if not args.skip_tar: + os.rename( + os.path.join(infer_package_with_pref, "local"), + os.path.join(infer_package_with_pref, "infer"), + ) + build_tar_package( + "tar", + "%s.tar.xz" % (package_name), + infer_package_with_pref, + [ + os.path.join("infer", "bin"), + os.path.join("infer", "lib"), + os.path.join("infer", "share"), + ], + ) diff --git a/build/build-infer/infer-linux64.json b/build/build-infer/infer-linux64.json new file mode 100644 index 0000000000..b6331b1d7e --- /dev/null +++ b/build/build-infer/infer-linux64.json @@ -0,0 +1,5 @@ +{ + "infer_repo": "https://github.com/facebook/infer", + "infer_revision": "99464c01da5809e7159ed1a75ef10f60d34506a4", + "patches": [] +} |