mirror of https://git.wownero.com/dsc/mxe.git
introducing copydlldeps.sh and copydlldeps.txt
This commit is contained in:
parent
b45184e1a2
commit
b1eb68704d
|
@ -0,0 +1,382 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
|
||||
# print version and license
|
||||
# is hereby part of the code and also displayed to the user
|
||||
version() {
|
||||
cat <<EOF >&2
|
||||
|
||||
Welcome to $( basename $0)!
|
||||
Authors: Lars Holger Engelhard - DL5RCW (2016)
|
||||
Tiancheng "Timothy" Gu (2014)
|
||||
|
||||
Version: 1.0
|
||||
|
||||
# This file is part of the MXE Project, sponsored by the named authors
|
||||
# it supports the shared build approach by providing an easy way to
|
||||
# check for library dependencies in a recursive manner
|
||||
|
||||
# Copyright (c) 2014 Tiancheng "Timothy" Gu
|
||||
# (c) 2016 Lars Holger Engelhard - DL5RCW
|
||||
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject
|
||||
# to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# default application objdump
|
||||
# you can specify your own objdump with --objdump or -o
|
||||
OBJDUMP=objdump
|
||||
|
||||
# create a temp directory
|
||||
tmp=`mktemp -d`
|
||||
|
||||
# print an help menu
|
||||
help() {
|
||||
cat <<EOF >&2
|
||||
|
||||
|
||||
Usage: $0 -c -d DEST -s SRC [-f FILE|-F DIR]
|
||||
or: $0 -p [-f FILE|-F DIR]
|
||||
or: $0 -c -p -d DEST -s SRC [-f FILE|-F DIR]
|
||||
or: $0 -p -d DEST -R SRC [-f FILE|-F DIR]
|
||||
or: $0 -p -d DEST -S "SRC_1 SRC_2 ... SRC_n" [-f FILE|-F DIR]
|
||||
or: $0 -c -d DEST -R SRC_1 -e SRC_2 [-f FILE|-F DIR]
|
||||
|
||||
|
||||
Copy executable FILE(s) and their DLL dependencies for SRC directory to a
|
||||
DEST directory, and/or print the recursive dependencies.
|
||||
|
||||
Operating modes:
|
||||
-c, --copy print and copy dependencies
|
||||
-p, --print print dependencies (no copy action)
|
||||
|
||||
Operating options:
|
||||
-d, --destdir Destination directory
|
||||
-f, --infile The input executable file or DLL.
|
||||
-F, --infiles, --indir The input directory of executable files and/or DLLs.
|
||||
-s, --srcdir [ multiCall ] The directory with DLLs that can be copied.
|
||||
-S, --srcdirs [ multiCall ] List of directories with DLLs that can be copied. Put "" around them, e.g. "/dir1 /root/dir2 /root/dir3"
|
||||
-R, --recursivesrcdir [ multiCall ] Target directory for recursive search of folders containing *dll files
|
||||
|
||||
Optional binary settings:
|
||||
-o, --objdump Specify the path or name of your objdump application
|
||||
-e, --enforce Enforce executable files and/or DLLs of a specific directory
|
||||
It will be entirely copied - flat, non recursive. assumes *.dll and *.exe in the top level directory
|
||||
e.g. <path_to_mxe>/mxe/usr/<compiler>/qt5/plugins/platforms/ - for qwindows.dll becomes
|
||||
DESTDIR/platforms/ containing qwindows.dll
|
||||
Other options:
|
||||
-h,-H, --help Display this message and exit
|
||||
-v,-V, --version Display version of this application
|
||||
-l,-L, --logLevel Display more output - default is 1
|
||||
|
||||
multiCall => you can specify this option multiple times!
|
||||
|
||||
Authors: Lars Holger Engelhard - DL5RCW
|
||||
Tiancheng "Timothy" Gu
|
||||
EOF
|
||||
}
|
||||
|
||||
# terminate the application
|
||||
# print an error message
|
||||
# and clean the tmp directory
|
||||
die() {
|
||||
echo $1 >&2
|
||||
rm -rf "$tmp"
|
||||
help
|
||||
exit 1
|
||||
}
|
||||
|
||||
# find all directories containing dll files
|
||||
# you can pass a list (array) of directories
|
||||
# and findAllSrcDirectories will hunt for dlls in each one recursively
|
||||
# it will return a sorted list and duplicates are removed
|
||||
findAllSrcDirectories(){
|
||||
ar_recursiveDirList=${!1}
|
||||
string=""
|
||||
for curPath in "${ar_recursiveDirList[@]}"; do
|
||||
for element in $(find $curPath -name "*.dll"); do
|
||||
#ar_list+="$(dirname $element) "
|
||||
string+="$(dirname $element) "
|
||||
done
|
||||
done
|
||||
string=$(echo "$string" | tr -s ' ' | tr ' ' '\n' | nl | sort -u -k2 | sort -n | cut -f2-)
|
||||
echo $string #returns the string
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
key="$1"
|
||||
shift
|
||||
|
||||
case $key in
|
||||
-f|--infile)
|
||||
infile="$1"
|
||||
shift
|
||||
;;
|
||||
-F|--indir|--infiles)
|
||||
indir="$1"
|
||||
shift
|
||||
;;
|
||||
-s|--srcdir)
|
||||
srcdir+=" $1"
|
||||
shift
|
||||
;;
|
||||
-d|--destdir)
|
||||
destdir="$1"
|
||||
shift
|
||||
;;
|
||||
-S|--srcdirs)
|
||||
srcdirs+=" $1"
|
||||
shift
|
||||
;;
|
||||
-R|--recursivesrcdir)
|
||||
recursivesrcdir+=" $1"
|
||||
shift
|
||||
;;
|
||||
-o|--objdump)
|
||||
OBJDUMP="$1"
|
||||
shift
|
||||
;;
|
||||
-e|--enforce)
|
||||
enforce+=" $1"
|
||||
shift
|
||||
;;
|
||||
-l|-L|--logLevel)
|
||||
logLevel="$1"
|
||||
shift
|
||||
;;
|
||||
-p|--print)
|
||||
opmode="print"
|
||||
;;
|
||||
-c|--copy)
|
||||
opmode="copy"
|
||||
;;
|
||||
-h|-H|--help)
|
||||
help
|
||||
exit 0
|
||||
;;
|
||||
-v|-V|--version)
|
||||
version
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "unknown option $key ignored" >&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if ! [ "$logLevel" ]; then
|
||||
logLevel=0
|
||||
fi
|
||||
|
||||
if ! [ "$opmode" ]; then
|
||||
opmode="copy" # used as default in productive
|
||||
#opmode="print" # used as default in development
|
||||
fi
|
||||
|
||||
if [ "$indir" ] && [ "$infile" ]; then
|
||||
die '--indir and --infile are mutually exclusive.'
|
||||
elif ! [ "$indir" ] && ! [ "$infile" ]; then
|
||||
die 'Neither --indir nor --infile is specified.'
|
||||
fi
|
||||
|
||||
if ! [ "$destdir" ]; then
|
||||
die '--destdir is not specified.'
|
||||
fi
|
||||
if ! ([ "$srcdir" ] || [ "$srcdirs" ] || [ "$recursivesrcdir" ]); then
|
||||
die 'either --srcdir or --srcdirs or --recursivesrcdir must be specified.'
|
||||
fi
|
||||
|
||||
if [ "$indir" ]; then
|
||||
filelist=`find $indir -iregex '.*\(dll\|exe\)' | tr '\n' ' '`
|
||||
else
|
||||
filelist="$infile"
|
||||
fi
|
||||
|
||||
if [ -n "$(ls -A $destdir 2>/dev/null)" ]; then
|
||||
echo 'Warning: --destdir already exists and contains files.' >&2
|
||||
else
|
||||
mkdir -p "$destdir"
|
||||
echo "info: created --destdir $destdir"
|
||||
fi
|
||||
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
echo "filelist=$filelist"
|
||||
echo "opmode=$opmode"
|
||||
fi
|
||||
|
||||
ar_srcDirList=()
|
||||
str_srcDirList=""
|
||||
if [ "$srcdir" ]; then
|
||||
str_srcDirList+=" $srcdir"
|
||||
fi
|
||||
if [ "$srcdirs" ]; then
|
||||
str_srcDirList+=" $srcdirs"
|
||||
fi
|
||||
if [ "$recursivesrcdir" ]; then
|
||||
result="$( findAllSrcDirectories recursivesrcdir )"
|
||||
str_srcDirList+=" $result"
|
||||
fi
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
echo "infiles: filelist=$filelist"
|
||||
echo " opmode: $opmode"
|
||||
fi
|
||||
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
echo "list for sources: str_srcDirList=${str_srcDirList}"
|
||||
echo "using OBJDUMP=$OBJDUMP in Version $( $OBJDUMP -V)"
|
||||
fi
|
||||
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
## during development, I like to interrupt here to check the above output and skip the rest
|
||||
echo "starting in 5 seconds" && sleep 5
|
||||
fi
|
||||
|
||||
# function to append dependencies (recursively)
|
||||
append_deps() {
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
echo "\$1=$1 + \$2=$2 "
|
||||
sleep 2
|
||||
fi
|
||||
local bn="`basename $1`"
|
||||
if [ -e "$tmp/$bn" ]; then
|
||||
return 0
|
||||
fi
|
||||
if [ $# -eq 2 ]; then
|
||||
path="$1"
|
||||
else
|
||||
path=""
|
||||
for curPath in $( echo "${str_srcDirList}" | tr -s ' ' | tr ' ' '\n' ); do
|
||||
counter=0
|
||||
result=$(find $curPath -name "$bn" | tail -n 1)
|
||||
if [ ! -z $result ];then
|
||||
path=$result
|
||||
counter=$(expr $counter + 1)
|
||||
fi
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
if [ $counter == 0 ]; then
|
||||
echo "could not find \$path for dll $bn, \$counter=$counter: searched $curPath"
|
||||
else
|
||||
echo "found path for dll $bn = $path, \$counter=$counter: searched $curPath"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
echo "path for dll $bn now is $path"
|
||||
sleep 2
|
||||
fi
|
||||
fi
|
||||
echo "Processing $1" >&2
|
||||
if ! [ -e "$path" ]; then
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
echo "path=$path| and we touch $tmp/$bn -> non existent in our src directories!"
|
||||
sleep 4
|
||||
fi
|
||||
touch "$tmp/$bn"
|
||||
return 0
|
||||
fi
|
||||
$OBJDUMP -p "$path" | grep 'DLL Name:' | cut -f3 -d' ' > "$tmp/$bn"
|
||||
echo "executing: $OBJDUMP -p "$path" | grep 'DLL Name:' | cut -f3 -d' ' > "$tmp/$bn""
|
||||
for dll in `cat "$tmp/$bn" | tr '\n' ' '`; do
|
||||
append_deps "$dll"
|
||||
done
|
||||
alldeps=$(printf "$alldeps\n%s" "$(cat $tmp/$bn)" | sort | uniq)
|
||||
}
|
||||
|
||||
process_enforced_deps(){
|
||||
enforcedDirectory=$1
|
||||
if [ ! -d $enforcedDirectory ]; then
|
||||
echo "warning! \$enforcedDirectory=$enforcedDirectory is not valid"
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
sleep 10
|
||||
fi
|
||||
fi
|
||||
# first we append the path to enforced dir to our list of source directories
|
||||
# if we would do this file recursively, we should loop to find those and append them all to the list
|
||||
str_srcDirList+=" $enforcedDirectory"
|
||||
# now we search for the dll and exe files to be included
|
||||
string=$( find $enforcedDirectory -maxdepth 1 -iregex '.*\(dll\|exe\)' | tr '\n' ' ' )
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
echo "enforcedDirectory=$enforcedDirectory"
|
||||
echo "we found dlls and exes:$string"
|
||||
sleep 4
|
||||
fi
|
||||
# we hard copy it to DEST
|
||||
cp -dpRxv "${enforcedDirectory}" "$destdir"
|
||||
}
|
||||
|
||||
# beginning of the main function
|
||||
# we start with the enforced dlls and exe
|
||||
if [ ! -z $enforce ]; then
|
||||
for curFile in $enforce; do
|
||||
echo "startig for file $curFile"
|
||||
append_deps "$curFile" rel
|
||||
process_enforced_deps "$curFile"
|
||||
done
|
||||
fi
|
||||
|
||||
# then we start with our indir or infile list
|
||||
for file in $filelist; do
|
||||
echo "starting for file $file"
|
||||
#sleep 4
|
||||
append_deps "$file" rel
|
||||
done
|
||||
|
||||
echo "I will now search for \$alldeps"
|
||||
for debugOut in $( echo $alldeps | tr -s ' ' | tr '\n' ' '); do
|
||||
echo "debugOut: $debugOut"
|
||||
done
|
||||
if [ "$logLevel" -eq 1 ]; then
|
||||
echo "waiting 10 seconds until I proceed - so you can read my debugOut"
|
||||
sleep 10
|
||||
|
||||
tmpStr=${str_srcDirList}
|
||||
echo "\$alldeps has ${#alldeps[@]} elements"
|
||||
echo "and \$str_srcDirList has ${#str_srcDirList} elements"
|
||||
echo "waiting another 10 seconds"
|
||||
#sleep 10
|
||||
fi
|
||||
|
||||
for dll in `echo $alldeps | tr '\n' ' '`; do
|
||||
counter=0
|
||||
for curFolder in $( echo "${str_srcDirList}" | tr -s ' ' | tr ' ' '\n'); do
|
||||
if [ "$logLevel" -gt 1 ]; then
|
||||
echo "search for dll $dll in curFolder $curFolder"
|
||||
sleep 1
|
||||
fi
|
||||
if [ -e "${curFolder}/${dll}" ]; then
|
||||
counter=$(expr $counter + 1)
|
||||
if [ $opmode == "copy" ]; then
|
||||
cp -dpRxv "${curFolder}/${dll}" "$destdir"
|
||||
elif [ $opmode == "print" ]; then
|
||||
echo "found $dll in: ${curFolder}/${dll}"
|
||||
else
|
||||
echo "unknown opmode=$opmode"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
if [ $counter == 0 ]; then
|
||||
echo "Warning: \"$dll\" not found. \$counter=$counter." >&2
|
||||
else
|
||||
echo "Found dll $dll in the list. \$counter=$counter" >&2
|
||||
fi
|
||||
done
|
||||
|
||||
rm -rf "$tmp"
|
|
@ -0,0 +1,58 @@
|
|||
== README of copydlldeps.sh ==
|
||||
This document was created 2016-02-05. It belongs to copydlldeps.sh
|
||||
|
||||
I call it on the command line like:
|
||||
<source lang="bash">
|
||||
/share/mxe/tools/copydlldeps.sh --infile /home/mxeuser/test/i686-w64-mingw32.shared/Application.exe \
|
||||
--destdir /home/mxeuser/testdlls/ \
|
||||
--recursivesrcdir /home/mxeuser/mxe/usr/i686-w64-mingw32.shared/ \
|
||||
--srcdir /home/mxeuser/test/ \
|
||||
--copy \
|
||||
--enforce /home/mxeuser/mxe/usr/i686-w64-mingw32.shared/qt5/plugins/platforms/ \
|
||||
--objdump /home/mxeuser/mxe/usr/bin/i686-w64-mingw32.shared-objdump
|
||||
</source>
|
||||
It got embedded in a build script like:
|
||||
|
||||
<source lang="bash">
|
||||
MXEPATH=/path/to/mxe
|
||||
compiler=i686-w64-mingw32.shared
|
||||
orgDir=/path/to/my/nsis/dll #nsis is then copying all dlls in there to the place where the exe is located
|
||||
|
||||
if [ ! $( echo $compiler | grep -q "shared" ) ]; then
|
||||
echo "\$compiler=$compiler and contains the word 'shared'" | tee -a $CURLOG
|
||||
|
||||
echo "#===============================================# " | tee -a $CURLOG
|
||||
echo "| Starting new MXE copydlldeps.sh by LHE DL5RCW | " | tee -a $CURLOG
|
||||
echo "#===============================================# " | tee -a $CURLOG
|
||||
echo "currently working in $( pwd ) " | tee -a $CURLOG
|
||||
executable=$( find . -name "*.exe" | tail -n 1 )
|
||||
if [ -e $MXEPATH/usr/bin/$compiler-objdump ]; then
|
||||
echo "now populating dir=${orgDir}/nsis/sharedLibs with dll dependencies of executable=$executable" | tee -a $CURLOG
|
||||
$MXEPATH/tools/copydlldeps.sh --infile $executable \
|
||||
--destdir ${orgDir}/nsis/sharedLibs \
|
||||
--recursivesrcdir $MXEPATH/usr/$compiler/ \
|
||||
--enforce $MXEPATH/usr/$compiler/qt5/plugins/platforms/ \
|
||||
--copy \
|
||||
--objdump $MXEPATH/usr/bin/$compiler-objdump | tee -a $CURLOG
|
||||
else
|
||||
echo "now populating dir=${orgDir}/nsis/sharedLibs with dll dependencies of executable=$executable" | tee -a $CURLOG
|
||||
$MXEPATH/tools/copydlldeps.sh --infile $executable \
|
||||
--destdir ${orgDir}/nsis/sharedLibs \
|
||||
--recursivesrcdir $MXEPATH/usr/$compiler/ \
|
||||
--enforce $MXEPATH/usr/$compiler/qt5/plugins/platforms/ \
|
||||
--copy | tee -a $CURLOG
|
||||
fi
|
||||
</source>
|
||||
|
||||
|
||||
== Additional hints ==
|
||||
=== objdump ===
|
||||
I checked if there is a mxe objdump. If not, I took the native one on my server. I actually do not know the difference but decided to include it in the script in case it is important to someone
|
||||
=== enforce ===
|
||||
My application is using Qt5 and objdump did not return the needed qwindows.dll - so I enforce the platform folder. You may add multiple --enforce directories using --enforce /path/folder1 --enforce /path/folder2 --enforce /path/folder3
|
||||
They are NOT recursively copied, only flat. See:
|
||||
string=$( find $enforcedDirectory -maxdepth 1 -iregex '.*\(dll\|exe\)' | tr '\n' ' ' )
|
||||
|
||||
If you would remove the -maxdepth 1, it would become recoursive. Does anyone need that?
|
||||
|
||||
|
Loading…
Reference in New Issue