Skip to content

Instantly share code, notes, and snippets.

@sveinse
Last active April 17, 2022 16:25
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sveinse/97411b95d36a6b8c430d4d381b620ecb to your computer and use it in GitHub Desktop.
Save sveinse/97411b95d36a6b8c430d4d381b620ecb to your computer and use it in GitHub Desktop.
Scheme for setting up pysndfile and libraries on Windows
#!/bin/bash -x
# The purpose of this script is to build a pysndfile wheel.
# The main purpose of generating a wheel, is to be able to distribute
# the wheel similar to the binary files, not needing to recompiling the
# module on every install.
disr="dist"
binaries="libsndfile_binaries_win32"
venv="venv-pysndfile"
python="winpty py -3"
# Pre cleanup
rm -rf "$venv"
# Create venv
$python -m venv "$venv"
pip="winpty "$(readlink -f "$venv/Scripts/pip")""
$pip install wheel numpy cython
# Unpack the binaries
mkdir -p "$venv/$dist"
tar -C "$venv/$dist" -xf "$binaries.tar.xz"
dir="$(readlink -f $venv/$dist)"
# Alternative 1) Download the official version from pypi
#$pip download --no-deps --no-binary=:all: pysndfile
#tar -xf pysndfile-*.tar.gz
#d=pysndfile-1*
# Alternative 2) Fetch the sources
git clone https://github.com/roebel/pysndfile.git pysndfile
d=pysndfile
# Generate the wheel
cd $d
$pip wheel . --verbose --no-deps \
--global-option=build_ext \
--global-option="-L$dir/lib" \
--global-option="-L$dir/include"
#!/bin/bash -x
# Setup a new venv and install the pysndfile wheel into it. It will
# also inject the libsndfile.dll into the venv, making it possible to
# use pysndfile
dist="dist"
binaries="libsndfile_binaries_win32"
venv="venv"
winpty="winpty"
python="py -3"
# Pre cleanup
rm -rf "$venv" "$dist"
# Create venv
$winpty $python -m venv "$venv"
# Setup new executables
python="$(readlink -f "$venv/Scripts/python")"
pip="$winpty "$(readlink -f "$venv/Scripts/pip")""
# Location of the python libraries
sp="$($python -c 'import distutils.sysconfig; print(distutils.sysconfig.get_python_lib())')"
mkdir -p "$sp"
# Unpack the binary libraries
mkdir -p "$dist"
tar -C "$dist" -xf "${binaries}.tar.xz"
# Install pysndfile and inject dll into it
$pip install wheel pysndfile-*.whl
cp "$dist/lib/"*.dll "$sp/pysndfile/"
# Install the rest of the application here
# $pip install myapp
#!/bin/bash -x
# The purpose of this script is to generate a tarball containing the
# binary non-python libraries needed to run pysndfile.
#
# The official libsndfile isn't compiled with flac and ogg support, so another
# 3rd party distribution is used for this. Secondly the binary distributions
# of libsndfile doesn't come with a .lib file which is required for linking on
# Windows. The crude tool used in this script requires Visual Studio 2017
# to generate the required .lib file.
dist="dist"
binaries="libsndfile_binaries_win32"
venv="venv-pysndfile"
python="winpty py -3"
dll2lib="$(readlink -f win_dll2lib.py)"
# Pre cleanup
rm -rf "$dist" "$binaries"
# Create storage dirs
mkdir -p "$dist/lib" "$dist/include"
# Download the official windows release.
# Copy the headers from it
d=libsndfile-1.0.28-w32
url="http://www.mega-nerd.com/libsndfile/files/libsndfile-1.0.28-w32.zip"
curl -# "$url" -o "$d.zip"
unzip "$d.zip" -d "$d"
cp -av $d/include/*.h $d/include/*.hh $dist/include/
# Get the non-official windows build that includes support for flac and friends
# The library seems statically linked, so only the libsndfile32bit.dll is needed
d=libsndfile-binaries
git clone https://github.com/bastibe/libsndfile-binaries.git $d
( cd $d
git checkout 84cb164928f17c7ca0c1e5c40342c20ce2b90e8c) || exit 1
cp -av $d/libsndfile32bit.dll $dist/lib/
# Generate the libsndfile.lib from the dll:
# Please note that to be able to execute this, Visual Studio 2017 must be installed
( cd $dist/lib
$python "$dll2lib" libsndfile32bit.dll sndfile.lib
)
# Compile the binary
tar -C "$dist" -cvJf "${binaries}.tar.xz" .
""" A crude tool to generate a .lib from a .dll file """
import os
import sys
import subprocess
import tempfile
import re
# Bat script to convert DLL to a DEF file input
dumpbin = r'''
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars32.bat"
@ECHO on
DUMPBIN /exports "%1" >"%2"
'''
# Bat script to convert parsed DEF to LIB
libbat = r'''
CALL "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars32.bat"
@ECHO on
LIB /DEF:"%1" /OUT:"%2" /MACHINE:X86
'''
# Rudimentary argument checking
print(sys.argv)
if len(sys.argv) < 3:
raise Exception("Too few arguments")
# Get the file
infile = sys.argv[1]
deffile = infile.replace('.dll', '.def')
outfile = sys.argv[2]
expfile = outfile.replace('.lib', '.exp')
# Ensure the input exists
if not os.path.exists(infile):
raise FileNotFoundError(infile)
# Create a temp working directory
with tempfile.TemporaryDirectory() as tmpdirname:
# Write the temp bat script for dumping the DLL file and run it
bat = os.path.join(tmpdirname, 'run.bat')
with open(bat, 'w') as f:
f.write(dumpbin)
subprocess.check_call([bat, infile, deffile])
# Parse the output from dumpbin and make it into a file with
# EXPORTS
# method names...
out = 'EXPORTS\n'
with open(deffile, 'r') as f:
mode = 'header'
n = 0
i = 1
for line in f:
n += 1
l = line.strip()
s = re.split(r'\s+', l)
if len(s) != 4:
continue
try:
ordinal = int(s[0])
except ValueError:
continue
if ordinal != i:
continue
i += 1
out += s[3] + '\n'
# Write the def file
print(deffile)
with open(deffile, 'w') as f:
f.write(out)
# Write the temp bat script for generating the LIB file and run it
bat = os.path.join(tmpdirname, 'run.bat')
with open(bat, 'w') as f:
f.write(libbat)
subprocess.check_call([bat, deffile, outfile])
# Remove the temporary def file
os.remove(deffile)
os.remove(expfile)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment