1# pqiv Makefile
2#
3
4# Default flags, overridden by values in config.make
5CFLAGS?=-O2 -g
6CROSS=
7DESTDIR=
8GTK_VERSION=0
9PQIV_WARNING_FLAGS=-Wall -Wextra -Wfloat-equal -Wpointer-arith -Wcast-align -Wstrict-overflow=1 -Wwrite-strings -Waggregate-return -Wunreachable-code -Wno-unused-parameter
10LDLIBS=-lm
11PREFIX=/usr
12EPREFIX=$(PREFIX)
13LIBDIR=$(PREFIX)/lib
14BINDIR=$(PREFIX)/bin
15MANDIR=$(PREFIX)/share/man
16EXECUTABLE_EXTENSION=
17PKG_CONFIG=$(CROSS)pkg-config
18OBJECTS=pqiv.o lib/strnatcmp.o lib/bostree.o lib/filebuffer.o lib/config_parser.o lib/thumbnailcache.o
19HEADERS=pqiv.h lib/bostree.h lib/filebuffer.h lib/strnatcmp.h
20BACKENDS=gdkpixbuf
21EXTRA_DEFS=
22BACKENDS_BUILD=static
23EXTRA_CFLAGS_SHARED_OBJECTS=-fPIC
24EXTRA_CFLAGS_BINARY=
25EXTRA_LDFLAGS_SHARED_OBJECTS=
26EXTRA_LDFLAGS_BINARY=
27
28# Always look for source code relative to the directory of this makefile
29SOURCEDIR:=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))
30ifeq ($(SOURCEDIR),$(CURDIR))
31	SOURCEDIR=
32else
33	HEADERS:=$(patsubst %, $(SOURCEDIR)%, $(HEADERS))
34endif
35
36# Load config.make (created by configure)
37CONFIG_MAKE_NAME=config.make
38ifeq ($(wildcard $(CONFIG_MAKE_NAME)),$(CONFIG_MAKE_NAME))
39	include $(CONFIG_MAKE_NAME)
40	HEADERS+=$(CONFIG_MAKE_NAME)
41endif
42
43# First things first: Require at least one backend
44ifeq ($(BACKENDS),)
45$(error Building pqiv without any backends is unsupported.)
46endif
47
48# pkg-config lines for the main program
49LIBS_GENERAL=glib-2.0 >= 2.8 cairo >= 1.6 gio-2.0
50LIBS_GTK3=gtk+-3.0 gdk-3.0
51LIBS_GTK2=gtk+-2.0 >= 2.6 gdk-2.0 >= 2.8
52
53# pkg-config libraries for the backends
54LIBS_gdkpixbuf=gdk-pixbuf-2.0 >= 2.2
55LIBS_poppler=poppler-glib
56LIBS_spectre=libspectre
57LIBS_wand=MagickWand
58LIBS_libav=libavformat libavcodec libswscale libavutil
59LIBS_archive_cbx=libarchive gdk-pixbuf-2.0 >= 2.2
60LIBS_archive=libarchive
61LIBS_webp=libwebp
62
63# This might be required if you use mingw, and is required as of
64# Aug 2014 for mxe, but IMHO shouldn't be required / is a bug in
65# poppler (which does not specify this dependency). If it isn't
66# or throws an error for you, please report this as a bug:
67#
68ifeq ($(EXECUTABLE_EXTENSION),.exe)
69   LDLIBS_poppler+=-llcms2 -lstdc++
70endif
71
72# If no GTK_VERSION is set, try to auto-determine, with GTK 3 preferred
73ifeq ($(GTK_VERSION), 0)
74	ifeq ($(shell $(PKG_CONFIG) --errors-to-stdout --print-errors "$(LIBS_GTK3)"), )
75		override GTK_VERSION=3
76	else
77		LIBS=$(LIBS_GTK2)
78		override GTK_VERSION=2
79	endif
80endif
81ifeq ($(GTK_VERSION), 2)
82	LIBS=$(LIBS_GTK2)
83endif
84ifeq ($(GTK_VERSION), 3)
85	LIBS=$(LIBS_GTK3)
86endif
87LIBS+=$(LIBS_GENERAL)
88
89# Add platform specific libraries
90# GIo for stdin loading,
91ifeq ($(EXECUTABLE_EXTENSION), .exe)
92	LIBS+=gio-windows-2.0
93else
94	LIBS+=gio-unix-2.0
95endif
96
97# We need X11 to workaround a bug, see http://stackoverflow.com/questions/18647475
98ifeq ($(filter x11, $(shell $(PKG_CONFIG) --errors-to-stdout --variable=target gtk+-$(GTK_VERSION).0; $(PKG_CONFIG) --errors-to-stdout --variable=targets gtk+-$(GTK_VERSION).0)), x11)
99	LIBS+=x11
100endif
101
102# Add backend-specific libraries and objects
103SHARED_OBJECTS=
104SHARED_BACKENDS=
105HELPER_OBJECTS=
106BACKENDS_INITIALIZER:=backends/initializer
107define handle-backend
108ifneq ($(origin LIBS_$(1)),undefined)
109	ifneq ($(findstring $(1), $(BACKENDS)),)
110		ifeq ($(BACKENDS_BUILD), shared)
111			ifeq ($(shell $(PKG_CONFIG) --errors-to-stdout --print-errors "$(LIBS_$(1))" 2>&1), )
112				SHARED_OBJECTS+=backends/pqiv-backend-$(1).so
113				HELPER_OBJECTS+=backends/$(1).o
114				BACKENDS_BUILD_CFLAGS_$(1):=$(shell $(PKG_CONFIG) --errors-to-stdout --print-errors --cflags "$(LIBS_$(1))" 2>&1)
115				BACKENDS_BUILD_LDLIBS_$(1):=$(shell $(PKG_CONFIG) --errors-to-stdout --print-errors --libs "$(LIBS_$(1))" 2>&1)
116				SHARED_BACKENDS+="$(1)",
117			endif
118		else
119			LIBS+=$(LIBS_$(1))
120			OBJECTS+=backends/$(1).o
121			LDLIBS+=$(LDLIBS_$(1))
122			BACKENDS_INITIALIZER:=$(BACKENDS_INITIALIZER)-$(1)
123		endif
124	endif
125endif
126endef
127$(foreach BACKEND_C, $(wildcard $(SOURCEDIR)backends/*.c), $(eval $(call handle-backend,$(basename $(notdir $(BACKEND_C))))))
128PIXBUF_FILTER="gdkpixbuf",
129ifeq ($(BACKENDS_BUILD), shared)
130	OBJECTS+=backends/shared-initializer.o
131	BACKENDS_BUILD_CFLAGS_shared-initializer=-DSHARED_BACKENDS='$(filter $(PIXBUF_FILTER), $(SHARED_BACKENDS)) $(filter-out $(PIXBUF_FILTER), $(SHARED_BACKENDS))' -DSEARCH_PATHS='"backends", "../$(subst $(PREFIX),,$(LIBDIR))/pqiv", "$(LIBDIR)/pqiv",'
132	LIBS+=gmodule-2.0
133else
134	OBJECTS+=$(BACKENDS_INITIALIZER).o
135endif
136
137# MagickWand changed their directory structure with version 7, pass the version
138# to the build
139ifneq ($(findstring wand, $(BACKENDS)),)
140backends/wand.o: CFLAGS_REAL+=-DWAND_VERSION=$(shell $(PKG_CONFIG) --modversion MagickWand | awk 'BEGIN { FS="." } { print $$1 }')
141endif
142
143# Add version information to builds from git
144PQIV_VERSION_STRING=$(shell [ -d $(SOURCEDIR).git ] && (which git 2>&1 >/dev/null) && git -C "$(SOURCEDIR)" describe --dirty --tags 2>/dev/null)
145ifneq ($(PQIV_VERSION_STRING),)
146	PQIV_VERSION_FLAG=-DPQIV_VERSION=\"$(PQIV_VERSION_STRING)\"
147endif
148ifdef DEBUG
149	DEBUG_CFLAGS=-DDEBUG
150else
151	DEBUG_CFLAGS=-DNDEBUG
152endif
153
154# Less verbose output
155ifndef VERBOSE
156	SILENT_CC=@echo   " CC  " $@;
157	SILENT_CCLD=@echo " CCLD" $@;
158	SILENT_GEN=@echo  " GEN " $@;
159endif
160
161# Assemble final compiler flags
162CFLAGS_REAL=-std=gnu99 $(PQIV_WARNING_FLAGS) $(PQIV_VERSION_FLAG) $(CFLAGS) $(DEBUG_CFLAGS) $(EXTRA_DEFS) $(shell $(PKG_CONFIG) --cflags "$(LIBS)")
163LDLIBS_REAL=$(shell $(PKG_CONFIG) --libs "$(LIBS)") $(LDLIBS)
164LDFLAGS_REAL=$(LDFLAGS)
165
166all: pqiv$(EXECUTABLE_EXTENSION) pqiv.desktop $(SHARED_OBJECTS)
167.PHONY: get_libs get_available_backends _build_variables clean distclean install uninstall all
168.SECONDARY:
169
170pqiv$(EXECUTABLE_EXTENSION): $(OBJECTS)
171	$(SILENT_CCLD) $(CROSS)$(CC) $(CPPFLAGS) $(EXTRA_CFLAGS_BINARY) -o $@ $+ $(LDLIBS_REAL) $(LDFLAGS_REAL) $(EXTRA_LDFLAGS_BINARY)
172
173ifeq ($(BACKENDS_BUILD), shared)
174backends/%.o: CFLAGS_REAL+=$(BACKENDS_BUILD_CFLAGS_$(notdir $*)) $(EXTRA_CFLAGS_SHARED_OBJECTS)
175
176$(SHARED_OBJECTS): backends/pqiv-backend-%.so: backends/%.o
177	@[ -d backends ] || mkdir -p backends || true
178	$(SILENT_CCLD) $(CROSS)$(CC) $(CPPFLAGS) $(EXTRA_CFLAGS_SHARED_OBJECTS) -o $@ $+ $(LDLIBS_REAL) $(LDFLAGS_REAL) $(BACKENDS_BUILD_LDLIBS_$*) $(EXTRA_LDFLAGS_SHARED_OBJECTS) -shared
179endif
180
181$(filter-out $(BACKENDS_INITIALIZER).o, $(OBJECTS)) $(HELPER_OBJECTS): %.o: $(SOURCEDIR)%.c $(HEADERS)
182	@[ -d $(dir $@) ] || mkdir -p $(dir $@) || true
183	$(SILENT_CC) $(CROSS)$(CC) $(CPPFLAGS) -c -o $@ $(CFLAGS_REAL) $<
184
185$(BACKENDS_INITIALIZER).o: $(BACKENDS_INITIALIZER).c $(HEADERS)
186	@[ -d $(dir $@) ] || mkdir -p $(dir $@) || true
187	$(SILENT_CC) $(CROSS)$(CC) $(CPPFLAGS) -I"$(SOURCEDIR)/lib" -c -o $@ $(CFLAGS_REAL) $<
188
189$(BACKENDS_INITIALIZER).c:
190	@[ -d $(dir $(BACKENDS_INITIALIZER)) ] || mkdir -p $(dir $(BACKENDS_INITIALIZER)) || true
191	@$(foreach BACKEND, $(sort $(BACKENDS)), [ -e $(SOURCEDIR)backends/$(BACKEND).c ] || { echo; echo "Backend $(BACKEND) not found!" >&2; exit 1; };)
192	$(SILENT_GEN) ( \
193		echo '/* Auto-Generated file by Make. */'; \
194		echo '#include "../pqiv.h"'; \
195		echo "file_type_handler_t file_type_handlers[$(words $(BACKENDS)) + 1];"; \
196		$(foreach BACKEND, $(sort $(BACKENDS)), echo "void file_type_$(BACKEND)_initializer(file_type_handler_t *info);";) \
197		echo "void initialize_file_type_handlers(const gchar * const * disabled_backends) {"; \
198		echo "	int i = 0;"; \
199		$(foreach BACKEND, $(filter gdkpixbuf, $(BACKENDS)), echo "	if(!strv_contains(disabled_backends, \"$(BACKEND)\")) file_type_$(BACKEND)_initializer(&file_type_handlers[i++]);";) \
200		$(foreach BACKEND, $(sort $(filter-out gdkpixbuf, $(BACKENDS))), echo "	if(!strv_contains(disabled_backends, \"$(BACKEND)\")) file_type_$(BACKEND)_initializer(&file_type_handlers[i++]);";) \
201		echo "}" \
202	) > $@
203
204pqiv.desktop: $(HEADERS)
205	$(SILENT_GEN) ( \
206		echo "[Desktop Entry]"; \
207		echo "Version=1.0"; \
208		echo "Type=Application"; \
209		echo "Comment=Powerful quick image viewer"; \
210		echo "Name=pqiv"; \
211		echo "NoDisplay=true"; \
212		echo "Icon=emblem-photos"; \
213		echo "TryExec=$(PREFIX)/bin/pqiv"; \
214		echo "Exec=$(PREFIX)/bin/pqiv %F"; \
215		echo "MimeType=$(shell cat $(foreach BACKEND, $(sort $(BACKENDS)), $(SOURCEDIR)backends/$(BACKEND).mime) /dev/null | sort | uniq | awk 'ORS=";"')"; \
216		echo "Categories=Graphics;"; \
217		echo "Keywords=Viewer;" \
218	) > $@
219
220install: all
221	mkdir -p $(DESTDIR)$(BINDIR)
222	install pqiv$(EXECUTABLE_EXTENSION) $(DESTDIR)$(BINDIR)/pqiv$(EXECUTABLE_EXTENSION)
223	-mkdir -p $(DESTDIR)$(MANDIR)/man1
224	-install -m 644 $(SOURCEDIR)pqiv.1 $(DESTDIR)$(MANDIR)/man1/pqiv.1
225	-mkdir -p $(DESTDIR)$(PREFIX)/share/applications
226	-install -m 644 pqiv.desktop $(DESTDIR)$(PREFIX)/share/applications/pqiv.desktop
227ifeq ($(BACKENDS_BUILD), shared)
228	mkdir -p $(DESTDIR)$(LIBDIR)/pqiv
229	install $(SHARED_OBJECTS) $(DESTDIR)$(LIBDIR)/pqiv/
230endif
231
232uninstall:
233	rm -f $(DESTDIR)$(PREFIX)/bin/pqiv$(EXECUTABLE_EXTENSION)
234	rm -f $(DESTDIR)$(MANDIR)/man1/pqiv.1
235	rm -f $(DESTDIR)$(PREFIX)/share/applications/pqiv.desktop
236ifeq ($(BACKENDS_BUILD), shared)
237	rm -f $(foreach SO_FILE, $(SHARED_OBJECTS), $(DESTDIR)$(LIBDIR)/pqiv/$(notdir $(SO_FILE)))
238	rmdir $(DESTDIR)$(LIBDIR)/pqiv
239endif
240
241# Rudimentary MacOS bundling
242# Only really useful for opening pqiv using "open pqiv.app --args ..." from the
243# command line right now, but that already has the benefit that the application
244# window will be visible right away
245pqiv.app: pqiv.app.tmp
246	rm -f ../$@
247	cd pqiv.app.tmp && zip -9r ../$@ .
248
249pqiv.app.tmp: pqiv.app.tmp/Contents/MacOS/pqiv pqiv.app.tmp/Contents/Info.plist pqiv.app.tmp/Contents/PkgInfo
250
251pqiv.app.tmp/Contents/MacOS/pqiv:
252	-mkdir -p pqiv.app.tmp/Contents/MacOS
253	install pqiv$(EXECUTABLE_EXTENSION) $@
254
255pqiv.app.tmp/Contents/PkgInfo:
256	-mkdir -p pqiv.app.tmp/Contents
257	$(SILENT_GEN) ( \
258		echo -n "APPL????"; \
259	) > $@
260
261pqiv.app.tmp/Contents/Info.plist: $(HEADERS)
262	-mkdir -p pqiv.app.tmp/Contents
263	$(SILENT_GEN) ( \
264		echo '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'; \
265		echo '<plist version="1.0"><dict><key>CFBundleName</key><string>pqiv</string><key>CFBundleDisplayName</key><string>pqiv</string>'; \
266		echo '<key>CFBundleIdentifier</key><string>com.pberndt.pqiv</string><key>CFBundleVersion</key><string>$(PQIV_VERSION_STRING)</string>'; \
267		echo '<key>CFBundlePackageType</key><string>APPL</string><key>CFBundleExecutable</key><string>pqiv</string><key>LSMinimumSystemVersion</key>'; \
268		echo '<string>10.4</string><key>CFBundleDocumentTypes</key><array><dict><key>CFBundleTypeMIMETypes</key><array>'; \
269		cat $(foreach BACKEND, $(sort $(BACKENDS)), $(SOURCEDIR)backends/$(BACKEND).mime) /dev/null | sort | uniq | awk '{print "<string>" $$0 "</string>"}'; \
270		echo '</array></dict></array></dict></plist>'; \
271	) > $@
272
273clean:
274	rm -f pqiv$(EXECUTABLE_EXTENSION) *.o backends/*.o backends/*.so lib/*.o backends/initializer-*.c pqiv.desktop
275
276distclean: clean
277	rm -f config.make
278
279get_libs:
280	$(info LIBS: $(LIBS))
281	@true
282
283get_available_backends:
284	@OUT=; $(foreach BACKEND_C, $(wildcard $(SOURCEDIR)backends/*.c), \
285		[ "$(DISABLE_AUTOMATED_BUILD_$(basename $(notdir $(BACKEND_C))))" != "yes" ] && \
286		[ -n "$(LIBS_$(basename $(notdir $(BACKEND_C))))" ] && \
287		$(PKG_CONFIG) --exists "$(LIBS_$(basename $(notdir $(BACKEND_C))))" \
288		&& OUT="$$OUT $(basename $(notdir $(BACKEND_C))) ";) echo BACKENDS: $$OUT
289	@true
290