all : # ====== VERSIONS ====== ADVANCECOMP_VER := 2.1 GIFSICLE_VER := 1.92 JHEAD_VER := 3.04 JPEGARCHIVE_VER := 2.2.0 JPEGOPTIM_VER := 1.4.6 LIBJPEG_VER := 9d LIBMOZJPEG_VER := 4.0.3 LIBPNG_VER := 1.6.37 LIBZ_VER := 1.2.11 OPTIPNG_VER := 0.7.7 PNGCRUSH_VER := 1.8.13 PNGQUANT_VER := 2.15.0 # ====== CHECKSUMS ====== include checksums.mk # ====== CONSTANTS ====== OS := $(shell uname -s | tr A-Z a-z) ARCH := $(shell uname -m) IS_DARWIN := $(findstring darwin,$(OS)) IS_LINUX := $(findstring linux,$(OS)) IS_BSD := $(findstring bsd,$(OS)) IS_FREEBSD := $(findstring freebsd,$(OS)) IS_OPENBSD := $(findstring openbsd,$(OS)) DLEXT := $(if $(IS_DARWIN),.dylib,.so) HOST := $(ARCH)-$(if $(IS_DARWIN),apple,pc)-$(OS) DL_DIR := $(CURDIR)/download BUILD_ROOT_DIR := $(CURDIR)/build BUILD_DIR := $(BUILD_ROOT_DIR)/$(OS)-$(ARCH) OUTPUT_ROOT_DIR := $(CURDIR)/vendor OUTPUT_DIR := $(OUTPUT_ROOT_DIR)/$(OS)-$(ARCH) $(shell mkdir -p $(DL_DIR) $(BUILD_DIR) $(OUTPUT_DIR)) ANSI_RED=\033[31m ANSI_GREEN=\033[32m ANSI_MAGENTA=\033[35m ANSI_RESET=\033[0m # ====== HELPERS ====== downcase = $(shell echo $1 | tr A-Z a-z) ln_s := ln -sf tar := $(shell if command -v gtar >/dev/null 2>&1; then echo gtar; else echo tar; fi) sha256sum := $(shell if command -v sha256sum >/dev/null 2>&1; then echo sha256sum; elif command -v shasum >/dev/null 2>&1; then echo shasum -a 256; else echo sha256; fi) # ====== ARCHIVES ====== ARCHIVES := # $1 - name of archive define archive ARCHIVES += $1 $1_DIR := $(BUILD_DIR)/$(call downcase,$1) $1_TGZ := $(DL_DIR)/$(call downcase,$1)-$($1_VER).tar.gz $1_EXTRACTED := $$($1_DIR)/__$$(notdir $$($1_TGZ))__ $$($1_EXTRACTED) : $$($1_TGZ) rm -rf $$(@D) echo "$$($1_SHA256) $$($1_TGZ)" | $(sha256sum) -c mkdir $$(@D) $(tar) -C $$(@D) --strip-components=1 -xzf $$< touch $$(@D)/__$$(notdir $$<)__ endef # $1 - name of archive # $2 - url of archive with [VER] for replace with version define archive-dl $(call archive,$1) # download archive from url $$($1_TGZ) : while ! mkdir $$@.lock 2> /dev/null; do sleep 1; done wget -q -O $$@.tmp $(subst [VER],$($1_VER),$(strip $2)) mv $$@.tmp $$@ rm -r $$@.lock endef $(eval $(call archive-dl,ADVANCECOMP, https://github.com/amadvance/advancecomp/releases/download/v[VER]/advancecomp-[VER].tar.gz)) $(eval $(call archive-dl,GIFSICLE, https://www.lcdf.org/gifsicle/gifsicle-[VER].tar.gz)) $(eval $(call archive-dl,JHEAD, https://www.sentex.ca/~mwandel/jhead/jhead-[VER].tar.gz)) $(eval $(call archive-dl,JPEGARCHIVE, https://github.com/danielgtaylor/jpeg-archive/archive/v[VER].tar.gz)) $(eval $(call archive-dl,JPEGOPTIM, https://www.kokkonen.net/tjko/src/jpegoptim-[VER].tar.gz)) $(eval $(call archive-dl,LIBJPEG, https://www.ijg.org/files/jpegsrc.v[VER].tar.gz)) $(eval $(call archive-dl,LIBMOZJPEG, https://github.com/mozilla/mozjpeg/archive/v[VER].tar.gz)) $(eval $(call archive-dl,LIBPNG, https://prdownloads.sourceforge.net/libpng/libpng-[VER].tar.gz?download)) $(eval $(call archive-dl,LIBZ, https://prdownloads.sourceforge.net/libpng/zlib-[VER].tar.gz?download)) $(eval $(call archive-dl,OPTIPNG, https://prdownloads.sourceforge.net/optipng/optipng-[VER].tar.gz?download)) $(eval $(call archive-dl,PNGCRUSH, https://prdownloads.sourceforge.net/pmt/pngcrush-[VER]-nolib.tar.gz?download)) $(eval $(call archive-dl,PNGQUANT, https://pngquant.org/pngquant-[VER]-src.tar.gz)) download : $(foreach archive,$(ARCHIVES),$($(archive)_TGZ)) .PHONY : download download-tidy-up : rm -f $(filter-out $(foreach archive,$(ARCHIVES),$($(archive)_TGZ)),$(wildcard $(DL_DIR)/*.*)) .PHONY : download-tidy-up checksum : download @$(sha256sum) $(foreach archive,$(ARCHIVES),$($(archive)_TGZ)) .PHONY : checksum checksum-verify : download @printf '%s %s\n' $(foreach archive,$(ARCHIVES),$($(archive)_SHA256) $($(archive)_TGZ)) | $(sha256sum) -c .PHONY : checksum-verify checksum-update : download @printf '%s := %s\n' $(foreach archive,$(ARCHIVES),$(archive)_SHA256 $(shell $(sha256sum) $($(archive)_TGZ) | cut -d ' ' -f 1)) > checksums.mk .PHONY : checksum-update # ====== PRODUCTS ====== PRODUCTS := # $1 - product name # $2 - archive name ($1 if empty) # $3 - path ($1 if empty) define target-build $1_PATH := $(or $3,$(call downcase,$1)) $1_BASENAME := $$(notdir $$($1_PATH)) $1_DIR := $($(or $2,$1)_DIR) $1_TGZ := $($(or $2,$1)_TGZ) $1_EXTRACTED := $($(or $2,$1)_EXTRACTED) $1_TARGET := $$($1_DIR)/$$($1_PATH) $$($1_TARGET) : DIR := $$($1_DIR) $$($1_TARGET) : $$($1_EXTRACTED) endef # $1 - product name # $2 - archive name ($1 if empty) # $3 - basename ($1 if empty) define target $(call target-build,$1,$2,$3) PRODUCTS += $1 $1_DESTINATION := $$(OUTPUT_DIR)/$$($1_BASENAME) # copy product to output dir $$($1_DESTINATION) : $$($1_TARGET) temppath=`mktemp "$(BUILD_DIR)"/tmp.XXXXXXXXXX` && \ strip $$< -Sx -o "$$$$temppath" && \ chmod 755 "$$$$temppath" && \ mv "$$$$temppath" $$@ # short name target $(call downcase,$1) : | $$($1_DESTINATION) endef $(eval $(call target,ADVPNG,ADVANCECOMP)) $(eval $(call target,GIFSICLE,,src/gifsicle)) $(eval $(call target,JHEAD)) $(eval $(call target,JPEG-RECOMPRESS,JPEGARCHIVE)) $(eval $(call target,JPEGOPTIM)) $(eval $(call target,JPEGTRAN,LIBJPEG,.libs/jpegtran)) $(eval $(call target,LIBJPEG,,libjpeg$(DLEXT))) $(eval $(call target-build,LIBMOZJPEG,,libjpeg.a)) $(eval $(call target,LIBPNG,,libpng$(DLEXT))) $(eval $(call target,LIBZ,,libz$(DLEXT))) $(eval $(call target,OPTIPNG,,src/optipng/optipng)) $(eval $(call target,PNGCRUSH)) $(eval $(call target,PNGQUANT)) # ====== TARGETS ====== all : build @$(MAKE) test .PHONY : all build : $(call downcase,$(PRODUCTS)) .PHONY : build ifdef IS_DARWIN ldd := otool -L else ldd := ldd endif ldd-version :; $(ldd) --version .PHONY : ldd-version define check_exists @test -f $(OUTPUT_DIR)/$1 || \ { printf "$1: $(ANSI_RED)not found$(ANSI_RESET)\n"; exit 1; } endef define check_version @$(OUTPUT_DIR)/$1 $2 | fgrep -q $3 || \ { printf "$1: $(ANSI_RED)Expected $3, got $$($(OUTPUT_DIR)/$1 $2)$(ANSI_RESET)\n"; exit 1; } endef define check_arch @file -b $(OUTPUT_DIR)/$1 | fgrep -q '$(ARCH_STRING)' || \ { printf "$1: $(ANSI_RED)Expected $(ARCH_STRING), got $$(file -b $(OUTPUT_DIR)/$1)$(ANSI_RESET)\n"; exit 1; } endef define check_output @printf "$1: $(ANSI_GREEN)$3$(ANSI_RESET) / $(ANSI_MAGENTA)$(ARCH_STRING)$(ANSI_RESET)\n" endef define check_shlib @! $(ldd) $(OUTPUT_DIR)/$1 | egrep -o "[^: ]+/[^: ]+" | egrep -v "^(@loader_path|/lib|/lib64|/usr|$(OUTPUT_DIR))/" endef define check_lib $(call check_exists,$1) $(call check_arch,$1) $(call check_output,$1,,-) $(call check_shlib,$1) endef define check_bin $(call check_exists,$1) $(call check_version,$1,$2,$3) $(call check_arch,$1) $(call check_output,$1,,$3) $(call check_shlib,$1) endef ifdef IS_DARWIN test : ARCH_STRING := $(ARCH) else ifeq (i386,$(ARCH:i686=i386)) test : ARCH_STRING := 80386 else ifeq (amd64,$(ARCH:x86_64=amd64)) test : ARCH_STRING := x86-64 endif test : $(if $(ARCH_STRING),,@echo Detecting 'ARCH $(ARCH) for OS $(OS) undefined'; false) $(call check_bin,advpng,--version 2>&1,$(ADVANCECOMP_VER)) $(call check_bin,gifsicle,--version,$(GIFSICLE_VER)) $(call check_bin,jhead,-V,$(JHEAD_VER)) $(call check_bin,jpeg-recompress,--version,$(JPEGARCHIVE_VER)) $(call check_bin,jpegoptim,--version,$(JPEGOPTIM_VER)) $(call check_bin,jpegtran,-v - 2>&1,$(LIBJPEG_VER)) $(call check_lib,libjpeg$(DLEXT)) $(call check_lib,libpng$(DLEXT)) $(call check_lib,libz$(DLEXT)) $(call check_bin,optipng,--version,$(OPTIPNG_VER)) $(call check_bin,pngcrush,-version 2>&1,$(PNGCRUSH_VER)) $(call check_bin,pngquant,--help,$(PNGQUANT_VER)) .PHONY : test livecheck :; @script/livecheck .PHONY : livecheck update-versions : script/livecheck --update make checksum-update .PHONY : update-versions # ====== CLEAN ====== clean : rm -rf $(BUILD_DIR) rm -rf $(OUTPUT_DIR) .PHONY : clean clean-all : rm -rf $(BUILD_ROOT_DIR) rm -rf $(OUTPUT_ROOT_DIR) .PHONY : clean-all clobber : clean-all rm -rf $(DL_DIR) .PHONY : clobber # ====== BUILD HELPERS ====== # $1 - name of product # $2 - list of dependency products define depend-build # depend this product on every specified product $($1_EXTRACTED) : $$(filter-out $($1_EXTRACTED),$(foreach dep,$2,$$($(dep)_EXTRACTED))) $($1_TARGET) : $(foreach dep,$2,$$($(dep)_TARGET)) # add dependent product dir to CPATH, LIBRARY_PATH and PKG_CONFIG_PATH $($1_TARGET) : export CPATH := $(subst $(eval) ,:,$(foreach dep,$2,$$($(dep)_DIR))) $($1_TARGET) : export LIBRARY_PATH := $$(CPATH) $($1_TARGET) : export PKG_CONFIG_PATH := $$(CPATH) endef # $1 - name of product # $2 - list of dependency products define depend $(call depend-build,$1,$2) # depend output of this product on output of every specified product $$($1_DESTINATION) : $(foreach dep,$2,$$($(dep)_DESTINATION)) endef pkgconfig_pwd = perl -pi -e 's/(?<=dir=).*/$$ENV{PWD}/' libtool_target_soname = perl -pi -e 's/(?<=soname_spec=)".*"/"$(@F)"/ ; s/(?<=library_names_spec=)".*"/"\\\$$libname\\\$$shared_ext"/' -- libtool ifdef IS_DARWIN chrpath_origin = else ifdef IS_OPENBSD chrpath_origin = perl -pi -e 's/XORIGIN/\$$ORIGIN/' -- $1 else chrpath_origin = chrpath -r '$$ORIGIN' $1 endif ifdef IS_LINUX XORIGIN := -Wl,-rpath,XORIGIN else ifdef IS_BSD XORIGIN := -Wl,-rpath,XORIGIN -Wl,-z,origin else XORIGIN := endif # ====== ENV ====== ifdef IS_DARWIN export CC := clang export CXX := clang++ else export CC := gcc export CXX := g++ endif GCC_FLAGS := -O3 STATIC_LIBGCC := $(shell if $(CC) -v 2>&1 | fgrep -q gcc; then echo -static-libgcc; fi) export CFLAGS = $(GCC_FLAGS) export CXXFLAGS = $(GCC_FLAGS) export CPPFLAGS = $(GCC_FLAGS) export LDFLAGS = $(GCC_FLAGS) ifdef IS_DARWIN export MACOSX_DEPLOYMENT_TARGET := 10.9 GCC_FLAGS += -arch $(ARCH) CXXFLAGS += -stdlib=libc++ endif ifdef IS_BSD autotool_version = $(shell printf '%s\n' /usr/local/bin/$1-* | egrep -o '[0-9][^-]+$$' | tail -n 1) export AUTOCONF_VERSION := $(call autotool_version,autoconf) export AUTOMAKE_VERSION := $(call autotool_version,automake) endif # ====== BUILD TARGETS ====== ## advpng $(eval $(call depend,ADVPNG,LIBZ)) $(ADVPNG_TARGET) : cd $(DIR) && ./configure LDFLAGS="$(XORIGIN)" cd $(DIR) && $(MAKE) advpng $(call chrpath_origin,$@) ## gifsicle $(GIFSICLE_TARGET) : cd $(DIR) && ./configure cd $(DIR) && $(MAKE) gifsicle ## jhead $(JHEAD_TARGET) : cd $(DIR) && $(MAKE) jhead CC="$(CC) $(CFLAGS)" ## jpeg-recompress $(eval $(call depend-build,JPEG-RECOMPRESS,LIBMOZJPEG)) $(JPEG-RECOMPRESS_TARGET) : cd $(DIR) && $(MAKE) jpeg-recompress CC="$(CC) $(CFLAGS)" LIBJPEG=$(LIBMOZJPEG_TARGET) \ MAKE=$(MAKE) # fix for bsd in jpeg-archive-2.1.1 ## jpegoptim $(eval $(call depend,JPEGOPTIM,LIBJPEG)) $(JPEGOPTIM_TARGET) : cd $(DIR) && ./configure LDFLAGS="$(XORIGIN)" --host $(HOST) cd $(DIR) && $(MAKE) jpegoptim $(call chrpath_origin,$@) ## jpegtran $(eval $(call depend,JPEGTRAN,LIBJPEG)) $(JPEGTRAN_TARGET) : cd $(DIR) && $(MAKE) jpegtran LDFLAGS="$(XORIGIN)" $(call chrpath_origin,$(JPEGTRAN_TARGET)) ## libjpeg $(LIBJPEG_TARGET) : cd $(DIR) && ./configure CC="$(CC) $(CFLAGS)" cd $(DIR) && $(libtool_target_soname) ifdef IS_DARWIN cd $(DIR) && $(MAKE) libjpeg.la LDFLAGS="-Wl,-install_name,@loader_path/$(@F)" else cd $(DIR) && $(MAKE) libjpeg.la endif cd $(@D) && $(ln_s) .libs/libjpeg$(DLEXT) . ## libmozjpeg $(LIBMOZJPEG_TARGET) : cd $(DIR) && cmake -DPNG_SUPPORTED=0 . cd $(DIR) && $(MAKE) jpeg-static ## libpng $(eval $(call depend,LIBPNG,LIBZ)) $(LIBPNG_TARGET) : cd $(DIR) && ./configure CC="$(CC) $(CFLAGS)" cd $(DIR) && $(pkgconfig_pwd) -- *.pc cd $(DIR) && perl -pi -e 's/(?<=lpng)\d+//g' -- *.pc # %MAJOR%%MINOR% suffix cd $(DIR) && $(libtool_target_soname) ifdef IS_DARWIN cd $(DIR) && $(MAKE) libpng16.la LDFLAGS="-Wl,-install_name,@loader_path/$(@F)" else cd $(DIR) && $(MAKE) libpng16.la LDFLAGS="$(XORIGIN)" endif cd $(DIR) && $(ln_s) .libs/libpng16$(DLEXT) libpng$(DLEXT) $(call chrpath_origin,$@) ## libz ifdef IS_DARWIN $(LIBZ_TARGET) : export LDSHARED = $(CC) -dynamiclib -install_name @loader_path/$(@F) -compatibility_version 1 -current_version $(LIBZ_VER) else $(LIBZ_TARGET) : export LDSHARED = $(CC) -shared -Wl,-soname,$(@F),--version-script,zlib.map endif $(LIBZ_TARGET) : cd $(DIR) && ./configure cd $(DIR) && $(pkgconfig_pwd) -- *.pc cd $(DIR) && $(MAKE) placebo ## optipng $(eval $(call depend,OPTIPNG,LIBPNG LIBZ)) $(OPTIPNG_TARGET) : cd $(DIR) && ./configure -with-system-libs cd $(DIR) && $(MAKE) all LDFLAGS="$(XORIGIN) $(LDFLAGS)" $(call chrpath_origin,$@) ## pngcrush $(eval $(call depend,PNGCRUSH,LIBPNG LIBZ)) $(PNGCRUSH_TARGET) : cd $(DIR) && rm -f png.h pngconf.h cd $(DIR) && $(MAKE) pngcrush \ CC="$(CC)" \ LD="$(CC)" \ LIBS="-lpng -lz -lm" \ CFLAGS="$(CFLAGS)" \ CPPFLAGS="$(CPPFLAGS)" \ LDFLAGS="$(XORIGIN) $(LDFLAGS)" $(call chrpath_origin,$@) ## pngquant $(eval $(call depend,PNGQUANT,LIBPNG LIBZ)) $(PNGQUANT_TARGET) : cd $(DIR) && ./configure --without-cocoa --without-lcms2 --extra-ldflags="$(XORIGIN) $(STATIC_LIBGCC)" cd $(DIR) && $(MAKE) pngquant $(call chrpath_origin,$@)