mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-24 04:29:34 -04:00
Add pkg/win32 support to create self-supporting Windows zips (#49)
This commit is contained in:
parent
ffef698040
commit
822f09ea79
@ -84,5 +84,6 @@ examples/Makefile
|
||||
Source/Makefile
|
||||
Source/resource.rc
|
||||
toolsrc/Makefile
|
||||
pkg/config.make
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
2
pkg/.gitignore
vendored
Normal file
2
pkg/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
Makefile
|
||||
config.make
|
8
pkg/Makefile.am
Normal file
8
pkg/Makefile.am
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
WIN32_FILES= \
|
||||
win32/GNUmakefile \
|
||||
win32/cp-with-libs \
|
||||
win32/README
|
||||
|
||||
EXTRA_DIST=$(WIN32_FILES)
|
||||
|
21
pkg/config.make.in
Normal file
21
pkg/config.make.in
Normal file
@ -0,0 +1,21 @@
|
||||
# Shared file included by the makefiles used to build packages.
|
||||
# This contains various information needed by the makefiles,
|
||||
# and is autogenerated by configure to include various
|
||||
# necessary details.
|
||||
|
||||
# Tools needed:
|
||||
|
||||
CC = @CC@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
STRIP = @STRIP@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
# Package name and version number:
|
||||
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
# Documentation files to distribute with packages.
|
||||
|
||||
DOC_FILES = README.md \
|
||||
COPYING
|
2
pkg/win32/.gitignore
vendored
Normal file
2
pkg/win32/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
staging/
|
||||
*.zip
|
24
pkg/win32/GNUmakefile
Normal file
24
pkg/win32/GNUmakefile
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
include ../config.make
|
||||
|
||||
TOPLEVEL=../..
|
||||
|
||||
ZIP=$(PACKAGE)$(PACKAGE_VERSION)-win32.zip
|
||||
|
||||
all: $(ZIP)
|
||||
|
||||
$(ZIP): staging
|
||||
zip -X -j -r $@ $<
|
||||
|
||||
staging:
|
||||
mkdir $@
|
||||
LC_ALL=C ./cp-with-libs --ldflags="$(LDFLAGS)" "$(TOPLEVEL)/Source/woof.exe"
|
||||
|
||||
$(STRIP) $@/*.exe $@/*.dll
|
||||
|
||||
unix2dos --add-bom --newfile "$(TOPLEVEL)/README.md" $@/README.txt
|
||||
unix2dos --add-bom --newfile "$(TOPLEVEL)/COPYING" $@/COPYING.txt
|
||||
|
||||
clean:
|
||||
$(RM) -r -- $(ZIP)
|
||||
$(RM) -r -- staging-*
|
175
pkg/win32/cp-with-libs
Executable file
175
pkg/win32/cp-with-libs
Executable file
@ -0,0 +1,175 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright(C) 2016 Simon Howard
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
|
||||
#
|
||||
# This script copies a Windows .exe file from a source to a destination
|
||||
# (like cp); however, it also uses the binutils objdump command to
|
||||
# recursively determine all its DLL dependencies and copy those too.
|
||||
#
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import shutil
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
DLL_NAME_RE = re.compile('\s+DLL Name: (.*\.dll)')
|
||||
|
||||
# DLLs that are bundled with Windows, and we don't need to copy.
|
||||
# Thanks to Martin Preisler; this is from mingw-bundledlls.
|
||||
WIN32_DLLS = {
|
||||
"advapi32.dll", "kernel32.dll", "msvcrt.dll", "ole32.dll",
|
||||
"user32.dll", "ws2_32.dll", "comdlg32.dll", "gdi32.dll", "imm32.dll",
|
||||
"oleaut32.dll", "shell32.dll", "winmm.dll", "winspool.drv",
|
||||
"wldap32.dll", "ntdll.dll", "d3d9.dll", "mpr.dll", "crypt32.dll",
|
||||
"dnsapi.dll", "shlwapi.dll", "version.dll", "iphlpapi.dll",
|
||||
"msimg32.dll", "setupapi.dll", "dsound.dll",
|
||||
}
|
||||
|
||||
parser = argparse.ArgumentParser(description='Copy EXE with DLLs.')
|
||||
parser.add_argument('--objdump', type=str, default='objdump',
|
||||
help='name of objdump binary to invoke')
|
||||
parser.add_argument('--dll_path', type=str, nargs='*', default=(),
|
||||
help='list of paths to check for DLLs')
|
||||
parser.add_argument('--ldflags', type=str, default="",
|
||||
help='linker flags, which can be used to automatically '
|
||||
'determine the DLL path')
|
||||
parser.add_argument('source', type=str,
|
||||
help='path to binary to copy')
|
||||
parser.add_argument('destination', type=str,
|
||||
help='destination to copy binary')
|
||||
|
||||
def file_dependencies(filename, objdump):
|
||||
"""Get the direct DLL dependencies of the given file.
|
||||
|
||||
The DLLs depended on by the given file are determined by invoking
|
||||
the provided objdump binary. DLLs which are part of the standard
|
||||
Win32 API are excluded from the result.
|
||||
|
||||
Args:
|
||||
filename: Path to a file to query.
|
||||
objdump: Name of objdump binary to invoke.
|
||||
Returns:
|
||||
List of filenames (not fully qualified paths).
|
||||
"""
|
||||
cmd = subprocess.Popen([objdump, '-p', filename],
|
||||
stdout=subprocess.PIPE)
|
||||
try:
|
||||
result = []
|
||||
for line in cmd.stdout:
|
||||
m = DLL_NAME_RE.match(line.decode())
|
||||
if m:
|
||||
dll = m.group(1)
|
||||
if dll.lower() not in WIN32_DLLS:
|
||||
result.append(dll)
|
||||
|
||||
return result
|
||||
finally:
|
||||
cmd.wait()
|
||||
assert cmd.returncode == 0, (
|
||||
'%s invocation for %s exited with %d' % (
|
||||
objdump, filename, cmd.returncode))
|
||||
|
||||
def find_dll(filename, dll_paths):
|
||||
"""Search the given list of paths for a DLL with the given name."""
|
||||
for path in dll_paths:
|
||||
full_path = os.path.join(path, filename)
|
||||
if os.path.exists(full_path):
|
||||
return full_path
|
||||
|
||||
raise IOError('DLL file %s not found in path: %s' % (
|
||||
filename, dll_paths))
|
||||
|
||||
def all_dependencies(filename, objdump, dll_paths):
|
||||
"""Recursively find all dependencies of the given executable file.
|
||||
|
||||
Args:
|
||||
filename: Executable file to examine.
|
||||
objdump: Command to invoke to find dependencies.
|
||||
dll_paths: List of directories to search for DLL files.
|
||||
Returns:
|
||||
Tuple containing:
|
||||
Set containing paths to all DLL dependencies of the file.
|
||||
Set of filenames of missing DLLs.
|
||||
"""
|
||||
result, missing = set(), set()
|
||||
to_process = {filename}
|
||||
while len(to_process) > 0:
|
||||
filename = to_process.pop()
|
||||
for dll in file_dependencies(filename, objdump):
|
||||
try:
|
||||
dll = find_dll(dll, dll_paths)
|
||||
if dll not in result:
|
||||
result |= {dll}
|
||||
to_process |= {dll}
|
||||
except IOError as e:
|
||||
missing |= {dll}
|
||||
|
||||
return result, missing
|
||||
|
||||
def get_dll_path():
|
||||
"""Examine command line arguments and determine the DLL search path.
|
||||
|
||||
If the --path argument is provided, paths from this are added.
|
||||
Furthermore, if --ldflags is provided, this is interpreted as a list of
|
||||
linker flags and the -L paths are used to find associated paths that are
|
||||
likely to contain DLLs, with the assumption that autotools usually
|
||||
installs DLLs to ${prefix}/bin when installing Unix-style libraries into
|
||||
${prefix}/lib.
|
||||
|
||||
Returns:
|
||||
List of filesystem paths to check for DLLs.
|
||||
"""
|
||||
result = set(args.dll_path)
|
||||
|
||||
if args.ldflags != '':
|
||||
for arg in shlex.split(args.ldflags):
|
||||
if arg.startswith("-L"):
|
||||
prefix, libdir = os.path.split(arg[2:])
|
||||
if libdir != "lib":
|
||||
continue
|
||||
bindir = os.path.join(prefix, "bin")
|
||||
if os.path.exists(bindir):
|
||||
result |= {bindir}
|
||||
|
||||
return list(result)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
dll_path = get_dll_path()
|
||||
dll_files, missing = all_dependencies(args.source, args.objdump, dll_path)
|
||||
|
||||
# Exit with failure if DLLs are missing.
|
||||
if missing:
|
||||
sys.stderr.write("Missing DLLs not found in path %s:\n" % (dll_path,))
|
||||
for filename in missing:
|
||||
sys.stderr.write("\t%s\n" % filename)
|
||||
sys.exit(1)
|
||||
|
||||
# Destination may be a full path (rename) or may be a directory to copy into:
|
||||
# cp foo.exe bar/baz.exe
|
||||
# cp foo.exe bar/
|
||||
if os.path.isdir(args.destination):
|
||||
dest_dir = args.destination
|
||||
else:
|
||||
dest_dir = os.path.dirname(args.destination)
|
||||
|
||||
# Copy .exe and DLLs.
|
||||
shutil.copy(args.source, args.destination)
|
||||
for filename in dll_files:
|
||||
shutil.copy(filename, dest_dir)
|
||||
|
Loading…
x
Reference in New Issue
Block a user