Skip to content

Instantly share code, notes, and snippets.

@pgaskin
Last active January 3, 2021 10:36
Show Gist options
  • Save pgaskin/6af44db4ac6b7fa538d8acc85ff67dcc to your computer and use it in GitHub Desktop.
Save pgaskin/6af44db4ac6b7fa538d8acc85ff67dcc to your computer and use it in GitHub Desktop.
FROM opensuse/tumbleweed AS mingw32
RUN zypper --non-interactive addrepo https://download.opensuse.org/repositories/windows:mingw:win32/openSUSE_Tumbleweed/windows:mingw:win32.repo && \
zypper --non-interactive --gpg-auto-import-keys refresh
RUN zypper --non-interactive install \
wget m4 git-core meson bsdtar gzip xmlstarlet \
mingw32-filesystem mingw32-cross-gcc mingw32-cross-gcc-c++ mingw32-cross-binutils mingw32-cross-pkgconf && \
zypper clean
FROM i386/alpine AS wine
ENV WINEDEBUG="-all" \
WINEDLLOVERRIDES="mscoree,mshtml=" \
WINEARCH="win32" \
WINEPREFIX="/opt/wine"
RUN apk add --no-cache wine ncurses freetype
FROM wine AS inno-tmp
RUN apk add --no-cache xvfb ca-certificates
RUN set -x; \
export DISPLAY=:0; \
Xvfb :0 -screen 0 1024x768x16 & sleep .5 && \
wineboot --init && \
wget -q http://files.jrsoftware.org/is/6/innosetup-6.1.2.exe && \
wine innosetup-6.1.2.exe /SP- /VERYSILENT /ALLUSERS /SUPPRESSMSGBOXES && \
rm innosetup-6.1.2.exe && \
wineboot --shutdown && \
pkill Xvfb && sleep .5
FROM wine AS inno
RUN touch /bin/iscc && \
chmod +x /bin/iscc && \
echo '#!/bin/sh' >> /bin/iscc && \
echo 'wine "C:\\Program Files\\Inno Setup 6\\ISCC.exe" "$*"' >> /bin/iscc
COPY --from=inno-tmp ${WINEPREFIX} ${WINEPREFIX}
FROM mingw32 AS build-pulseaudio-tmp
RUN zypper --non-interactive install \
intltool gettext-tools mingw32-libsndfile-devel mingw32-libintl-devel mingw32-win_iconv-devel mingw32-pcre-devel \
orc mingw32-libspeex-devel mingw32-liborc-devel mingw32-libtool && \
zypper clean
RUN mkdir /src
RUN wget -qO /src/linux-mingw-w64-32bit.txt https://raw.githubusercontent.com/mesonbuild/meson/master/cross/linux-mingw-w64-32bit.txt
RUN git clone https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git /src/pulseaudio && \
git -c advice.detachedHead=false -C /src/pulseaudio checkout 8f6029077a0c18f4d12105e9bd8c093c25ad7b38
RUN sed -i 's/privlibdir = .*/privlibdir = bindir/' /src/pulseaudio/meson.build
RUN meson setup \
--cross-file /src/linux-mingw-w64-32bit.txt \
-Dtests=false \
-Ddatabase=simple \
-Drunning-from-build-tree=false \
-Dlegacy-database-entry-format=false \
-Dprefix=/pulseaudio \
-Dbindir=/pulseaudio \
-Dlibdir=/pulseaudio \
-Dsysconfdir=/pulseaudio \
-Dmodlibexecdir=/pulseaudio \
-Dbluez5=false \
/build/pulseaudio /src/pulseaudio
RUN ninja -C /build/pulseaudio
RUN meson install -C /build/pulseaudio
FROM mingw32 AS build-pulseaudio-polish
COPY --from=build-pulseaudio-tmp /pulseaudio /pulseaudio
RUN rm -r \
# static libraries
/pulseaudio/*.a \
# development files
/pulseaudio/pkgconfig /pulseaudio/include /pulseaudio/cmake /pulseaudio/share/vala \
# manual pages
/pulseaudio/share/man \
# shell completion
/pulseaudio/share/bash-completion /pulseaudio/share/zsh \
# extra locales
/pulseaudio/share/locale \
# configuration files (these won't even be loaded due to the fixed paths)
/pulseaudio/pulse \
# misc scripts (not compatible with windows)
/pulseaudio/pa-info && \
rmdir /pulseaudio/share
RUN echo '#!/bin/bash' >> /deps.sh && \
echo 'set -eo pipefail' >> /deps.sh && \
echo 'xml() { xmlstarlet sel -N p="http://linux.duke.edu/metadata/repo" -N m="http://linux.duke.edu/metadata/common" -N r="http://linux.duke.edu/metadata/rpm" -t -v "$1" ; }' >> /deps.sh && \
echo 'repomd="$(wget -qO- "$1/repodata/repomd.xml" | xml "/p:repomd/p:data[@type=\"primary\"]/p:location/@href")"' >> /deps.sh && \
echo 'repopk="$(wget -qO- "$1/$repomd" | zcat -)"' >> /deps.sh && \
echo 'dlls_builtin="$(xml "/m:metadata/m:package[m:name=\"mingw32-runtime\"]/m:format/r:provides/r:entry/@name" <<< "$repopk" | sed -En "s/mingw32\(lib:(.+)\)/\1.dll/p")"' >> /deps.sh && \
echo 'while true; do' >> /deps.sh && \
echo ' dlls_deps="$(find "$2" -maxdepth 1 \( -name "*.exe" -o -name "*.dll" \) -exec i686-w64-mingw32-objdump --private-headers {} \; | sed -En "s/.*DLL Name: ([^ ]+).*/\\1/p" | sort | uniq)"' >> /deps.sh && \
echo ' dlls_have="$(find "$2" -maxdepth 1 -name "*.dll" -exec basename {} \; )"' >> /deps.sh && \
echo ' dll="$({ grep -ivxFf <(cat <<< "$dlls_have") -f <(cat <<< "$dlls_builtin") <<< "$dlls_deps" || true; } | head -n1)"' >> /deps.sh && \
echo ' test -n "$dll" || break' >> /deps.sh && \
echo ' pkg="$(xml "/m:metadata/m:package[m:format/r:provides/r:entry/@name=\"mingw32($(tr "[A-Z]" "[a-z]" <<< "$dll"))\"][last()]/m:location/@href" <<< "$repopk" || true)"' >> /deps.sh && \
echo ' test -n "$pkg" || { echo "Error: No package for $dll." >&2; exit 1; }' >> /deps.sh && \
echo ' wget -qO- "$1/$pkg" | rpm2cpio | bsdtar -xvf - -s "|.*/||" -C "$2" ./usr/i686-w64-mingw32/sys-root/mingw/bin/$dll' >> /deps.sh && \
echo 'done' >> /deps.sh
RUN bash deps.sh "https://download.opensuse.org/repositories/windows:/mingw:/win32/openSUSE_Tumbleweed" /pulseaudio
FROM wine AS build-pulseaudio-icon
COPY --from=build-pulseaudio-polish /pulseaudio /pulseaudio
RUN apk add --no-cache inkscape imagemagick xvfb unzip
RUN echo '<?xml version="1.0" encoding="UTF-8"?><svg width="48" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink"> <metadata> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> <dc:title/> </cc:Work> </rdf:RDF> </metadata> <defs> <linearGradient id="f" x1="585" x2="585" y1="390.61" y2="85.377" gradientTransform="matrix(.15426 0 0 .15349 -67.321 -12.481)" gradientUnits="userSpaceOnUse"> <stop offset="0"/> <stop stop-color="#141413" offset="1"/> </linearGradient> <linearGradient id="h" x1="585" x2="585" y1="390.61" y2="85.377" gradientTransform="matrix(.15426 0 0 .15349 -67.321 -12.482)" gradientUnits="userSpaceOnUse" xlink:href="#d"/> <linearGradient id="d"> <stop stop-color="#fff" stop-opacity=".361" offset="0"/> <stop stop-color="#fff" stop-opacity="0" offset="1"/> </linearGradient> <linearGradient id="g" x1="532" x2="667.5" y1="131.41" y2="357.41" gradientTransform="matrix(.15426 0 0 .15349 -67.32 -12.482)" gradientUnits="userSpaceOnUse" xlink:href="#d"/> </defs> <rect x="1.0162" y="1.2747" width="45.815" height="45.586" ry="8.0042" stroke="url(#f)" stroke-linecap="round" stroke-width="1.2311"/> <g transform="matrix(1.2366 0 0 1.2305 -5.7556 -1.4643)" fill="#729fcf"> <path d="m28.81 20.75a4.81 4.81 0 1 1-9.62 0 4.81 4.81 0 1 1 9.62 0z"/> <path d="m21.496 11.326c-4.169 1.107-7.243 4.907-7.243 9.422 0 4.516 3.074 8.32 7.243 9.426-3.007-1.35-5.17-5.063-5.17-9.426s2.163-8.072 5.17-9.422zm5.009 0c3.007 1.35 5.169 5.06 5.169 9.422 0 4.363-2.162 8.076-5.17 9.426 4.17-1.107 7.244-4.91 7.244-9.426 0-4.515-3.075-8.315-7.243-9.422z"/> <path d="m20.09 6.034c-6.51 1.728-11.312 7.662-11.312 14.713s4.8 12.991 11.31 14.72c-4.696-2.108-8.072-7.907-8.072-14.72s3.376-12.605 8.072-14.713zm7.821 0c4.696 2.108 8.072 7.9 8.072 14.713s-3.376 12.612-8.072 14.72c6.51-1.729 11.31-7.669 11.31-14.72s-4.8-12.985-11.31-14.713z"/> </g> <path d="m9.0615 1.9221c-4.1085 0-7.3947 3.2655-7.3947 7.353v29.58c0 4.0874 3.2866 7.3578 7.3947 7.3578h29.724c4.1079 0 7.3947-3.2702 7.3947-7.3578v-29.58c0-4.0874-3.2862-7.353-7.3947-7.353z" fill="url(#linearGradient2395)" stroke-width=".15387"/> <path d="m44.978 17.3c-5.9275 6.3225-12.02 6.8205-20.998 6.8205-8.8379 0-15.552 4.1974-21.112 9.5307v5.2032c0 3.564 2.7856 6.1587 6.1944 6.1587l29.724 0.61886c3.7938 0 6.1896-3.0025 6.1896-6.7774l0.0023-21.555z" fill="url(#g)" fill-rule="evenodd" stroke-width=".15387"/> <path d="m9.0615 2.5024c-3.7948 0-6.8114 2.9976-6.8114 6.7727v29.58c0 3.7749 3.0176 6.7774 6.8114 6.7774h29.724c3.7938 0 6.8114-3.0025 6.8114-6.7774v-29.58c0-3.775-3.0167-6.7727-6.8114-6.7727z" fill="none" stroke="url(#h)" stroke-linecap="round" stroke-width="1.231"/></svg>' > /pulseaudio-flat.svg
RUN echo '<?xml version="1.0" encoding="UTF-8"?><svg width="48" height="48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink"> <metadata> <rdf:RDF> <cc:Work rdf:about=""> <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/> <dc:title/> </cc:Work> </rdf:RDF> </metadata> <defs> <linearGradient id="f" x1="585" x2="585" y1="390.61" y2="85.377" gradientTransform="matrix(.15426 0 0 .15349 -67.321 -12.481)" gradientUnits="userSpaceOnUse"> <stop offset="0"/> <stop stop-color="#141413" offset="1"/> </linearGradient> <linearGradient id="h" x1="585" x2="585" y1="390.61" y2="85.377" gradientTransform="matrix(.15426 0 0 .15349 -67.321 -12.482)" gradientUnits="userSpaceOnUse" xlink:href="#d"/> <linearGradient id="d"> <stop stop-color="#fff" stop-opacity=".361" offset="0"/> <stop stop-color="#fff" stop-opacity="0" offset="1"/> </linearGradient> <linearGradient id="g" x1="532" x2="667.5" y1="131.41" y2="357.41" gradientTransform="matrix(.15426 0 0 .15349 -67.32 -12.482)" gradientUnits="userSpaceOnUse" xlink:href="#d"/> </defs> <rect x="1.0162" y="1.2747" width="45.815" height="45.586" ry="8.0042" stroke="url(#f)" stroke-linecap="round" stroke-width="1.2311"/> <g transform="matrix(1.2366 0 0 1.2305 -5.7556 -1.4643)" fill="#99cbf3"> <path d="m29.488 20.75c0 2.6565-2.832 5.6158-5.4884 5.6158s-5.3034-2.9593-5.3034-5.6158c0-1.4861 0.46107-2.6891 1.1926-3.594 2.8076-3.4732 9.5993-2.5565 9.5993 3.594z"/> <path d="m22.304 10.513c-4.169 1.107-8.8603 5.7197-8.8603 10.235 0 4.516 4.6913 9.1329 8.8603 10.239-4.1409-4.5935-5.7168-5.7883-5.7168-10.151s0.87811-4.4139 5.7168-10.322zm3.3923 0c2.0475 2.0513 5.8028 6.4863 5.8028 10.848 0 4.363-2.6456 4.7688-6.6131 9.6253 4.17-1.107 9.6698-5.7229 9.6698-10.239 0-4.515-4.6915-9.1277-8.8595-10.235z"/> <path d="m20.09 6.034c-6.51 1.728-12.929 7.662-12.929 14.713s6.417 12.991 12.927 14.72c-3.9559-3.2857-8.8805-7.907-8.8805-14.72s4.6779-11.055 8.8805-14.713zm7.821 0c3.7708 2.7279 8.8803 7.9 8.8803 14.713s-5.2328 11.558-8.8803 14.72c6.51-1.729 12.928-7.669 12.928-14.72s-6.4176-12.985-12.928-14.713z"/> </g> <path d="m9.0615 1.9221c-4.1085 0-7.3947 3.2655-7.3947 7.353v29.58c0 4.0874 3.2866 7.3578 7.3947 7.3578h29.724c4.1079 0 7.3947-3.2702 7.3947-7.3578v-29.58c0-4.0874-3.2862-7.353-7.3947-7.353z" fill="url(#linearGradient2395)" stroke-width=".15387"/> <path d="m44.978 17.3c-5.9275 6.3225-12.02 6.8205-20.998 6.8205-8.8379 0-15.552 4.1974-21.112 9.5307v5.2032c0 3.564 2.7856 6.1587 6.1944 6.1587l29.724 0.61886c3.7938 0 6.1896-3.0025 6.1896-6.7774l0.0023-21.555z" fill="url(#g)" fill-rule="evenodd" stroke-width=".15387"/> <path d="m9.0615 2.5024c-3.7948 0-6.8114 2.9976-6.8114 6.7727v29.58c0 3.7749 3.0176 6.7774 6.8114 6.7774h29.724c3.7938 0 6.8114-3.0025 6.8114-6.7774v-29.58c0-3.775-3.0167-6.7727-6.8114-6.7727z" fill="none" stroke="url(#h)" stroke-linecap="round" stroke-width="1.231"/></svg>' > /pulsaudio-flat-fat.svg
RUN set -x; \
export DISPLAY=:0; \
Xvfb :0 -screen 0 1024x768x16 & sleep .5 && \
inkscape -w 16 -h 16 --export-filename=/pulseaudio-flat.16.png /pulseaudio-flat-fat.svg && \
inkscape -w 32 -h 32 --export-filename=/pulseaudio-flat.32.png /pulseaudio-flat-fat.svg && \
inkscape -w 48 -h 48 --export-filename=/pulseaudio-flat.48.png /pulseaudio-flat-fat.svg && \
inkscape -w 64 -h 64 --export-filename=/pulseaudio-flat.64.png /pulseaudio-flat.svg && \
inkscape -w 96 -h 96 --export-filename=/pulseaudio-flat.96.png /pulseaudio-flat.svg && \
inkscape -w 128 -h 128 --export-filename=/pulseaudio-flat.96.png /pulseaudio-flat.svg && \
convert /pulseaudio-flat.*.png /pulseaudio.ico && \
rm /pulseaudio-flat.svg /pulseaudio-flat.*.png && \
pkill Xvfb && sleep .5
RUN wget -O /reshack.zip http://www.angusj.com/resourcehacker/resource_hacker.zip && \
unzip /reshack.zip ResourceHacker.exe -d / && \
rm /reshack.zip
RUN set -x; \
export DISPLAY=:0; \
Xvfb :0 -screen 0 1024x768x16 & sleep .5 && \
wine 'Z:/ResourceHacker.exe' -open 'Z:\pulseaudio\pulseaudio.exe' -save 'Z:\pulseaudio\pulseaudio.exe' -action addskip -res 'Z:\pulseaudio.ico' -mask ICONGROUP,MAINICON, && \
pkill Xvfb && sleep .5
FROM mingw32 AS build-pulseaudio
COPY --from=build-pulseaudio-icon /pulseaudio /pulseaudio
RUN bsdtar -acf /pulseaudio.zip -C / pulseaudio
FROM inno AS build-pasetup
COPY --from=build-pulseaudio /pulseaudio /pulseaudio
# TODO: make a wrapper so it can run as a proper service with reduced permissions, maybe connect with a unix socket by default on recent win10 versions
RUN echo -en '\
[Setup] \n\
AppName=PulseAudio \n\
AppVersion=14.0 \n\
UninstallDisplayName=PulseAudio \n\
AppPublisher=freedesktop.org \n\
AppPublisherURL=https://www.freedesktop.org \n\
AppSupportURL=https://www.freedesktop.org/software/pulseaudio \n\
DefaultDirName={autopf}\PulseAudio \n\
DisableDirPage=yes \n\
DisableProgramGroupPage=yes \n\
DisableReadyPage=yes \n\
MinVersion=6.1sp1 \n\
OutputBaseFilename=pasetup \n\
PrivilegesRequired=admin \n\
WizardStyle=classic \n\
Uninstallable=IsComponentSelected('"'"'uninstall'"'"') \n\
UninstallDisplayIcon={app}\pulseaudio.exe \n\
SourceDir=pulseaudio \n\
OutputDir=.. \n\
\n\
[Types] \n\
Name: "full"; Description: "Full installation" \n\
Name: "minimal"; Description: "Minimal installation" \n\
Name: "custom"; Description: "Custom installation"; Flags: iscustom \n\
\n\
[Components] \n\
Name: "pulseaudio"; Description: "PulseAudio"; Types: full minimal custom; Flags: fixed \n\
Name: "service"; Description: "System service"; Types: full \n\
Name: "uninstall"; Description: "Uninstall support"; Types: full minimal custom \n\
\n\
[Files] \n\
Source: "*"; DestDir: "{app}"; Flags: recursesubdirs \n\
\n\
[Run] \n\
Filename: "{sys}\\schtasks.exe"; Parameters: "/End /TN PulseAudio"; StatusMsg: "Stopping service if running"; Flags: runhidden; Components: service \n\
Filename: "{sys}\\taskkill.exe"; Parameters: "/F /IM pulseaudio.exe"; StatusMsg: "Stopping process if running"; Flags: runhidden; Components: service \n\
Filename: "{sys}\\schtasks.exe"; Parameters: "/Delete /TN PulseAudio /F"; StatusMsg: "Deleting service if exists"; Flags: runhidden; Components: service \n\
Filename: "{sys}\\schtasks.exe"; Parameters: "/Create /TN PulseAudio /RU ""NT AUTHORITY\SYSTEM"" /SC ONSTART /TR ""\\""{app}\pulseaudio.exe\\"" \\""--disallow-exit\\"" \\""--exit-idle-time=-1\\"" \\""--load=module-native-protocol-tcp auth-anonymous=1\\"" \\""--load=module-waveout\\"" \\""--log-target=file:{app}\\pulseaudio.log\\"""" /F"; StatusMsg: "Registering service"; Flags: runhidden runascurrentuser; Components: service \n\
Filename: "{sys}\\schtasks.exe"; Parameters: "/Run /TN PulseAudio"; StatusMsg: "Starting service"; Flags: runhidden; Components: service \n\
Filename: "{sys}\\netsh.exe"; Parameters: "firewall set portopening protocol=TCP port=4713 name=PulseAudio mode=ENABLE"; StatusMsg: "Adding firewall exception for tcp/4713"; Flags: runhidden runascurrentuser; Components: service \n\
\n\
[UninstallDelete] \n\
Type: files; Name: "{app}\pulseaudio.log" \n\
\n\
[UninstallRun] \n\
Filename: "{sys}\\schtasks.exe"; Parameters: "/End /TN PulseAudio"; Flags: runhidden; Components: service \n\
Filename: "{sys}\\taskkill.exe"; Parameters: "/F /IM pulseaudio.exe"; Flags: runhidden; Components: service \n\
Filename: "{sys}\\schtasks.exe"; Parameters: "/Delete /TN PulseAudio /F"; Flags: runhidden; Components: service \n\
Filename: "{sys}\\netsh.exe"; Parameters: "firewall delete portopening protocol=TCP port=4713"; Flags: runhidden runascurrentuser; Components: service \n\
\n\
[Code] \n\
function PrepareToInstall(var NeedsRestart: Boolean): String; \n\
var \n\
ResultCode: Integer; \n\
begin \n\
Exec(ExpandConstant('"'"'{sys}\\taskkill.exe'"'"'), '"'"'/F /IM pulseaudio.exe'"'"', '"'"''"'"', SW_HIDE, ewWaitUntilTerminated, ResultCode); \n\
end; \n\
\n\
' | sed -Ee 's/^(\t| )//g' -e 's/ ?$/\r/g' | tee /pasetup.iss
RUN iscc 'Z:\pasetup.iss'
FROM scratch AS final-tmp
COPY --from=build-pulseaudio /pulseaudio.zip /
COPY --from=build-pasetup /pasetup.exe /
FROM scratch AS final
COPY --from=final-tmp / /
# docker build . && docker save "$(docker build --quiet .)" | tar -xOf - --wildcards '*/layer.tar' | tar xf -
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment