aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorJoão Valverde <j@v6e.pt>2023-05-21 15:44:35 +0100
committerJoão Valverde <j@v6e.pt>2023-05-22 00:54:39 +0100
commitaa6b8368b7efc97e38f65aa89a33d37b5eecb64b (patch)
tree0b9b3fecb42ab4ddd3ae94c0e1cd8fd336d4eaed /tools
parent83cebf956375d8c11cb14c32d1831c73fc0f55ac (diff)
MSYS2: Add support for building a stand-alone NSIS installer
This changes the existing code for the MSVC installer as little as possible to allow building the Wireshark .exe Windows installer using the MinGW-w64 toolchain. Currently the DLL dependency list is static, this may change in the future. Ideally we would use CPack and install() logic to copy the DLLs. The msys2checkdeps.py script is copied from the Inkscape project[1]. It doesn't have a specific license identifier. The Inkscape project is licensed under the GPL version 2 or later. TODO: Download Npcap and USBPcap using CMake instead of requiring manual action. [1]https://gitlab.com/inkscape/inkscape Ping #17771.
Diffstat (limited to 'tools')
-rw-r--r--tools/msys2-setup.sh4
-rw-r--r--tools/msys2checkdeps.py177
2 files changed, 180 insertions, 1 deletions
diff --git a/tools/msys2-setup.sh b/tools/msys2-setup.sh
index 6056be5051..e658db58ce 100644
--- a/tools/msys2-setup.sh
+++ b/tools/msys2-setup.sh
@@ -82,6 +82,7 @@ BASIC_LIST="base-devel \
${PACKAGE_PREFIX}-qt6-base \
${PACKAGE_PREFIX}-qt6-multimedia \
${PACKAGE_PREFIX}-qt6-tools \
+ ${PACKAGE_PREFIX}-qt6-translations \
${PACKAGE_PREFIX}-qt6-5compat \
${PACKAGE_PREFIX}-sbc \
${PACKAGE_PREFIX}-snappy \
@@ -97,7 +98,8 @@ ADDITIONAL_LIST="${PACKAGE_PREFIX}-asciidoctor \
${PACKAGE_PREFIX}-docbook-xsl \
${PACKAGE_PREFIX}-doxygen \
${PACKAGE_PREFIX}-libxslt \
- ${PACKAGE_PREFIX}-perl"
+ ${PACKAGE_PREFIX}-perl \
+ ${PACKAGE_PREFIX}-ntldd"
TESTDEPS_LIST="${PACKAGE_PREFIX}-python-pytest \
${PACKAGE_PREFIX}-python-pytest-xdist"
diff --git a/tools/msys2checkdeps.py b/tools/msys2checkdeps.py
new file mode 100644
index 0000000000..f46eb503b4
--- /dev/null
+++ b/tools/msys2checkdeps.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+# ------------------------------------------------------------------------------------------------------------------
+# list or check dependencies for binary distributions based on MSYS2 (requires the package mingw-w64-ntldd)
+#
+# run './msys2checkdeps.py --help' for usage information
+# ------------------------------------------------------------------------------------------------------------------
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+from __future__ import print_function
+
+
+import argparse
+import os
+import subprocess
+import sys
+
+
+SYSTEMROOT = os.environ['SYSTEMROOT']
+
+
+class Dependency:
+ def __init__(self):
+ self.location = None
+ self.dependents = set()
+
+
+def warning(msg):
+ print("Warning: " + msg, file=sys.stderr)
+
+
+def error(msg):
+ print("Error: " + msg, file=sys.stderr)
+ exit(1)
+
+
+def call_ntldd(filename):
+ try:
+ output = subprocess.check_output(['ntldd', '-R', filename], stderr=subprocess.STDOUT)
+ except subprocess.CalledProcessError as e:
+ error("'ntldd' failed with '" + str(e) + "'")
+ except WindowsError as e:
+ error("Calling 'ntldd' failed with '" + str(e) + "' (have you installed 'mingw-w64-ntldd-git'?)")
+ except Exception as e:
+ error("Calling 'ntldd' failed with '" + str(e) + "'")
+ return output.decode('utf-8')
+
+
+def get_dependencies(filename, deps):
+ raw_list = call_ntldd(filename)
+
+ skip_indent = float('Inf')
+ parents = {}
+ parents[0] = os.path.basename(filename)
+ for line in raw_list.splitlines():
+ line = line[1:]
+ indent = len(line) - len(line.lstrip())
+ if indent > skip_indent:
+ continue
+ else:
+ skip_indent = float('Inf')
+
+ # if the dependency is not found in the working directory ntldd tries to find it on the search path
+ # which is indicated by the string '=>' followed by the determined location or 'not found'
+ if ('=>' in line):
+ (lib, location) = line.lstrip().split(' => ')
+ if location == 'not found':
+ location = None
+ else:
+ location = location.rsplit('(', 1)[0].strip()
+ else:
+ lib = line.rsplit('(', 1)[0].strip()
+ location = os.getcwd()
+
+ parents[indent+1] = lib
+
+ # we don't care about Microsoft libraries and their dependencies
+ if location and SYSTEMROOT in location:
+ skip_indent = indent
+ continue
+
+ if lib not in deps:
+ deps[lib] = Dependency()
+ deps[lib].location = location
+ deps[lib].dependents.add(parents[indent])
+ return deps
+
+
+def collect_dependencies(path):
+ # collect dependencies
+ # - each key in 'deps' will be the filename of a dependency
+ # - the corresponding value is an instance of class Dependency (containing full path and dependents)
+ deps = {}
+ if os.path.isfile(path):
+ deps = get_dependencies(path, deps)
+ elif os.path.isdir(path):
+ extensions = ['.exe', '.pyd', '.dll']
+ exclusions = ['distutils/command/wininst'] # python
+ for base, dirs, files in os.walk(path):
+ for f in files:
+ filepath = os.path.join(base, f)
+ (_, ext) = os.path.splitext(f)
+ if (ext.lower() not in extensions) or any(exclusion in filepath for exclusion in exclusions):
+ continue
+ deps = get_dependencies(filepath, deps)
+ return deps
+
+
+if __name__ == '__main__':
+ modes = ['list', 'list-compact', 'check', 'check-missing', 'check-unused']
+
+ # parse arguments from command line
+ parser = argparse.ArgumentParser(description="List or check dependencies for binary distributions based on MSYS2.\n"
+ "(requires the package 'mingw-w64-ntldd')",
+ formatter_class=argparse.RawTextHelpFormatter)
+ parser.add_argument('mode', metavar="MODE", choices=modes,
+ help="One of the following:\n"
+ " list - list dependencies in human-readable form\n"
+ " with full path and list of dependents\n"
+ " list-compact - list dependencies in compact form (as a plain list of filenames)\n"
+ " check - check for missing or unused dependencies (see below for details)\n"
+ " check-missing - check if all required dependencies are present in PATH\n"
+ " exits with error code 2 if missing dependencies are found\n"
+ " and prints the list to stderr\n"
+ " check-unused - check if any of the libraries in the root of PATH are unused\n"
+ " and prints the list to stderr")
+ parser.add_argument('path', metavar='PATH',
+ help="full or relative path to a single file or a directory to work on\n"
+ "(directories will be checked recursively)")
+ parser.add_argument('-w', '--working-directory', metavar="DIR",
+ help="Use custom working directory (instead of 'dirname PATH')")
+ args = parser.parse_args()
+
+ # check if path exists
+ args.path = os.path.abspath(args.path)
+ if not os.path.exists(args.path):
+ error("Can't find file/folder '" + args.path + "'")
+
+ # get root and set it as working directory (unless one is explicitly specified)
+ if args.working_directory:
+ root = os.path.abspath(args.working_directory)
+ elif os.path.isdir(args.path):
+ root = args.path
+ elif os.path.isfile(args.path):
+ root = os.path.dirname(args.path)
+ os.chdir(root)
+
+ # get dependencies for path recursively
+ deps = collect_dependencies(args.path)
+
+ # print output / prepare exit code
+ exit_code = 0
+ for dep in sorted(deps):
+ location = deps[dep].location
+ dependents = deps[dep].dependents
+
+ if args.mode == 'list':
+ if (location is None):
+ location = '---MISSING---'
+ print(dep + " - " + location + " (" + ", ".join(dependents) + ")")
+ elif args.mode == 'list-compact':
+ print(dep)
+ elif args.mode in ['check', 'check-missing']:
+ if ((location is None) or (root not in os.path.abspath(location))):
+ warning("Missing dependency " + dep + " (" + ", ".join(dependents) + ")")
+ exit_code = 2
+
+ # check for unused libraries
+ if args.mode in ['check', 'check-unused']:
+ installed_libs = [file for file in os.listdir(root) if file.endswith(".dll")]
+ deps_lower = [dep.lower() for dep in deps]
+ top_level_libs = [lib for lib in installed_libs if lib.lower() not in deps_lower]
+ for top_level_lib in top_level_libs:
+ warning("Unused dependency " + top_level_lib)
+
+ exit(exit_code)