backup of useful relinking script, in case GitHub disappears
This commit is contained in:
		
							
								
								
									
										93
									
								
								Builds/MacOSX/make_portable.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										93
									
								
								Builds/MacOSX/make_portable.sh
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,93 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Example input:
 | 
				
			||||||
 | 
					# ./make_portable.sh mycoolbinary
 | 
				
			||||||
 | 
					# where mycoolbinary is a mach-o object file
 | 
				
			||||||
 | 
					# (for example an executable binary or a .dylib)
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# this script rewrites your file's every environment-specific
 | 
				
			||||||
 | 
					# dynamic link (recursively!)
 | 
				
			||||||
 | 
					# such that they point to local .dylibs.
 | 
				
			||||||
 | 
					# these .dylibs are then copied to a folder lib, next to your binary
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# by "environment-specific" I mean any link to a .dylib under /usr/local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					set -o pipefail
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error() {
 | 
				
			||||||
 | 
					  local parent_lineno="$1"
 | 
				
			||||||
 | 
					  local message="$2"
 | 
				
			||||||
 | 
					  local code="${3:-1}"
 | 
				
			||||||
 | 
					  if [[ -n "$message" ]] ; then
 | 
				
			||||||
 | 
					    echo "Error on or near line ${parent_lineno}: ${message}; exiting with status ${code}"
 | 
				
			||||||
 | 
					  else
 | 
				
			||||||
 | 
					    echo "Error on or near line ${parent_lineno}; exiting with status ${code}"
 | 
				
			||||||
 | 
					  fi
 | 
				
			||||||
 | 
					  exit "${code}"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					trap 'error ${LINENO}' ERR
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BINARY="$1"
 | 
				
			||||||
 | 
					BINARYDIR=$(dirname "$BINARY")
 | 
				
			||||||
 | 
					LIBREL="lib"
 | 
				
			||||||
 | 
					LIB="$BINARYDIR/$LIBREL"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# make a lib folder
 | 
				
			||||||
 | 
					mkdir -p "$LIB"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# find every LC_LOAD_DYLIB command in the obj file
 | 
				
			||||||
 | 
					# filter to just loads under /usr/local
 | 
				
			||||||
 | 
					# print the absolute path of each such dylib
 | 
				
			||||||
 | 
					get_env_specific_direct_dependencies () {
 | 
				
			||||||
 | 
						# otool -L shows us every LC_LOAD_DYLIB plus LC_ID_DYLIB
 | 
				
			||||||
 | 
						# otool -D shows us just LC_ID_DYLIB
 | 
				
			||||||
 | 
						ALL_DYLIBS=$(otool -L "$1" | awk 'NR>1')
 | 
				
			||||||
 | 
						DYLIB_ID=$(otool -D "$1" | awk 'NR>1')
 | 
				
			||||||
 | 
						if [ -z "$DYLIB_ID" ]; then
 | 
				
			||||||
 | 
							DIRECT_DEPS="$ALL_DYLIBS"
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							DIRECT_DEPS=$(echo "$ALL_DYLIBS" | grep -v "$DYLIB_ID")
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
						echo "$DIRECT_DEPS" \
 | 
				
			||||||
 | 
						| awk '/\/usr\/local\//,/.dylib/ {print $1}'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# lookup LC_LOAD_DYLIB commands in an obj file,
 | 
				
			||||||
 | 
					# then follow those loads and ask the same of each
 | 
				
			||||||
 | 
					# of its dylibs, recursively
 | 
				
			||||||
 | 
					get_env_specific_dependencies_recursive () {
 | 
				
			||||||
 | 
						while read -r obj; do
 | 
				
			||||||
 | 
							[ -z "$obj" ] && continue
 | 
				
			||||||
 | 
							echo "$obj"
 | 
				
			||||||
 | 
							get_env_specific_dependencies_recursive "$obj"
 | 
				
			||||||
 | 
						done < <(get_env_specific_direct_dependencies "$1")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEP_PATHS=$(get_env_specific_dependencies_recursive "$BINARY")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mkdir -p "$LIB"
 | 
				
			||||||
 | 
					echo "$DEP_PATHS" \
 | 
				
			||||||
 | 
					| xargs -n 1 -I'{}' cp {} "$LIB/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					chmod +w "$LIB"/*.dylib
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					while read -r obj; do
 | 
				
			||||||
 | 
						[ -z "$obj" ] && continue
 | 
				
			||||||
 | 
						OBJ_LEAF_NAME=$(echo "$obj" | awk -F'/' '{print $NF}')
 | 
				
			||||||
 | 
						# rewrite the install name of this obj file. completely optional.
 | 
				
			||||||
 | 
						# provides good default for future people who link to it.
 | 
				
			||||||
 | 
						install_name_tool -id "@rpath/$OBJ_LEAF_NAME" "$obj"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# iterate over every LC_LOAD_DYLIB command in the objfile
 | 
				
			||||||
 | 
						while read -r load; do
 | 
				
			||||||
 | 
							[ -z "$load" ] && continue
 | 
				
			||||||
 | 
							LOAD_LEAF_NAME=$(echo "$load" | awk -F'/' '{print $NF}')
 | 
				
			||||||
 | 
							# rewrite a LC_LOAD_DYLIB command in this obj file
 | 
				
			||||||
 | 
							# to point relative to @rpath
 | 
				
			||||||
 | 
							install_name_tool -change "$load" "@rpath/$LOAD_LEAF_NAME" "$obj"
 | 
				
			||||||
 | 
						done < <(get_env_specific_direct_dependencies "$obj")
 | 
				
			||||||
 | 
					done < <(cat <(echo "$BINARY") <(echo "$DEP_PATHS" | awk -F'/' -v l="$LIB" -v OFS='/' '{print l,$NF}'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define in our binary what it should expand the
 | 
				
			||||||
 | 
					# runtime search path @rpath to
 | 
				
			||||||
 | 
					install_name_tool -add_rpath "@loader_path/$LIBREL" "$BINARY"
 | 
				
			||||||
		Reference in New Issue
	
	Block a user