From 53cf78e63f1ccf9e136d278d2f7a67d64488e745 Mon Sep 17 00:00:00 2001
From: Philippe Renon <philippe_renon@yahoo.fr>
Date: Sat, 24 Jun 2017 16:10:16 +0200
Subject: [PATCH 1/5] LP-535 msys2: add python utility to find and copy library
 dependencies

also add a new qmake addCopyDependenciesTarget function to invoke new utility
---
 ground/gcs/gcs.pri        | 21 +++++++++
 make/copy_dependencies.py | 92 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 113 insertions(+)
 create mode 100644 make/copy_dependencies.py

diff --git a/ground/gcs/gcs.pri b/ground/gcs/gcs.pri
index cb25cd54f..094a09deb 100644
--- a/ground/gcs/gcs.pri
+++ b/ground/gcs/gcs.pri
@@ -46,6 +46,27 @@ defineTest(addCopyFileTarget) {
     export($${file}.target)
     export($${file}.depends)
     export($${file}.commands)
+
+defineTest(addCopyDependenciesTarget) {
+    file = $$1
+    src  = $$2/$$1
+    dest = $$3
+
+    target_file = $${OUT_PWD}/deps/$${file}.deps
+
+    target = $${file}_deps
+    $${target}.target    = $$target_file
+    $${target}.depends   = $$src
+
+    $${target}.commands  = -@$(MKDIR) \"$$dirname(target_file)\" $$addNewline()
+    $${target}.commands  += $$(PYTHON) $$(ROOT_DIR)/make/copy_dependencies.py --dest \"$$dest\" --files \"$$src\" --excludes OPENGL32.DLL > \"$$target_file\"
+
+    QMAKE_EXTRA_TARGETS += $$target
+    POST_TARGETDEPS += $$eval($${target}.target)
+
+    export($${target}.target)
+    export($${target}.depends)
+    export($${target}.commands)
     export(QMAKE_EXTRA_TARGETS)
     export(POST_TARGETDEPS)
 
diff --git a/make/copy_dependencies.py b/make/copy_dependencies.py
new file mode 100644
index 000000000..413c16ab0
--- /dev/null
+++ b/make/copy_dependencies.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python2
+
+ ###############################################################################
+ #
+ # The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
+ # Script to find and copy dependencies (msys2 only).
+ # ./copy_dependencies.py -h for usage.
+ #
+ ###############################################################################
+
+import argparse
+import glob
+import os
+import re
+import shutil
+import subprocess
+import sys
+
+def cygpath(file):
+	return subprocess.check_output(["cygpath", "-m", file]).strip()
+
+# ldd does not work well on Windows 10 and is not supported on mingw32
+# ntldd seems to be more reliable but is not recursive (so recursion needs to be done here)
+def ldd(file):
+	ldd_output = subprocess.check_output(["ntldd", file])
+	# sanitize output
+	ldd_output = ldd_output.strip()
+	ldd_output = ldd_output.replace('\\', '/')
+	# split output into lines
+	ldd_lines = ldd_output.split('\n')
+	# parse lines that match this format : <file name> ==> <file path> (<memory address>)
+	file_pattern = ".*/mingw../bin/.*"
+	pattern = "(.*) => (" + file_pattern + ") \((.*)\)";
+	regex = re.compile(pattern)
+	dependencies = {m.group(2).strip() for m in [regex.match(line) for line in ldd_lines] if m}
+	return dependencies
+
+def find_dependencies(file, visited):
+	print "Analyzing " + file
+	visited.add(file)
+	dependencies = ldd(file)
+	# recurse
+	for f in dependencies.copy():
+		if f in visited:
+			continue
+		if args.excludes and os.path.basename(f) in args.excludes:
+			print "Ignoring " + f
+			dependencies.remove(f)
+			continue
+		dependencies = dependencies | find_dependencies(f, visited)
+	return dependencies
+
+parser = argparse.ArgumentParser(description='Find and copy dependencies to a destination directory.')
+parser.add_argument('-n', '--no-copy', action='store_true', help='don\'t copy dependencies to destination dir')
+parser.add_argument('-v', '--verbose', action='store_true', help='enable verbose mode')
+parser.add_argument('-d', '--dest', type=str, default='.', help='destination directory (defaults to current directory)')
+parser.add_argument('-s', '--source', type=str, default='.', help='source directory (defaults to current directory)')
+parser.add_argument('-f', '--files', metavar='FILE', nargs='+', required=True, help='a file')
+parser.add_argument('-e', '--excludes', metavar='FILE', nargs='+', help='a file')
+
+args = parser.parse_args()
+
+# check that args.dest exists and is a directory
+if not os.path.isdir(args.dest):
+	print "Error: destination " + str(args.dest) + " is not a directory."
+	exit(1)
+
+# find dependencies
+dependencies = set()
+visited = set()
+for file in args.files:
+	file = os.path.join(args.source, file)
+	files = glob.glob(file)
+	for f in files:
+		dependencies = dependencies | find_dependencies(f, visited)
+print "Found " + str(len(dependencies)) + " dependencies."
+
+# no copy, exit now
+if args.no_copy:
+	exit(0)
+
+# copy dependencies to destination dir
+copy_count = 0
+for file in dependencies:
+	dest_file = args.dest + "/" + os.path.basename(file)
+	if not os.path.isfile(dest_file):
+		print "Copying " + file + " to " + args.dest
+		shutil.copy2(file, args.dest)
+		copy_count += 1
+print "Copied " + str(copy_count) + " dependencies to '" + str(args.dest) + "'."
+
+exit(0)

From 5e6b0e83b3a5bd2549704aeb9d8c948446c6cad7 Mon Sep 17 00:00:00 2001
From: Philippe Renon <philippe_renon@yahoo.fr>
Date: Sat, 24 Jun 2017 16:11:29 +0200
Subject: [PATCH 2/5] LP-535 cosmetic renaming in addCopyFileTarget and
 addCopyDirTarget

---
 ground/gcs/gcs.pri | 47 ++++++++++++++++++++++++++--------------------
 1 file changed, 27 insertions(+), 20 deletions(-)

diff --git a/ground/gcs/gcs.pri b/ground/gcs/gcs.pri
index 094a09deb..f36f6290e 100644
--- a/ground/gcs/gcs.pri
+++ b/ground/gcs/gcs.pri
@@ -33,19 +33,25 @@ defineTest(addCopyFileTarget) {
     src  = $$2/$$1
     dest = $$3/$$1
 
-    $${file}.target    = $$dest
-    $${file}.depends   = $$src
+    target = $${file}
+    $${target}.target    = $$dest
+    $${target}.depends   = $$src
 
     # create directory. Better would be an order only dependency
-    $${file}.commands  = -@$(MKDIR) \"$$dirname(dest)\" $$addNewline()
-    $${file}.commands += $(COPY_FILE) \"$$src\" \"$$dest\"
+    $${target}.commands  = -@$(MKDIR) \"$$dirname(dest)\" $$addNewline()
+    $${target}.commands += $(COPY_FILE) \"$$src\" \"$$dest\"
 
-    QMAKE_EXTRA_TARGETS += $$file
-    POST_TARGETDEPS += $$eval($${file}.target)
+    QMAKE_EXTRA_TARGETS += $$target
+    POST_TARGETDEPS += $$eval($${target}.target)
 
-    export($${file}.target)
-    export($${file}.depends)
-    export($${file}.commands)
+    export($${target}.target)
+    export($${target}.depends)
+    export($${target}.commands)
+    export(QMAKE_EXTRA_TARGETS)
+    export(POST_TARGETDEPS)
+
+    return(true)
+}
 
 defineTest(addCopyDependenciesTarget) {
     file = $$1
@@ -78,22 +84,23 @@ defineTest(addCopyDirTarget) {
     src  = $$2/$$1
     dest = $$3/$$1
 
-    $${dir}.target    = $$dest
-    $${dir}.depends   = $$src
+    target = $${dir}
+    $${target}.target    = $$dest
+    $${target}.depends   = $$src
     # Windows does not update directory timestamp if files are modified
-    win32: $${dir}.depends += FORCE
+    win32:$${target}depends += FORCE
 
-    $${dir}.commands  = @rm -rf \"$$dest\" $$addNewline()
+    $${target}.commands  = @rm -rf \"$$dest\" $$addNewline()
     # create directory. Better would be an order only dependency
-    $${dir}.commands += -@$(MKDIR) \"$$dirname(dest)\" $$addNewline()
-    $${dir}.commands += $(COPY_DIR) \"$$src\" \"$$dest\"
+    $${target}.commands += -@$(MKDIR) \"$$dirname(dest)\" $$addNewline()
+    $${target}.commands += $(COPY_DIR) \"$$src\" \"$$dest\"
 
-    QMAKE_EXTRA_TARGETS += $$dir
-    POST_TARGETDEPS += $$eval($${dir}.target)
+    QMAKE_EXTRA_TARGETS += $$target
+    POST_TARGETDEPS += $$eval($${target}.target)
 
-    export($${dir}.target)
-    export($${dir}.depends)
-    export($${dir}.commands)
+    export($${target}.target)
+    export($${target}.depends)
+    export($${target}.commands)
     export(QMAKE_EXTRA_TARGETS)
     export(POST_TARGETDEPS)
 

From bdd95f95f35c7b778df09e75ec54fe645d68e680 Mon Sep 17 00:00:00 2001
From: Philippe Renon <philippe_renon@yahoo.fr>
Date: Sat, 24 Jun 2017 16:12:17 +0200
Subject: [PATCH 3/5] LP-535 msys2: use new addCopyDependenciesTarget to
 automatically find and copy library dependencies

---
 ground/gcs/copydata.pro                   | 29 ++-----------
 ground/gcs/src/libs/osgearth/copydata.pro | 50 ++++-------------------
 2 files changed, 11 insertions(+), 68 deletions(-)

diff --git a/ground/gcs/copydata.pro b/ground/gcs/copydata.pro
index e2fc81a67..c0133a7d8 100644
--- a/ground/gcs/copydata.pro
+++ b/ground/gcs/copydata.pro
@@ -87,35 +87,11 @@ win32 {
         Qt5MultimediaWidgets$${DS}.dll \
         Qt5Quick$${DS}.dll \
         Qt5QuickWidgets$${DS}.dll \
-        Qt5Qml$${DS}.dll \
-        libicuin57.dll \
-        libicudt57.dll \
-        libicuuc57.dll \
-        libstdc++-6.dll \
-        libwinpthread-1.dll \
-        libpcre-1.dll \
-        libpcre16-0.dll \
-        zlib1.dll \
-        libharfbuzz-0.dll \
-        libgraphite2.dll \
-        libfreetype-6.dll \
-        libbz2-1.dll \
-        libpng16-16.dll \
-        libjpeg-8.dll \
-        libglib-2.0-0.dll \
-        libintl-8.dll \
-        libiconv-2.dll
-
-    contains(QT_ARCH, i386) {
-        QT_DLLS += \
-            libgcc_s_dw2-1.dll
-    } else {
-        QT_DLLS += \
-            libgcc_s_seh-1.dll
-    }
+        Qt5Qml$${DS}.dll
 
     for(dll, QT_DLLS) {
         addCopyFileTarget($${dll},$$[QT_INSTALL_BINS],$${GCS_APP_PATH})
+        win32:addCopyDependenciesTarget($${dll},$$[QT_INSTALL_BINS],$${GCS_APP_PATH})
     }
 
     # copy OpenSSL DLLs
@@ -141,6 +117,7 @@ win32 {
 
 for(plugin, QT_PLUGINS) {
     addCopyFileTarget($${plugin},$$[QT_INSTALL_PLUGINS],$${GCS_QT_PLUGINS_PATH})
+    win32:addCopyDependenciesTarget($${plugin},$$[QT_INSTALL_PLUGINS],$${GCS_APP_PATH})
 }
 
 # Copy QtQuick2 complete directories
diff --git a/ground/gcs/src/libs/osgearth/copydata.pro b/ground/gcs/src/libs/osgearth/copydata.pro
index b4d89a487..89e018726 100644
--- a/ground/gcs/src/libs/osgearth/copydata.pro
+++ b/ground/gcs/src/libs/osgearth/copydata.pro
@@ -44,39 +44,7 @@ linux|macx {
 }
 
 osg:win32 {
-    # osg & osgearth dependencies
-
-    # curl
-    OSG_LIBS = \
-        libcurl-4.dll \
-        libidn-11.dll \
-        librtmp-1.dll \
-        libgmp-10.dll \
-        libgnutls-30.dll \
-        libunistring-2.dll \
-        libp11-kit-0.dll \
-        libffi-6.dll \
-        libtasn1-6.dll \
-        libssh2-1.dll \
-        libnghttp2-14.dll
-
-    equals(OSG_VERSION, "3.5.1") {
-        OSG_LIBS += \
-            libhogweed-4-2.dll \
-            libnettle-6-2.dll
-    } else {
-        OSG_LIBS += \
-            libhogweed-4.dll \
-            libnettle-6.dll
-    }
-
-    # other
-    OSG_LIBS += \
-        libjpeg-8.dll \
-        libfreetype-6.dll \
-        libpng16-16.dll \
-        libiconv-2.dll \
-        zlib1.dll
+    # osg and osgearth dependencies
 
     # osg libraries
     OSG_LIBS += \
@@ -103,6 +71,7 @@ osg:win32 {
 
     for(lib, OSG_LIBS) {
         addCopyFileTarget($${lib},$${OSG_SDK_DIR}/bin,$${GCS_APP_PATH})
+        win32:addCopyDependenciesTarget($${lib},$${OSG_SDK_DIR}/bin,$${GCS_APP_PATH})
     }
 
     # osg plugins
@@ -183,6 +152,7 @@ osg:win32 {
 
     for(lib, OSG_PLUGINS) {
         addCopyFileTarget($${lib},$${OSG_SDK_DIR}/bin/osgPlugins-$${OSG_VERSION},$${GCS_LIBRARY_PATH}/osg/osgPlugins-$${OSG_VERSION})
+        win32:addCopyDependenciesTarget($${lib},$${OSG_SDK_DIR}/bin/osgPlugins-$${OSG_VERSION},$${GCS_APP_PATH})
     }
 }
 
@@ -193,23 +163,18 @@ osgearth:win32 {
         libosgEarthAnnotation$${DS}.dll \
         libosgEarthFeatures$${DS}.dll \
         libosgEarthSymbology$${DS}.dll \
-        libosgEarthUtil$${DS}.dll \
-        libprotobuf.dll
+        libosgEarthUtil$${DS}.dll
 
-    # gdal
+    # loaded dynamically (probably by an osg plugin, need to find by which)
     OSGEARTH_LIBS += \
-        libgdal-20.dll \
-        libgeos_c.dll \
-        libgeos.dll \
-        libopenjp2-7.dll \
-        libtiff-5.dll \
-        liblzma-5.dll
+        libopenjp2-7.dll
 
     osgearthQt:OSGEARTH_LIBS += \
         libosgEarthQt$${DS}.dll
 
     for(lib, OSGEARTH_LIBS) {
         addCopyFileTarget($${lib},$${OSGEARTH_SDK_DIR}/bin,$${GCS_APP_PATH})
+        win32:addCopyDependenciesTarget($${lib},$${OSGEARTH_SDK_DIR}/bin,$${GCS_APP_PATH})
     }
 
     # osgearth plugins
@@ -261,5 +226,6 @@ osgearth:win32 {
 
     for(lib, OSGEARTH_PLUGINS) {
         addCopyFileTarget($${lib},$${OSGEARTH_SDK_DIR}/bin/osgPlugins-$${OSG_VERSION},$${GCS_LIBRARY_PATH}/osg/osgPlugins-$${OSG_VERSION})
+        win32:addCopyDependenciesTarget($${lib},$${OSGEARTH_SDK_DIR}/bin/osgPlugins-$${OSG_VERSION},$${GCS_APP_PATH})
     }
 }

From 9098517693230aae14971739341797c15b25f2e1 Mon Sep 17 00:00:00 2001
From: Philippe Renon <philippe_renon@yahoo.fr>
Date: Sat, 24 Jun 2017 16:19:37 +0200
Subject: [PATCH 4/5] LP-535 add ntldd to list of required msys2 packages

---
 CONTRIBUTING.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 6f3f11e01..b4fbef76f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -41,7 +41,7 @@ Add the following lines at the end of your /etc/pacman.conf file:
 Start a MinGW-w64 Win64 Shell or a MinGW-w64 Win32 Shell.
 
     pacman -Sy
-    pacman -S --needed git unzip tar mingw-w64-i686-toolchain mingw-w64-i686-ccache mingw-w64-i686-qt5 mingw-w64-i686-SDL mingw-w64-i686-mesa mingw-w64-i686-openssl mingw-w64-i686-gdal-minimal mingw-w64-i686-OpenSceneGraph mingw-w64-i686-osgearth
+    pacman -S --needed git unzip tar mingw-w64-i686-toolchain mingw-w64-i686-ccache mingw-w64-i686-ntldd mingw-w64-i686-qt5 mingw-w64-i686-SDL mingw-w64-i686-mesa mingw-w64-i686-openssl mingw-w64-i686-gdal-minimal mingw-w64-i686-OpenSceneGraph mingw-w64-i686-osgearth
 
 Optionally install debug packages:
 
@@ -52,7 +52,7 @@ Optionally install debug packages:
 Start a MinGW-w64 Win64 Shell.
 
     pacman -Sy
-    pacman -S --needed git unzip tar mingw-w64-x86_64-toolchain mingw-w64-x86_64-ccache mingw-w64-x86_64-qt5 mingw-w64-x86_64-SDL mingw-w64-x86_64-mesa mingw-w64-x86_64-openssl mingw-w64-x86_64-gdal-minimal mingw-w64-x86_64-OpenSceneGraph mingw-w64-x86_64-osgearth
+    pacman -S --needed git unzip tar mingw-w64-x86_64-toolchain mingw-w64-x86_64-ccache mingw-w64-x86_64-ntldd mingw-w64-x86_64-qt5 mingw-w64-x86_64-SDL mingw-w64-x86_64-mesa mingw-w64-x86_64-openssl mingw-w64-x86_64-gdal-minimal mingw-w64-x86_64-OpenSceneGraph mingw-w64-x86_64-osgearth
 
 Optionally install debug packages:
 

From d4f7f4af496b118e66e264f297b8b28e42b4c5bd Mon Sep 17 00:00:00 2001
From: Philippe Renon <philippe_renon@yahoo.fr>
Date: Mon, 26 Jun 2017 10:02:00 +0200
Subject: [PATCH 5/5] LP-535 added ntldd package to .drone.yml (for tea ci)

---
 .drone.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.drone.yml b/.drone.yml
index b8f8c67b2..6babff051 100644
--- a/.drone.yml
+++ b/.drone.yml
@@ -6,7 +6,7 @@ build:
     - if [ $$arch = 32 ]; then target=i686; fi
     - if [ $$arch = 64 ]; then target=x86_64; fi
     - echo -e "[librepilot-mingw]\nSigLevel = Optional TrustAll\nServer = http://download.librepilot.org/repo/mingw" >> /etc/pacman.conf
-    - pacman -Syu --noconfirm --noprogressbar --needed git unzip tar mingw-w64-${target}-toolchain mingw-w64-${target}-ccache mingw-w64-${target}-qt5 mingw-w64-${target}-SDL mingw-w64-${target}-mesa mingw-w64-${target}-openssl mingw-w64-${target}-gdal-minimal mingw-w64-${target}-OpenSceneGraph mingw-w64-${target}-osgearth
+    - pacman -Syu --noconfirm --noprogressbar --needed git unzip tar mingw-w64-${target}-toolchain mingw-w64-${target}-ccache mingw-w64-${target}-ntldd mingw-w64-${target}-qt5 mingw-w64-${target}-SDL mingw-w64-${target}-mesa mingw-w64-${target}-openssl mingw-w64-${target}-gdal-minimal mingw-w64-${target}-OpenSceneGraph mingw-w64-${target}-osgearth
     - mingw32-make all_sdk_install
     - git config core.filemode false
     - mingw32-make build-info && cat build/build-info.txt