Building Icons with GNU Make
Desktop icon formats are a mess. No platforms share formats - Windows uses .ico (and for various reasons so does the web), Mac OS X uses .icns, and desktop GNU/Linux doesn't even have an icon format, you just throw PNGs into the air and pray.
But let's say you are foolishly trying to write a cross-platform application, yet intelligently want to automate creating most of these from source data.
A reasonable "source data" for icons is a directory full of
PNGs.1 Apple uses a format called .iconset for this, with filenames
example.iconset/icon_64x64.png. Since it's just a directory of
images, it'll serve for making Windows/website icons as well, and
GNU/Linux build scripts can copy files out of it directly.
To convert this to the desired formats, you'll need GraphicsMagick, and either build on a Mac OS X system or install libicns.
Now for the Makefile:
ICONUTIL := $(word 1, $(shell command -v iconutil icnsutil) iconutil) .SECONDEXPANSION: %.icns: %.iconset $$(wildcard $$(@D)/$$*.iconset/icon_*.png) $(ICONUTIL) -c icns -o $@ $< .SECONDEXPANSION: %.ico: %.iconset $$(wildcard $$(@D)/$$*.iconset/icon_*[0-9].png) convert -background transparent -colors 256 $(filter-out $<,$^) $@
(You'll need to replace those spaces with tabs. Sorry. Complain here.)
This uses a couple unusual tricks.
ICONUTIL assignment figures out whether you've got the
iconutil from Mac OS X, or the compatible
libicns. If you don't have either, it picks
iconutil so you get a
Second, it uses GNU Make's secondary expansion feature. This specifies a wildcard dependent on the pattern and target name when generating the list of source names.
Third, it depends on the source directory. This is uncommon in
Makefiles because directories update when contained files are added or
deleted, not when files are modified. The modification case is covered
.SECONDEXPANSION trick but we also need to handle the
case where an icon size was removed, because the target files need to
be rebuilt without the removed file.
Finally, please note the slightly different glob patterns.
files support high-DPI ("Retina") icons using the format
icon_WxH@2.png - so
firstname.lastname@example.org is actually 32 pixels on each
.ico files, as far as I can determine, have no such feature;
they will use the 32x32 icon instead. So
@2x files should not
be included when building the
Assigning a .ico to a .exe
I've not found a good cross-platform tool for doing this.
GitHub's Atom project has produced a Windows tool called rcedit (compiled binary here) which does nothing but poke icons and version numbers into Windows executables. Because it is so minimal it runs perfectly in Wine, and it has an MIT-style license.
wine rcedit.exe --set-icon example.ico example.exe
Assigning a .icns to a .app
Mac OS X
.app files are directories. The usual place to put an
icon would be
Contents/Resources/Icon.icns, and you may simply need to
copy it over the file already there.
If you're building the package from scratch, you'll need to create the Info.plist file referencing the icon in the first place. This can be done on any platform with Python's plistlib.
Another reasonable source format is one or multiple SVGs. Turning an SVG into a directory of PNGs is left as an exercise for the reader. ↩