https://flaky.build/creating-wrappers-for-windows-exe-files-using-homebrew-and-wine
[favicon]Flaky Build
About
[]Creating wrappers for Windows exe files using Homebrew and Wine
Creating wrappers for Windows exe files using Homebrew and Wine
Creating wrappers for Windows exe files using Homebrew and Wine
Tags
MacOS
OSS
Software Development
Published
August 22, 2024
Author
Introduction to the Windows software I needed: FORScan
I recently noticed that my 2013 Ford Transit mk7 van doesn't have
great observability to debug what went wrong and it just shows ENGINE
MALFUNCTION text in the small screen instead of actually providing
helpful error messages. This message is pretty scary, but my car
seemed to move forward so I thought it's mainly to get more money for
the Ford service shops.
[]ENGINE MALFUNCTION warning on the Ford Transit mk7 display and
yellow light for stability control system.ENGINE MALFUNCTION warning
on the Ford Transit mk7 display and yellow light for stability
control system.ENGINE MALFUNCTION warning on the Ford Transit mk7
display and yellow light for stability control system.
I had learned that it's pretty easy to diagnose these errors by
installing FORScan for my machine and finding compatible OBD2 cable.
The only problem was that FORScan only works with Windows machines
and I only had Macbook available.
Figuring out how to run FORScan on MacOS
I spend sometime googling how I could get FORScan working on my
Macbook and stumbled upon this great discussion in miata.net car
enthusiastics. I learned that I would need to:
1. Install Wine through Homebrew
2. Find proper device drivers for my USB OBD2 cable
3. Symlinking the connected USB serial devices to Wine COM ports
I followed their great instructions and was able to get FORScan
working but this seemed very tedious way to set it up and I wondered
if all of this could be automated somehow with Homebrew so that it
would be easier to setup next time for the benefit of myself and
others.
[]Connecting my vLinker FS OBD2 USB diagnostics cable to Ford Transit
was easy.Connecting my vLinker FS OBD2 USB diagnostics cable to Ford
Transit was easy.Connecting my vLinker FS OBD2 USB diagnostics cable
to Ford Transit was easy.
[]After installing drivers, connecting the cables, editing Windows
regedit and symlinking the devices to Wine I was able to get FORScan
to read my car diagnostics. One pipe in the turbo was leaking and
after that was replaced the problem went away.After installing
drivers, connecting the cables, editing Windows regedit and
symlinking the devices to Wine I was able to get FORScan to read my
car diagnostics. One pipe in the turbo was leaking and after that was
replaced the problem went away.After installing drivers, connecting
the cables, editing Windows regedit and symlinking the devices to
Wine I was able to get FORScan to read my car diagnostics. One pipe
in the turbo was leaking and after that was replaced the problem went
away.
Automating FORScan installation steps with Homebrew
I had noticed that Homebrew supports custom taps. Taps are basically
3rd party packages which anyone can create and host in their public
github repository called homebrew-tap.
Everything tap related is very well documented by Homebrew: https://
docs.brew.sh/Formula-Cookbook.
In order to create a new tap you need to create a git repository
called homebrew-tap with folder Casks
# Create new homebrew tap which will host your casks formulaes
YOUR_GITHUB_USERNAME="onnimonni" # change this to your username!
brew tap-new $YOUR_GITHUB_USERNAME/homebrew-tap
# Change directory to the newly created tap. You can see this from the output of the earlier command
cd /opt/homebrew/Library/Taps/$YOUR_GITHUB_USERNAME/homebrew-tap
Next I needed to find the URL for the installer. This was easy to do
by just right-clicking the installer link and using Copy Link Address
feature in Chrome. In my case the installer link was:
https://FORScan.org/download/FORScanSetup2.3.62.release.exe
[]notion imagenotion image
With the link to the installer I was able create a new cask for
Homebrew using their template:
brew create --tap $YOUR_GITHUB_USERNAME/homebrew-tap \
--set-name FORScan \
--cask "https://FORScan.org/download/FORScanSetup2.3.62.release.exe"
This opens your code editor and automatically fills up the the name
and is able to figure out the version and the checksum automatically:
# Documentation: https://docs.brew.sh/Cask-Cookbook
# https://docs.brew.sh/Adding-Software-to-Homebrew#cask-stanzas
# PLEASE REMOVE ALL GENERATED COMMENTS BEFORE SUBMITTING YOUR PULL REQUEST!
cask "FORScanni" do
version "2.3.62"
sha256 "fad11dd5f91a86961b2435798eeae8241dd3a69c92808f5b9eedfe35eac2a77c"
url "https://FORScan.org/download/FORScanSetup#{version}.release.exe"
name "FORScanni"
desc ""
homepage ""
# Documentation: https://docs.brew.sh/Brew-Livecheck
livecheck do
url ""
strategy ""
end
depends_on macos: ""
app ""
# Documentation: https://docs.brew.sh/Cask-Cookbook#stanza-zap
zap trash: ""
end
Well this is nice. Next I added proper values for desc and homepage.
I also added auto_updates false line into the formula to tell
homebrew that this software can't automatically update itself. If
you're unsure please check guidance from Homebrew docs.
Automatically updating Casks by adding livecheck block
livecheck is needed if you want to be able to easily update the
version with Homebrew. I needed to use a bit time to figure this out
but FORScan change history page provides links to all versions https:
//FORScan.org/changes_history.html and I noticed that all download
links follow this pattern download/FORScanSetup.
Searching examples with Github code search helped me to figure out
how to use regex properly here:
livecheck do
url "https://FORScan.org/changes_history.html"
regex(%r{href=.*download/FORScanSetup(\d+(?:\.\d+)+)\.release\.exe})
end
Adding other casks as dependencies to your cask
Next I needed to add additional dependencies which we will need in
order to get my software running. If your windows software will not
need USB serial devices you should not need anything else than
wine-stable.
# Since FORScan is made for Windows we need to install Wine to run it
depends_on cask: "wine-stable"
# Virtual COM Drivers which work for vLinker FS USB OBD2 reader
# They also should work for the OBDLink EX which is the other recommended cable
# These are needed for the MacOS host machine to detect the OBD2 reader
depends_on cask: "ftdi-vcp-driver"
Running the downloaded Windows installer
Remember that Windows software typically doesn't look like the
self-contained Application.app containers we have on MacOS? With
Windows you will download a installer which will then create a
shortcut to desktop and add the software to your C:/Program Files
(x86)/FORScan/FORScan.exe. We have now only told the Homebrew to
download this installer.
We can run the installer manually by locating it and running that
with Wine:
wine FORScanSetup2.3.62.release.exe
But this doesn't look very automatic and doesn't happen in the
background. You can ask for Windows installer flags by providing /
help as the third parameter:
wine FORScanSetup2.3.62.release.exe /help
Running this command will open a new long window containing all of
the different installer options. I thought that I will not want to
change the default installation path but I just want it to use
defaults and run in the background. By adding following flags I was
able to do that:
wine FORScanSetup2.3.62.release.exe /SP- /VERYSILENT
This will run the installer for us and adds the FORScan program files
into $HOME/.wine/drive_c/Program Files (x86)/FORScan/FORScan.exe. We
can now add a Homebrew installer keyword into our formula. See how I
used the staged_path and version variables provided by Homebrew.
# Runs the FORScan Windows installer
installer script: {
executable: "wine",
args: [
"#{staged_path}/FORScanSetup#{version}.release.exe",
# Windows EXE installer options here:
# Run the FORScan without user input
"/SP-",
"/VERYSILENT",
# Default installation path is C:/Program Files (x86)/FORScan/
],
}
Creating a artificial .app folder to actually launch FORScan
Currently Homebrew can download and run the Windows Installer but we
don't yet have a nice FORScan.app in our Applications folder.
We will need to create a minimal .app structure to actually launch
the FORScan. It will not be self-contained and portable to other
systems but we don't care about that. We will need to create a
executable into FORScan.app/Contents/MacOS/FORScan and a project
metadata file into FORScan.app/Contents/Resources/Info.plist. The end
result will look like this:
$ tree FORScan.app/
FORScan.app/
+-- Contents
+-- MacOS
| +-- FORScan
+-- Resources
+-- Info.plist
We will abuse next Homebrew keyword preflight to create that but
before that add a name for the .app folder which Homebrew will look
for into your formula:
app "FORScan.app"
This will also tell Homebrew to move this folder to your
Applications. Next let's create it in the preflight phase of the
cask.
# This very tiny bash script will be our installer
forscan_launcher_content = <<~EOS
#!/usr/bin/env bash
# Open the FORScan application itself through Wine
open -a 'Wine Stable' "$HOME/.wine/drive_c/Program Files (x86)/FORScan/FORScan.exe"
EOS
# We need to add a PLIST file to tell MacOS about our application.
# I'm not sure if this was actually needed in the end
# Source: https://www.artembutusov.com/how-to-wrap-wine-applications-into-macos-x-application-bundle/
forscan_plist_content = <<~EOS
CFBundleExecutable
FORScan
CFBundleGetInfoString
FORScan
CFBundleIconFile
AppIcon
CFBundleIconName
AppIcon
CFBundleName
FORScan
CFBundlePackageType
APPL
CFBundleSignature
4242
NSHighResolutionCapable
EOS
# Create the Forscan.app folder structure and necessary files
preflight do
FileUtils.mkdir_p "#{staged_path}/FORScan.app/Contents/MacOS"
File.write "#{staged_path}/FORScan.app/Contents/MacOS/FORScan", forscan_launcher_content
FileUtils.chmod 0755, "#{staged_path}/FORScan.app/Contents/MacOS/FORScan"
FileUtils.mkdir_p "#{staged_path}/FORScan.app/Contents/Resources/image.iconset"
File.write "#{staged_path}/FORScan.app/Contents/Resources/Info.plist", forscan_plist_content
end
Then you are done and should be able to use your Windows software
through wine. If you want your users to be able to cleanup the
installation you could add uninstall keyword as well into your Cask
formula:
uninstall delete: [
"~/.wine/drive_c/Program Files (x86)/FORScan",
"~/.wine/drive_c/ProgramData/Microsoft/Windows/Start Menu/Programs/FORScan",
]
After these changes the complete file should look like something like
this:
cask "forscan" do
version "2.3.62"
sha256 "fad11dd5f91a86961b2435798eeae8241dd3a69c92808f5b9eedfe35eac2a77c"
url "https://forscan.org/download/FORScanSetup#{version}.release.exe"
name "FORScan"
desc "Software scanner for Ford, Mazda, Lincoln and Mercury vehicles"
homepage "https://forscan.org/home.html"
livecheck do
url "https://FORScan.org/changes_history.html"
regex(%r{href=.*download/FORScanSetup(\d+(?:\.\d+)+)\.release\.exe})
end
# Since FORScan is made for Windows we need to install Wine to run it
depends_on cask: "wine-stable"
# Virtual COM Drivers which work for vLinker FS USB OBD2 reader
# They also should work for the OBDLink EX which is the other recommended cable
# These are needed for the MacOS host machine to detect the OBD2 reader
depends_on cask: "ftdi-vcp-driver"
app "FORScan.app"
# This very tiny bash script will be our installer
forscan_launcher_content = <<~EOS
#!/usr/bin/env bash
# Open the FORScan application itself through Wine
open -a 'Wine Stable' "$HOME/.wine/drive_c/Program Files (x86)/FORScan/FORScan.exe"
EOS
# We need to add a PLIST file to tell MacOS about our application.
# I'm not sure if this was actually needed in the end
# Source: https://www.artembutusov.com/how-to-wrap-wine-applications-into-macos-x-application-bundle/
forscan_plist_content = <<~EOS
CFBundleExecutable
FORScan
CFBundleGetInfoString
FORScan
CFBundleIconFile
AppIcon
CFBundleIconName
AppIcon
CFBundleName
FORScan
CFBundlePackageType
APPL
CFBundleSignature
4242
NSHighResolutionCapable
EOS
# Create the Forscan.app folder structure and necessary files
preflight do
FileUtils.mkdir_p "#{staged_path}/FORScan.app/Contents/MacOS"
File.write "#{staged_path}/FORScan.app/Contents/MacOS/FORScan", forscan_launcher_content
FileUtils.chmod 0755, "#{staged_path}/FORScan.app/Contents/MacOS/FORScan"
FileUtils.mkdir_p "#{staged_path}/FORScan.app/Contents/Resources/image.iconset"
File.write "#{staged_path}/FORScan.app/Contents/Resources/Info.plist", forscan_plist_content
end
uninstall delete: [
"~/.wine/drive_c/Program Files (x86)/FORScan",
"~/.wine/drive_c/ProgramData/Microsoft/Windows/Start Menu/Programs/FORScan",
]
end
Then just commit your changes and push them to your public Github
repository:
cd /opt/homebrew/Library/Taps/$YOUR_GITHUB_USERNAME/homebrew-tap
git add .
git commit -am "Created FORScan Cask installer to use Windows software on MacOS"
git push origin HEAD
After this your Windows software can be installed by running:
brew install --no-quarantine --cask wine-stable $YOUR_GITHUB_USERNAME/tap/forscan
Because the installer of our Cask formula depends on the wine being
available in the system we need to give that as the first package to
be installed before our custom tap can be used. I hope this was
useful for you and will help you to run Windows software on your Mac
with ease.
Extras: Automating complicated setup and dependencies
Because FORScan needs to use the USB serial device attached to the
host machine these need to be symlinked to virtual Wine COM devices I
needed to add a lot of extra ducktape and glue to make that
experience easy for the users of my tap. I replaced the bash based
launcher with Applescript which takes care that the necessary system
extensions will be installed and the USB devices are connected and
symlinked properly before actually opening the FORScan. There's also
some Windows regedit changes needed before Wine can see the USB
devices.
If you're curious you can check the complete Cask formulae I created
in my own tap: https://github.com/onnimonni/homebrew-tap/blob/main/
Casks/forscan.rb
It was a pretty fun experiment of how one can open programs and click
their buttons automatically for the user. Now I don't need to
remember how to make this complicated setup manually anymore. It was
a pretty complicated and time consuming journey but hopefully this
will allow others to achieve same results easily in the future .
Table of Contents
Introduction to the Windows software I needed: FORScanFiguring out
how to run FORScan on MacOSAutomating FORScan installation steps with
HomebrewAutomatically updating Casks by adding livecheck blockAdding
other casks as dependencies to your caskRunning the downloaded
Windows installerCreating a artificial .app folder to actually launch
FORScanExtras: Automating complicated setup and dependencies
[favicon]Flaky Build
Terms and ConditionsPrivacy PolicyAffiliate DisclosureSecurity Policy
(c) Copyright 2025. All rights reserved.