# This file is part of MXE. # See index.html for further information. MXE_TARGET_LIST := i686-pc-mingw32 x86_64-w64-mingw32 i686-w64-mingw32 MXE_TARGETS := i686-pc-mingw32 DEFAULT_MAX_JOBS := 6 SOURCEFORGE_MIRROR := freefr.dl.sourceforge.net PKG_MIRROR := s3.amazonaws.com/mxe-pkg PKG_CDN := d1yihgixbnrglp.cloudfront.net PWD := $(shell pwd) SHELL := bash NPROCS := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1) JOBS := $(shell printf "$(DEFAULT_MAX_JOBS)\n$(NPROCS)" | sort -n | head -1) DATE := $(shell gdate --help >/dev/null 2>&1 && echo g)date INSTALL := $(shell ginstall --help >/dev/null 2>&1 && echo g)install LIBTOOL := $(shell glibtool --help >/dev/null 2>&1 && echo g)libtool LIBTOOLIZE := $(shell glibtoolize --help >/dev/null 2>&1 && echo g)libtoolize PATCH := $(shell gpatch --help >/dev/null 2>&1 && echo g)patch SED := $(shell gsed --help >/dev/null 2>&1 && echo g)sed SORT := $(shell gsort --help >/dev/null 2>&1 && echo g)sort WGET := wget --no-check-certificate \ --user-agent=$(shell wget --version | \ $(SED) -n 's,GNU \(Wget\) \([0-9.]*\).*,\1/\2,p') REQUIREMENTS := autoconf automake bash bison bzip2 cmake flex \ gcc g++ intltoolize $(LIBTOOL) $(LIBTOOLIZE) \ $(MAKE) openssl $(PATCH) $(PERL) pkg-config \ scons $(SED) $(SORT) unzip wget xz PREFIX := $(PWD)/usr LOG_DIR := $(PWD)/log TIMESTAMP := $(shell date +%Y%m%d_%H%M%S) PKG_DIR := $(PWD)/pkg TMP_DIR = $(PWD)/tmp-$(1) MAKEFILE := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST)) TOP_DIR := $(patsubst %/,%,$(dir $(MAKEFILE))) PKGS := $(shell $(SED) -n 's/^.* class="package">\([^<]*\)<.*$$/\1/p' '$(TOP_DIR)/index.html') PATH := $(PREFIX)/bin:$(PATH) # unexport any environment variables that might cause trouble unexport AR CC CFLAGS C_INCLUDE_PATH CPATH CPLUS_INCLUDE_PATH CPP unexport CPPFLAGS CROSS CXX CXXCPP CXXFLAGS EXEEXT EXTRA_CFLAGS unexport EXTRA_LDFLAGS LD LDFLAGS LIBRARY_PATH LIBS NM unexport OBJC_INCLUDE_PATH PKG_CONFIG QMAKESPEC RANLIB STRIP unexport CONFIG_SITE ALL_TARGETS TARGET TARGETS SHORT_PKG_VERSION = \ $(word 1,$(subst ., ,$($(1)_VERSION))).$(word 2,$(subst ., ,$($(1)_VERSION))) UNPACK_ARCHIVE = \ $(if $(filter %.tgz, $(1)),tar xzf '$(1)', \ $(if $(filter %.tar.gz, $(1)),tar xzf '$(1)', \ $(if $(filter %.tar.bz2, $(1)),tar xjf '$(1)', \ $(if $(filter %.tar.lzma,$(1)),xz -dc -F lzma '$(1)' | tar xf -, \ $(if $(filter %.tar.xz,$(1)),xz -dc '$(1)' | tar xf -, \ $(if $(filter %.zip, $(1)),unzip -q '$(1)', \ $(error Unknown archive format: $(1)))))))) UNPACK_PKG_ARCHIVE = \ $(call UNPACK_ARCHIVE,$(PKG_DIR)/$($(1)_FILE)) PKG_CHECKSUM = \ openssl sha1 '$(PKG_DIR)/$($(1)_FILE)' 2>/dev/null | $(SED) -n 's,^.*\([0-9a-f]\{40\}\)$$,\1,p' CHECK_PKG_ARCHIVE = \ [ '$($(1)_CHECKSUM)' == "`$$(call PKG_CHECKSUM,$(1))`" ] ESCAPE_PKG = \ echo '$($(1)_FILE)' | perl -lpe 's/([^A-Za-z0-9])/sprintf("%%%02X", ord($$$$1))/seg' DOWNLOAD_PKG_ARCHIVE = \ mkdir -p '$(PKG_DIR)' && \ $(if $($(1)_URL_2), \ ( $(WGET) -T 30 -t 3 -O- '$($(1)_URL)' || \ $(WGET) -O- '$($(1)_URL_2)' || \ $(WGET) -O- $(PKG_MIRROR)/`$(call ESCAPE_PKG,$(1))` || \ $(WGET) -O- $(PKG_CDN)/`$(call ESCAPE_PKG,$(1))` ), \ ( $(WGET) -O- '$($(1)_URL)' || \ $(WGET) -O- $(PKG_MIRROR)/`$(call ESCAPE_PKG,$(1))` || \ $(WGET) -O- $(PKG_CDN)/`$(call ESCAPE_PKG,$(1))` )) \ $(if $($(1)_FIX_GZIP), \ | gzip -d | gzip -9n, \ ) \ > '$(PKG_DIR)/$($(1)_FILE)' || rm -f '$(PKG_DIR)/$($(1)_FILE)' ifeq ($(IGNORE_SETTINGS),yes) $(info [ignore settings.mk]) else ifeq ($(wildcard $(PWD)/settings.mk),$(PWD)/settings.mk) include $(PWD)/settings.mk else $(info [create settings.mk]) $(shell { \ echo '#JOBS := $(JOBS)'; \ echo '#MXE_TARGETS := $(MXE_TARGET_LIST)'; \ echo '#SOURCEFORGE_MIRROR := downloads.sourceforge.net'; \ echo '#LOCAL_PKG_LIST := boost curl file flac lzo pthreads vorbis wxwidgets'; \ echo '#.DEFAULT local-pkg-list:'; \ echo '#local-pkg-list: $$(LOCAL_PKG_LIST)'; \ } >'$(PWD)/settings.mk') endif .PHONY: all all: $(PKGS) .PHONY: check-requirements define CHECK_REQUIREMENT @if ! $(1) --help &>/dev/null; then \ echo; \ echo 'Missing requirement: $(1)'; \ echo; \ echo 'Please have a look at "index.html" to ensure'; \ echo 'that your system meets all requirements.'; \ echo; \ exit 1; \ fi endef define CHECK_REQUIREMENT_VERSION @if ! $(1) --version | head -1 | grep ' \($(2)\)$$' >/dev/null; then \ echo; \ echo 'Wrong version of requirement: $(1)'; \ echo; \ echo 'Please have a look at "index.html" to ensure'; \ echo 'that your system meets all requirements.'; \ echo; \ exit 1; \ fi endef check-requirements: $(PREFIX)/installed/check-requirements $(PREFIX)/installed/check-requirements: $(MAKEFILE) @echo '[check requirements]' $(foreach REQUIREMENT,$(REQUIREMENTS),$(call CHECK_REQUIREMENT,$(REQUIREMENT))) $(call CHECK_REQUIREMENT_VERSION,autoconf,2\.6[4-9]\|2\.[7-9][0-9]) $(call CHECK_REQUIREMENT_VERSION,automake,1\.[1-9][0-9]\(\.[0-9]\+\)\?) @[ -d '$(PREFIX)/installed' ] || mkdir -p '$(PREFIX)/installed' @touch '$@' define newline endef include $(patsubst %,$(TOP_DIR)/src/%.mk,$(PKGS)) .PHONY: download download: $(addprefix download-,$(PKGS)) define TARGET_DEPS $(1)_DEPS := $(shell echo '$(MXE_TARGETS)' | \ $(SED) -n 's,.*$(1)\(.*\),\1,p' | \ awk '{print $$1}') endef $(foreach TARGET,$(MXE_TARGETS),$(eval $(call TARGET_DEPS,$(TARGET)))) TARGET_HEADER = \ $(strip with \ $(if $(value MAKECMDGOALS),\ $(words $(MAKECMDGOALS)) goal$(shell [ $(words $(MAKECMDGOALS)) == 1 ] || echo s) from command line,\ $(if $(value LOCAL_PKG_LIST),\ $(words $(LOCAL_PKG_LIST)) goal$(shell [ $(words $(LOCAL_PKG_LIST)) == 1 ] || echo s) from settings.mk,\ $(words $(PKGS)) goal$(shell [ $(words $(PKGS)) == 1 ] || echo s) from src/*.mk))) define TARGET_RULE .PHONY: $(1) $(1): | $(if $(value $(1)_DEPS), \ $(if $(value MAKECMDGOALS),\ $(addprefix $(PREFIX)/$($(1)_DEPS)/installed/,$(MAKECMDGOALS)), \ $(if $(value LOCAL_PKG_LIST),\ $(addprefix $(PREFIX)/$($(1)_DEPS)/installed/,$(LOCAL_PKG_LIST)), \ $(addprefix $(PREFIX)/$($(1)_DEPS)/installed/,$(PKGS))))) \ $($(1)_DEPS) @echo '[target] $(1) $(call TARGET_HEADER)' endef $(foreach TARGET,$(MXE_TARGETS),$(eval $(call TARGET_RULE,$(TARGET)))) define PKG_RULE .PHONY: download-$(1) download-$(1):: $(addprefix download-,$($(1)_DEPS) $($(1)_DEPS_$(3))) if ! $(call CHECK_PKG_ARCHIVE,$(1)); then \ $(call DOWNLOAD_PKG_ARCHIVE,$(1)); \ $(call CHECK_PKG_ARCHIVE,$(1)) || { echo 'Wrong checksum!'; exit 1; }; \ fi .PHONY: $(1) $(1): $(PREFIX)/$(3)/installed/$(1) $(PREFIX)/$(3)/installed/$(1): $(TOP_DIR)/src/$(1).mk \ $(wildcard $(TOP_DIR)/src/$(1)-*.patch) \ $(wildcard $(TOP_DIR)/src/$(1)-test*) \ $(addprefix $(PREFIX)/$(3)/installed/,$($(1)_DEPS) $($(1)_DEPS_$(3))) \ | check-requirements $(3) @[ -d '$(LOG_DIR)/$(TIMESTAMP)' ] || mkdir -p '$(LOG_DIR)/$(TIMESTAMP)' @if ! $(call CHECK_PKG_ARCHIVE,$(1)); then \ echo '[download] $(1)'; \ ($(call DOWNLOAD_PKG_ARCHIVE,$(1))) &> '$(LOG_DIR)/$(TIMESTAMP)/$(1)-download'; \ ln -sf '$(TIMESTAMP)/$(1)-download' '$(LOG_DIR)/$(1)-download'; \ if ! $(call CHECK_PKG_ARCHIVE,$(1)); then \ echo; \ echo 'Wrong checksum of package $(1)!'; \ echo '------------------------------------------------------------'; \ tail -n 10 '$(LOG_DIR)/$(1)-download' | $(SED) -n '/./p'; \ echo '------------------------------------------------------------'; \ echo '[log] $(LOG_DIR)/$(1)-download'; \ echo; \ exit 1; \ fi; \ fi $(if $(or $(value $(1)_BUILD_$(3)),\ $(and $(value $(1)_BUILD),$(findstring undefined,$(origin $(1)_BUILD_$(3))))), @echo '[build] $(1)', $(if $(findstring undefined,$(origin $(1)_BUILD_$(3))), @echo '[no-op] $(1)', @echo '[exclude] $(1)' ) ) @touch '$(LOG_DIR)/$(TIMESTAMP)/$(1)_$(3)' @[ $(words $(MXE_TARGETS)) == 1 ] || ln -sf '$(TIMESTAMP)/$(1)_$(3)' '$(LOG_DIR)/$(1)_$(3)' @ln -sf '$(TIMESTAMP)/$(1)_$(3)' '$(LOG_DIR)/$(1)' @if ! (time $(MAKE) -f '$(MAKEFILE)' 'build-only-$(1)_$(3)') &> '$(LOG_DIR)/$(TIMESTAMP)/$(1)_$(3)'; then \ echo; \ echo 'Failed to build package $(1)!'; \ echo '------------------------------------------------------------'; \ tail -n 10 '$(LOG_DIR)/$(1)' | $(SED) -n '/./p'; \ echo '------------------------------------------------------------'; \ echo '[log] $(LOG_DIR)/$(1)'; \ echo; \ (echo; \ find '$(2)' -name 'config.log' -print -exec cat {} \;; \ echo; \ echo 'settings.mk'; \ cat '$(TOP_DIR)/settings.mk'; \ ) >> '$(LOG_DIR)/$(TIMESTAMP)/$(1)_$(3)'; \ exit 1; \ fi @echo '[done] $(1)' .PHONY: build-only-$(1)_$(3) build-only-$(1)_$(3): PKG = $(1) build-only-$(1)_$(3): TARGET = $(3) build-only-$(1)_$(3): CMAKE_TOOLCHAIN_FILE = $(PREFIX)/$(3)/share/cmake/mxe-conf.cmake build-only-$(1)_$(3): $(if $(or $(value $(1)_BUILD_$(3)),\ $(and $(value $(1)_BUILD),$(findstring undefined,$(origin $(1)_BUILD_$(3))))), uname -a git show-branch --list --reflog=1 lsb_release -a 2>/dev/null || sw_vers 2>/dev/null || true rm -rf '$(2)' mkdir -p '$(2)' cd '$(2)' && $(call UNPACK_PKG_ARCHIVE,$(1)) cd '$(2)/$($(1)_SUBDIR)' $(foreach PKG_PATCH,$(sort $(wildcard $(TOP_DIR)/src/$(1)-*.patch)), (cd '$(2)/$($(1)_SUBDIR)' && $(PATCH) -p1 -u) < $(PKG_PATCH)) $$(call $(if $(value $(1)_BUILD_$(3)),$(1)_BUILD_$(3),$(1)_BUILD),$(2)/$($(1)_SUBDIR),$(TOP_DIR)/src/$(1)-test) (du -k -d 0 '$(2)' 2>/dev/null || du -k --max-depth 0 '$(2)') | $(SED) -n 's/^\(\S*\).*/du: \1 KiB/p' rm -rfv '$(2)' ,) [ -d '$(PREFIX)/$(3)/installed' ] || mkdir -p '$(PREFIX)/$(3)/installed' touch '$(PREFIX)/$(3)/installed/$(1)' endef $(foreach TARGET,$(MXE_TARGETS), \ $(foreach PKG,$(PKGS), \ $(eval $(call PKG_RULE,$(PKG),$(call TMP_DIR,$(PKG)),$(TARGET))))) .PHONY: clean clean: rm -rf $(call TMP_DIR,*) $(PREFIX)/* .PHONY: clean-pkg clean-pkg: rm -f $(patsubst %,'%', \ $(filter-out \ $(foreach PKG,$(PKGS),$(PKG_DIR)/$($(PKG)_FILE)), \ $(wildcard $(PKG_DIR)/*))) .PHONY: update define UPDATE $(if $(2), $(if $(filter $($(1)_IGNORE),$(2)), $(info IGNORED $(1) $(2)), $(if $(filter $(2),$(shell printf '$($(1)_VERSION)\n$(2)' | $(SORT) -V | head -1)), $(if $(filter $(2),$($(1)_VERSION)), $(info . $(1) $(2)), $(info OLD $(1) $($(1)_VERSION) --> $(2) ignoring)), $(info NEW $(1) $($(1)_VERSION) --> $(2)) $(SED) -i 's/^\([^ ]*_VERSION *:=\).*/\1 $(2)/' '$(TOP_DIR)/src/$(1).mk' $(MAKE) -f '$(MAKEFILE)' 'update-checksum-$(1)' \ || { $(SED) -i 's/^\([^ ]*_VERSION *:=\).*/\1 $($(1)_VERSION)/' '$(TOP_DIR)/src/$(1).mk'; \ exit 1; })), $(info Unable to update version number of package $(1) \ $(newline)$(newline)$($(1)_UPDATE)$(newline))) endef update: $(foreach PKG,$(PKGS),$(call UPDATE,$(PKG),$(shell $($(PKG)_UPDATE)))) update-checksum-%: $(if $(findstring $*~,$(addsuffix ~,$(PKGS))), \ $(call DOWNLOAD_PKG_ARCHIVE,$*) && \ $(SED) -i 's/^\([^ ]*_CHECKSUM *:=\).*/\1 '"`$(call PKG_CHECKSUM,$*)`"'/' '$(TOP_DIR)/src/$*.mk', \ $(error package $* not found in index.html)) cleanup-style: @$(foreach FILE,$(wildcard $(addprefix $(TOP_DIR)/,Makefile index.html CNAME src/*.mk src/*test.* tools/*)),\ $(SED) ' \ s/\r//g; \ s/[ \t]\+$$//; \ s,^#!/bin/bash$$,#!/usr/bin/env bash,; \ $(if $(filter %Makefile,$(FILE)),,\ s/\t/ /g; \ ) \ ' < $(FILE) > $(TOP_DIR)/tmp-cleanup-style; \ diff -u $(FILE) $(TOP_DIR)/tmp-cleanup-style >/dev/null \ || { echo '[cleanup] $(FILE)'; \ cp $(TOP_DIR)/tmp-cleanup-style $(FILE); }; \ rm -f $(TOP_DIR)/tmp-cleanup-style; \ )