From ba5ad8212881f336845492908313dd22cfefc4b5 Mon Sep 17 00:00:00 2001 From: Jules Villard Date: Thu, 14 Feb 2019 02:32:36 -0800 Subject: [PATCH] [make] support relocating libs at install time Summary: Provide hooks into the autoconf configure script to define where libgmp and libmpfr may be found. Use these and opam to copy the more exotic library objects into the installation of infer on a new `make install-with-libs` target so that the binaries can be distributed usefully, i.e., without users having to install gmp, mpfr, and more importantly apron and elina (which need ocaml + opam + ..., which would defeat the point of having binaries). Reviewed By: skcho Differential Revision: D14065317 fbshipit-source-id: 9a2ac7200 --- Makefile | 50 ++++++++++++++++++++++++++++++++ Makefile.autoconf.in | 4 +++ configure.ac | 41 +++++++++++++------------- scripts/create_binary_release.sh | 2 +- scripts/set_libso_path.sh | 30 +++++++++++++++++++ 5 files changed, 105 insertions(+), 22 deletions(-) create mode 100755 scripts/set_libso_path.sh diff --git a/Makefile b/Makefile index eb41e0aba..821b23345 100644 --- a/Makefile +++ b/Makefile @@ -650,6 +650,56 @@ else endif endif +# 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 +ifneq ($(OPAM),no) + $(INSTALL_PROGRAM) -C $(GMP_LIB_PATH) '$(DESTDIR)$(libdir)'/infer/infer/libso/ + $(INSTALL_PROGRAM) -C $(MPFR_LIB_PATH) '$(DESTDIR)$(libdir)'/infer/infer/libso/ + set -x; \ + OPAM_SHARE=$$($(OPAM) config var share); \ + APRON_LIB_PATHS="$$OPAM_SHARE/apron/lib/libapron.so $$OPAM_SHARE/apron/lib/liboctMPQ.so"; \ + ELINA_LIB_PATHS="$$OPAM_SHARE/elina/lib/libelinalinearize.so $$OPAM_SHARE/elina/lib/liboptpoly.so $$OPAM_SHARE/elina/lib/libpartitions.so"; \ + $(INSTALL_PROGRAM) -C $$APRON_LIB_PATHS '$(DESTDIR)$(libdir)'/infer/infer/libso/; \ + $(INSTALL_PROGRAM) -C $$ELINA_LIB_PATHS '$(DESTDIR)$(libdir)'/infer/infer/libso/ +# update rpath of executables +ifneq ($(PATCHELF),no) +# this sort of assumes Linux + for sofile in '$(DESTDIR)$(libdir)'/infer/infer/libso/*.so; do \ + $(PATCHELF) --set-rpath '$$ORIGIN' "$$sofile"; \ + done + $(PATCHELF) --set-rpath '$$ORIGIN/../libso' '$(DESTDIR)$(libdir)'/infer/infer/bin/infer +ifeq ($(IS_FACEBOOK_TREE),yes) + $(PATCHELF) --set-rpath '$$ORIGIN/../libso' '$(DESTDIR)$(libdir)'/infer/infer/bin/InferCreateTraceViewLinks +endif +else # patchelf not found +ifneq ($(OTOOL),no) +ifneq ($(INSTALL_NAME_TOOL),no) +# this sort of assumes osx + set -x; \ + for sofile in '$(DESTDIR)$(libdir)'/infer/infer/libso/*.{so,dylib}; do \ + $(INSTALL_NAME_TOOL) -add_rpath "@executable_path" "$$sofile" 2> /dev/null || true; \ + 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 2> /dev/null || true + scripts/set_libso_path.sh '$(DESTDIR)$(libdir)'/infer/infer/libso '$(DESTDIR)$(libdir)'/infer/infer/bin/infer +ifeq ($(IS_FACEBOOK_TREE),yes) + $(INSTALL_NAME_TOOL) -add_rpath '@executable_path/../libso' '$(DESTDIR)$(libdir)'/infer/infer/bin/InferCreateTraceViewLinks 2> /dev/null || true + scripts/set_libso_path.sh '$(DESTDIR)$(libdir)'/infer/infer/libso '$(DESTDIR)$(libdir)'/infer/infer/bin/InferCreateTraceViewLinks +endif +else # install_name_tool not found + echo "ERROR: need patchelf (Linux) or otool + install_name_tool (OSX) available" >&2; exit 1 +endif +else # otool not found + echo "ERROR: need patchelf (Linux) or otool + install_name_tool (OSX) available" >&2; exit 1 +endif +endif # patchelf +else # opam not found + echo "ERROR: non-opam installations not supported" >&2; exit 1 +endif + # Nuke objects built from OCaml. Useful when changing the OCaml compiler, for instance. .PHONY: ocaml_clean ocaml_clean: diff --git a/Makefile.autoconf.in b/Makefile.autoconf.in index 3b5823d51..e21c9af3d 100644 --- a/Makefile.autoconf.in +++ b/Makefile.autoconf.in @@ -27,6 +27,7 @@ EMACS = @EMACS@ ENABLE_OCAMLOPT_CUSTOM_CC = @ENABLE_OCAMLOPT_CUSTOM_CC@ ENABLE_OCAML_BINANNOT = @ENABLE_OCAML_BINANNOT@ exec_prefix = @exec_prefix@ +GMP_LIB_PATH = @GMP_LIB_PATH@ GNU_SED = @GNU_SED@ INFER_MAJOR = @INFER_MAJOR@ INFER_MAN_LAST_MODIFIED = @INFER_MAN_LAST_MODIFIED@ @@ -34,6 +35,7 @@ INFER_MINOR = @INFER_MINOR@ INFER_PATCH = @INFER_PATCH@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ +INSTALL_NAME_TOOL = @INSTALL_NAME_TOOL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ IS_FACEBOOK_TREE = @IS_FACEBOOK_TREE@ IS_RELEASE_TREE = @IS_RELEASE_TREE@ @@ -51,6 +53,7 @@ MKDIR_P_CMD = case "@MKDIR_P@" in \ *) printf "@MKDIR_P@\n";; \ esac MKDIR_P = $(shell $(MKDIR_P_CMD)) +MPFR_LIB_PATH = @MPFR_LIB_PATH@ MVN = @MVN@ NCPU = @NCPU@ NDKBUILD = @NDKBUILD@ @@ -62,6 +65,7 @@ OCAMLOPT = @OCAMLOPT@ OPAM = @OPAM@ OPAMROOT = @OPAMROOT@ OPAMSWITCH = @OPAMSWITCH@ +OTOOL = @OTOOL@ PATCHELF = @PATCHELF@ PATH = @PATH@ prefix = @prefix@ diff --git a/configure.ac b/configure.ac index 6c88f821e..2073aa6bd 100644 --- a/configure.ac +++ b/configure.ac @@ -116,7 +116,6 @@ AS_IF([test "x$enable_c_analyzers" = "xyes"], [ ]) # end if($enable_c_analyzers) - AC_CHECK_TOOL([PYTHON27], [python2.7], [no]) AC_ASSERT_PROG([python2.7], [$PYTHON27]) @@ -184,6 +183,7 @@ Alternatively, you can checkout a binary release of infer: fi # end if($enable_c_analyzers) + # OCaml dependencies AC_PROG_OCAML AC_ASSERT_PROG([ocamlc], [$OCAMLC]) @@ -347,26 +347,25 @@ AC_ARG_VAR([SDKROOT], [path to the OSX platform SDK used by clang]) AC_SUBST([SDKROOT]) AC_CHECK_TOOL([PATCHELF], [patchelf], [no]) - -# warn about broken pkg-config version for brew users -if test "$BREW" != "no"; then - if "$BREW" info pkg-config > /dev/null && \ - test x"$(which pkg-config)" = x"/usr/local/bin/pkg-config"; then - AC_MSG_NOTICE([pkg-config seems to have been installed from Homebrew]) - AC_MSG_CHECKING([for bad version of pkg-config brew package]) - if readlink $(which pkg-config) | grep -q -e '/0.29.1_1/'; then - AC_MSG_RESULT([found 0.29.1_1]) - AC_MSG_WARN([]) - AC_MSG_WARN([This version of pkg-config is known to cause issues with compiling infer.]) - AC_MSG_WARN([Consider running the following command to get a working version:]) - AC_MSG_WARN([]) - AC_MSG_WARN([ brew remove pkg-config && brew update && brew install pkg-config]) - AC_MSG_WARN([]) - else - AC_MSG_RESULT([no bad version found]) - fi - fi -fi +AC_SUBST([PATCHELF]) +AC_CHECK_TOOL([INSTALL_NAME_TOOL], [install_name_tool], [no]) +AC_SUBST([INSTALL_NAME_TOOL]) +AC_CHECK_TOOL([OTOOL], [otool], [no]) +AC_SUBST([OTOOL]) + +# look for the location of various libraries, needed to create relocatable installations of infer + +AC_ARG_VAR([MPFR_LIB_PATH], [path to libmpfr.so or libmpfr.dylib]) +AC_MSG_CHECKING([where to find libmpfr]) +AS_IF([test "x$MPFR_LIB_PATH" = "x"], [MPFR_LIB_PATH=no]) +AC_MSG_RESULT([$MPFR_LIB_PATH]) +AC_SUBST([MPFR_LIB_PATH]) + +AC_MSG_CHECKING([where to find libgmp]) +AC_ARG_VAR([GMP_LIB_PATH], [path to libgmp.so or libgmp.dylib]) +AS_IF([test "x$GMP_LIB_PATH" = "x"], [GMP_LIB_PATH=no]) +AC_MSG_RESULT([$GMP_LIB_PATH]) +AC_SUBST([GMP_LIB_PATH]) AC_CHECK_INFER_MAN_LAST_MODIFIED() diff --git a/scripts/create_binary_release.sh b/scripts/create_binary_release.sh index 423e882c0..b68d1c4d4 100755 --- a/scripts/create_binary_release.sh +++ b/scripts/create_binary_release.sh @@ -43,7 +43,7 @@ eval $(opam env) touch .release ./autogen.sh ./configure --prefix="/$RELEASE_NAME" -make -j "$JOBS" install BUILD_MODE=opt DESTDIR="$ROOT_DIR" libdir_relative_to_bindir=../lib +make -j "$JOBS" install-with-libs BUILD_MODE=opt DESTDIR="$ROOT_DIR" libdir_relative_to_bindir=../lib popd if [ "$DRYRUN" = "no" ]; then diff --git a/scripts/set_libso_path.sh b/scripts/set_libso_path.sh new file mode 100755 index 000000000..e39f28496 --- /dev/null +++ b/scripts/set_libso_path.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Copyright (c) 2018-present, Facebook, Inc. +# +# This source code is licensed under the MIT license found in the +# LICENSE file in the root directory of this source tree. + +# Usage: set_libso_path.sh [LIBSO_DIR] [TARGET] +# +# This changes MacOSX's executable [TARGET] to use shared libraries in +# [LIBSO_DIR] when rpath has been set to [LIBSO_DIR]. + +set -e +set -o pipefail +set -u + +LIBSO_DIR=$1 +TARGET=$2 + +TMP=$( mktemp ) +trap "rm $TMP" EXIT + +otool -L "$TARGET" | tail -n +2 > "$TMP" +while IFS='' read -r line || [[ -n "$line" ]]; do + LIB_PATH=$( echo $line | awk '{print $1}' ) + LIB_FILE=$( basename "${LIB_PATH}" ) + if [ -f "${LIBSO_DIR}/${LIB_FILE}" ]; then + install_name_tool -change "${LIB_PATH}" "@rpath/${LIB_FILE}" "$TARGET" + fi +done < "$TMP"