1#!/bin/bash 2# 3# Copyright 2015 The Bazel Authors. All rights reserved. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17# OS X relpath is not really working. This is a wrapper script around gcc 18# to simulate relpath behavior. 19# 20# This wrapper uses install_name_tool to replace all paths in the binary 21# (bazel-out/.../path/to/original/library.so) by the paths relative to 22# the binary. It parses the command line to behave as rpath is supposed 23# to work. 24# 25# See https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac 26# on how to set those paths for Mach-O binaries. 27# 28set -eu 29 30INSTALL_NAME_TOOL="/usr/bin/install_name_tool" 31 32LIBS= 33LIB_DIRS= 34RPATHS= 35OUTPUT= 36 37function parse_option() { 38 local -r opt="$1" 39 if [[ "${OUTPUT}" = "1" ]]; then 40 OUTPUT=$opt 41 elif [[ "$opt" =~ ^-l(.*)$ ]]; then 42 LIBS="${BASH_REMATCH[1]} $LIBS" 43 elif [[ "$opt" =~ ^-L(.*)$ ]]; then 44 LIB_DIRS="${BASH_REMATCH[1]} $LIB_DIRS" 45 elif [[ "$opt" =~ ^-Wl,-rpath,\@loader_path/(.*)$ ]]; then 46 RPATHS="${BASH_REMATCH[1]} ${RPATHS}" 47 elif [[ "$opt" = "-o" ]]; then 48 # output is coming 49 OUTPUT=1 50 fi 51} 52 53# let parse the option list 54for i in "$@"; do 55 if [[ "$i" = @* ]]; then 56 while IFS= read -r opt 57 do 58 parse_option "$opt" 59 done < "${i:1}" || exit 1 60 else 61 parse_option "$i" 62 fi 63done 64 65# Set-up the environment 66%{env} 67 68# Call the C++ compiler 69%{cc} "$@" 70 71function get_library_path() { 72 for libdir in ${LIB_DIRS}; do 73 if [ -f ${libdir}/lib$1.so ]; then 74 echo "${libdir}/lib$1.so" 75 elif [ -f ${libdir}/lib$1.dylib ]; then 76 echo "${libdir}/lib$1.dylib" 77 fi 78 done 79} 80 81# A convenient method to return the actual path even for non symlinks 82# and multi-level symlinks. 83function get_realpath() { 84 local previous="$1" 85 local next=$(readlink "${previous}") 86 while [ -n "${next}" ]; do 87 previous="${next}" 88 next=$(readlink "${previous}") 89 done 90 echo "${previous}" 91} 92 93# Get the path of a lib inside a tool 94function get_otool_path() { 95 # the lib path is the path of the original lib relative to the workspace 96 get_realpath $1 | sed 's|^.*/bazel-out/|bazel-out/|' 97} 98 99# Do replacements in the output 100for rpath in ${RPATHS}; do 101 for lib in ${LIBS}; do 102 unset libname 103 if [ -f "$(dirname ${OUTPUT})/${rpath}/lib${lib}.so" ]; then 104 libname="lib${lib}.so" 105 elif [ -f "$(dirname ${OUTPUT})/${rpath}/lib${lib}.dylib" ]; then 106 libname="lib${lib}.dylib" 107 fi 108 # ${libname-} --> return $libname if defined, or undefined otherwise. This is to make 109 # this set -e friendly 110 if [[ -n "${libname-}" ]]; then 111 libpath=$(get_library_path ${lib}) 112 if [ -n "${libpath}" ]; then 113 ${INSTALL_NAME_TOOL} -change $(get_otool_path "${libpath}") \ 114 "@loader_path/${rpath}/${libname}" "${OUTPUT}" 115 fi 116 fi 117 done 118done 119 120