include projects.mk

noop :=
space := $(noop) $(noop)

# $1 - project name
DEST = build/dist/$1
BUNDLE = build/bundle/$1-bundle
ALLOW_CLONE = true

TESTING_IEX_URL=http://iex-proxy-testing.n.yandex-team.ru/iex/factextract/
IEX_URL ?= $(iex-url)

URL = $(if $(filter-out testing,$(IEX_URL)),$(IEX_URL),$(TESTING_IEX_URL))

java-homes := $(strip\
    $(JAVA_HOME)\
    /usr/lib/jvm/yandex-ibm-java\
    /usr/lib/jvm/java-1.7.0-ibm-wrt-3.64\
    /opt/ibm/javawrt3_64\
    /opt/javawrt3_64)
# $1 - java home to search in
java-check-home = $(and\
    $(wildcard $1/bin/java),$(wildcard $1/bin/javac),$(wildcard $1/bin/jar))
java-home := \
    $(firstword\
	$(foreach home,\
	    $(java-homes),\
	    $(if $(call java-check-home,$(home)),$(home))))
JAR := $(java-home)/bin/jar
JAVA := $(java-home)/bin/java
JAVA_OPTS := -Xdump:none
override JAVA_OPTS += \
    -Dfile.encoding=UTF8 \
    $(addprefix -DIEX_URL=,$(URL)) \
    -Djava.net.preferIPv4Stack=false \
    -Djava.net.preferIPv6Addresses=true
JAVA_TEST_OPTS := -Xss128k
JAVAC := $(java-home)/bin/javac
JAVAC_OPTS = \
    -J-Xmx2G -g -encoding UTF-8 -XDignore.symbol.file -Xdiags:verbose \
    $(if $($1-skip-checks),,-Xlint -Werror)
JAVACC := $(JAVA) -cp \
    ./lib/javacc.jar:/usr/share/java/javacc.jar:/usr/share/javacc/lib/javacc.jar javacc
PROTOC := ./protoc/protoc
CFLAGS := -Ofast -flto -fvisibility=hidden -mtune=ivybridge
# resolve <jni.h>
override CFLAGS += -I$(java-home)/include/ -I$(java-home)/include/linux
# we are building only shared libraries
override CFLAGS += -fPIC -DPIC -D_LARGEFILE64_SOURCE=1 -DHAVE_HIDDEN
override CFLAGS += -mmmx -msse -msse2
# Allow overrides
override CFLAGS += $(CFLAGS_OVERRIDES)
# bleeding edge features for zlib_fast
ZLIB_FAST_CFLAGS := -DHAS_SSE42 -DHAS_PCLMUL -msse4.2 -mpclmul

LDFLAGS := -Wl,-O4 -Wl,-z,now
WL_PREFIX := -Wl,
override LDFLAGS += $(addprefix $(WL_PREFIX),$(findstring -flto,$(CFLAGS)))

checkstyle-libs := \
    $(guava) \
    $(commons-cli) \
    $(commons-collections) \
    $(commons-lang) \
    $(commons-logging) \
    lib/checkstyle/antlr-2.7.7.jar \
    lib/checkstyle/antlr4-runtime-4.5.3.jar \
    lib/checkstyle/checkstyle-6.19.jar \
    lib/checkstyle/commons-beanutils-1.9.2.jar

spotbugs-version := 3.1.12
spotbugs-dir := lib/spotbugs-$(spotbugs-version)
spotbugs-jar := $(spotbugs-dir)/spotbugs.jar

spotbugs-libs := \
    $(addprefix $(spotbugs-dir)/,\
	asm-7.0.jar \
	asm-analysis-7.0.jar \
	asm-commons-7.0.jar \
	asm-tree-7.0.jar \
	asm-util-7.0.jar \
	bcel-6.3.jar \
	commons-lang-2.6.jar \
	dom4j-2.1.1.jar \
	jaxen-1.1.6.jar \
	jcip-annotations-1.0.jar \
	jsr305-3.0.2.jar \
	log4j-api-2.11.1.jar \
	log4j-core-2.11.1.jar \
	log4j-slf4j18-impl-2.11.1.jar \
	slf4j-api-1.8.0-alpha2.jar \
	slf4j-api-1.8.0-beta2.jar \
	spotbugs-annotations.jar)

# $1 - list of directories
existing-dirs = \
    $(strip $(foreach dir,$1,$(if $(wildcard $(dir)/),$(dir))))

# $1 - list of directories
# $2 - additional filters
dirs-listing = $(if $(call existing-dirs,$1),$(shell find \
    $(sort $(call existing-dirs,$1)) $2 -not -name .\*))

# $1 - project name/main or test, e.g. httpserver/main or tikaite/test
project-resources = $(call dirs-listing,src/$1/resources/,)
project-javacc-sources = \
    $(call dirs-listing,src/$1/javacc,-type f -name \*.jj)
project-javacc-generated-sources = \
    $(sort $(addsuffix .fake,$(subst src/$1/javacc,build/$1/java,\
	$(dir $(call project-javacc-sources,$1)))))
project-jflex-sources = \
    $(call dirs-listing,src/$1/jflex,-type f -name \*.lex)
project-jflex-generated-sources = $(patsubst src/$1/jflex/%.lex,\
    build/$1/java/%.java,$(call project-jflex-sources,$1))
project-jute-sources = \
    $(call dirs-listing,src/$1/jute,-type f -name \*.jute)
project-jute-generated-sources = \
    $(sort $(addsuffix /.fake,$(subst src/$1/jute,build/$1/java,\
	$(call project-jute-sources,$1))))
project-protobuf-sources = \
    $(call dirs-listing,src/$1/protobuf,-type f -name \*.proto)
project-protobuf-generated-sources = \
    $(sort $(addsuffix /.fake,$(subst src/$1/protobuf,build/$1/java,\
	$(call project-protobuf-sources,$1))))
project-ragel-sources = \
    $(call dirs-listing,src/$1/ragel,-type f -name \*.rl)
project-ragel-generated-sources = $(patsubst src/$1/ragel/%.rl,\
    build/$1/java/%.java,$(call project-ragel-sources,$1))
project-static-java-sources = \
    $(call dirs-listing,src/$1/java,-type f -name \*.java)
project-sources = $(call dirs-listing,\
    src/$1/java src/$1/javacc src/$1/jflex src/$1/jute src/$1/protobuf src/$1/ragel,-type f)
project-java-sources = $(strip \
    $(call project-static-java-sources,$1) \
    $(call project-javacc-generated-sources,$1) \
    $(call project-jflex-generated-sources,$1) \
    $(call project-jute-generated-sources,$1) \
    $(call project-protobuf-generated-sources,$1) \
    $(call project-ragel-generated-sources,$1))

# $1 - project name
# $2 - main, test or benchmark
project-deps-impl = \
    $($1-$2-deps) \
    $($1-main-deps) \
    $(foreach dep,$(sort $($1-$2-deps) $($1-main-deps)),\
	$(call project-deps-impl,$(dep),main))
project-deps = $(sort $(call project-deps-impl,$1,$2))
project-deps-libs = $(sort $(foreach dep,$(call project-deps,$1,$2),\
    $($(dep)-main-libs) $($(dep)-$2-libs)))
project-deps-resources = $(call dirs-listing,\
    $(foreach dep,$(call project-deps,$1,$2),src/$1/$2/resources),)
project-deps-dlls = $(sort $(foreach dep,$(call project-deps,$1,$2),\
    $($(dep)-main-dlls) $($(dep)-$2-dlls)))
project-all-libs = $(sort $($1-$2-libs) $($1-main-libs) \
    $(call project-deps-libs,$1,$2) $(call project-deps-libs,$1,main))
project-all-resources = $(call project-deps-resources,$1,$2) \
    $(call project-resources,$1/$2)
project-all-dlls = $(sort $($1-$2-dlls) $($1-main-dlls) \
    $(call project-deps-dlls,$1,$2) $(call project-deps-dlls,$1,main))

# $1 - project name
project-jar = \
    $(if $(strip $(foreach prj,$1 $(call project-deps,$1,main),\
	$(if $(call project-java-sources,$(prj)/main),build/$(prj).jar))),\
    build/$1.jar)
project-tests = $(subst /,.,$(patsubst src/$1/test/java/%.java,%,\
    $(call dirs-listing,src/$1/test/java,-type f -name \*Test.java)))
project-execs = $(patsubst %,build/report/$1/%.exec,$(call project-tests,$1))
project-benchmarks = $(subst /,.,$(patsubst src/$1/benchmark/java/%.java,%,\
    $(call dirs-listing,src/$1/benchmark/java,-type f -name \*Benchmark.java)))
project-bundles = $(foreach dep,$1 $(call project-deps,$1,main),\
    $(call existing-dirs,src/$(dep)/main/bundle))
project-bundles-sources = $(call dirs-listing,$(call project-bundles,$1),)
project-main-classes = \
    $(foreach dep,$(call project-deps,$1,main),\
	$(if $(call project-java-sources,$(dep)/main),\
	    build/$(dep)/main/classes))
project-all-main-classes = \
    $(if $(call project-java-sources,$1/main),build/$1/main/classes) \
    $(call project-main-classes,$1)
project-test-classes = \
    $(foreach dep,$(call project-deps,$1,test),\
	$(if $(call project-java-sources,$(dep)/main),\
	    build/$(dep)/main/classes))

projects-javacc-generated-sources := $(foreach project,$(projects),\
    $(call project-javacc-generated-sources,$(project)/main))
projects-jflex-generated-sources := $(foreach project,$(projects),\
    $(call project-jflex-generated-sources,$(project)/main))
projects-jute-generated-sources := $(foreach project,$(projects),\
    $(call project-jute-generated-sources,$(project)/main))
projects-protobuf-generated-sources := $(foreach project,$(projects),\
    $(call project-protobuf-generated-sources,$(project)/main))
projects-ragel-generated-sources := $(foreach project,$(projects),\
    $(call project-ragel-generated-sources,$(project)/main))
projects-main-classes := \
    $(foreach project,$(projects),\
	$(if \
	    $(call project-java-sources,$(project)/main),\
	    build/$(project)/main/classes))
projects-benchmark-classes := $(patsubst src/%,build/%,\
    $(addsuffix /classes,$(strip $(foreach project,$(projects), \
	$(call existing-dirs,src/$(project)/benchmark)))))
projects-jars := $(foreach project,$(projects),build/$(project).jar)
projects-execs := \
    $(strip $(foreach project,$(projects),$(call project-execs,$(project))))
projects-with-tests := $(strip $(foreach project,$(projects),\
    $(if $(call project-tests,$(project)),$(project))))
projects-with-benchmarks := $(strip $(foreach project,$(projects),\
    $(if $(call project-benchmarks,$(project)),$(project))))
projects-static-sources := \
    $(foreach project,$(projects), $(foreach stage,main test benchmark,\
	$(call project-sources,$(project)/$(stage))))
projects-main-libs := $(sort $(foreach project,$(projects),\
    $(call project-all-libs,$(project),main)))
projects-test-libs := $(sort $(foreach project,$(projects),\
    $(call project-all-libs,$(project),test)))
projects-installs := $(addsuffix -install,$(projects))
projects-bundles := $(addsuffix -bundle,$(projects))
projects-uploads := $(addsuffix -upload,$(projects))
projects-instancectl-uploads := $(addsuffix -instancectl-upload,$(projects))
projects-benchmarks := $(addsuffix -benchmark,$(projects-with-benchmarks))

uncheckable-projects := $(strip $(foreach project,$(projects),\
    $(if $($(project)-skip-checks),$(project))))
checkable-projects := $(filter-out $(uncheckable-projects),$(projects))
checkable-classes := \
    $(filter $(patsubst %,build/%/main/classes,$(checkable-projects)),\
	$(projects-main-classes))
uncheckable-classes := \
    $(filter $(patsubst %,build/%/main/classes,$(uncheckable-projects)),\
	$(projects-main-classes))

checkstyle-prereqs := $(sort $(strip $(junit) $(checkstyle-libs) \
    $(projects-main-classes) \
    $(foreach project,$(projects-with-tests),build/$(project)/test/classes) \
    $(foreach project,$(projects-with-benchmarks),\
	build/$(project)/benchmark/classes) \
    $(sort $(projects-main-libs) $(projects-test-libs))))

.SUFFIXES:
.PHONY: \
    all \
    clean \
    checkstyle \
    coverage \
    install \
    $(projects) \
    $(projects-installs) \
    $(projects-bundles) \
    $(projects-uploads)

all: checkstyle coverage findbugs benchmark

clean:
	-@rm -rf build

build:
	@mkdir -p build

Makefile projects.mk: | build

$(projects-static-sources)\
    src/compress/Inflater.c \
    src/compress/Deflater.c src/compress/jlong_md.h src/compress/jni_util.h \
    src/compress/main.c src/compress/lzma.c src/compress/compress.h \
    src/fast-md5/MD5.c \
    src/jniwrapper/main.c src/jniwrapper/test.c \
    src/ldpreload/ldpreload.c \
    src/scripts/java.sh \
    src/scripts/bin_with_preload.sh:\
    Makefile projects.mk
	@touch $@

checkstyle: build/checkstyle build/projects-checkstyle

build/checkstyle: $(checkstyle-prereqs) lib/checkstyle/checkstyle.xml
	@echo "[Performing checkstyle]"
	@$(JAVA) $(JAVA_OPTS) -cp $(subst $(space),:,$(checkstyle-prereqs)) \
	    com.puppycrawl.tools.checkstyle.Main \
	    -c lib/checkstyle/checkstyle.xml \
	    $(foreach project,$(checkable-projects),\
		$(call project-static-java-sources,$(project)/main) \
		$(call project-static-java-sources,$(project)/test) \
		$(call project-static-java-sources,$(project)/benchmark))
	@touch $@

build/sonar.config: Makefile projects.mk | build 
	@echo sonar.projectKey=personal_search >> $@.try
	@echo sonar.projectName=Personal Search >> $@.try
	@echo -n sonar.projectVersion= >> $@.try
	@TZ=UTC date -d @$$(git log -n1 --pretty=format:'%ct') +%Y.%m.%d-%H.%M.%S+ | tr -d '\n' >> $@.try
	@git log -n1 --pretty=format:'%h' >> $@.try
	@echo >> $@.try
	@echo >> $@.try
	@echo sonar.java.binaries=./build >> $@.try
	@echo sonar.sources=./src >> $@.try
	@echo sonar.java.libraries=./lib/*.jar >> $@.try
	@echo >> $@.try
	@echo -n sonar.modules= >> $@.try
	@ls src | while read project; do \
	    echo -n $$project, >> $@.try; \
	done;
	@echo >> $@.try
	@echo >> $@.try
	@echo sonar.jacoco.reportPath=./build/report/coverage/jacoco.exec >> $@.try
	@echo >> $@.try
	@ls src | while read project; do \
	    echo $$project.sonar.projectBaseDir=. >> $@.try; \
	    echo $$project.sonar.inclusions=**/$$project/main/java/ru/yandex/**/*.java >> $@.try; \
	    echo $$project.sonar.binaries=./build/$$project >> $@.try; \
	    echo $$project.sonar.projectName=$$project >> $@.try; \
	    echo >> $@.try; \
        done;
	@echo sonar.sourceEncoding=UTF-8 >> $@.try
	@mv -f $@.try $@
	@ln -sf $@ ./sonar-project.properties

build/projects-checkstyle: $(projects-static-sources)\
    build/projects-checkstyle/main/classes
	@echo "[Performing projects checkstyle]"
	@$(JAVA) $(JAVA_OPTS) -cp build/projects-checkstyle/main/classes \
	    ru.yandex.tools.checkstyle.projects.Main
	@touch $@

coverage: build/report/coverage/index.html

build/report/coverage/index.html: build/coverage-builder.jar\
    $(projects-main-classes) $(projects-execs)
	@echo "[Building code coverage report]"
	-@rm -rf build/report/coverage
	@$(JAVA) $(JAVA_OPTS) -cp $(subst $(space),:,\
	    $(call project-all-libs,coverage-builder,main) \
	    build/coverage-builder.jar \
	    $(patsubst %,build/%/main/classes,$(projects-with-tests))): \
	    ru.yandex.tools.jacoco.Coverage \
	    $(projects)

findbugs: build/spotbugs

build/spotbugs: $(spotbugs-libs) $(spotbugs-jar) lib/spotbugsfilter.xml\
    $(projects-main-classes) $(projects-main-libs)
	@echo "[Searching for bugs]"
	@$(JAVA) $(JAVA_OPTS) -cp $(subst $(space),:,$(spotbugs-libs)) -jar \
	    $(spotbugs-jar) -textui -effort:max -exitcode \
	    -low -exclude lib/spotbugsfilter.xml -auxclasspath \
	    $(subst $(space),:,$(projects-main-libs) $(uncheckable-classes)) \
	    $(checkable-classes)
	@touch $@

install: $(projects-installs)

$(projects-installs): %-install: %
	@echo "[Installing $*]"
	-@rm -rf $(call DEST,$*)
	@mkdir -p $(call DEST,$*)
	@$(foreach x,$(call project-jar,$*) $(call project-all-libs,$*,main),\
	    cp $(x) $(call DEST,$*);)
	@echo -n "Class-Path:" > $(call DEST,$*)/$*.manifest
	@$(foreach x,$(notdir $(call project-all-libs,$*,main)), \
	    echo "  $(x)" >> $(call DEST,$*)/$*.manifest;)
	@test -z "$(call project-jar,$*)" || \
	    $(JAR) umf $(call DEST,$*)/$*.manifest $(call DEST,$*)/$*.jar
	@$(foreach x,$(call project-all-dlls,$*,main),cp $(x) $(call DEST,$*);)
	@rm -f $(call DEST,$*)/$*.manifest

$(projects-instancectl-uploads): %-instancectl-upload: src/%/main/bundle/instancectl.conf
	@cd "src/$*/main/bundle" && \
	    sandbox-upload -t PERSONAL_SEARCH_DAEMON -d \
		$*-instancectl.conf-$$(git log -n1 --pretty=format:"%h") \
		-A 'ttl=inf' -a any instancectl.conf

$(projects-uploads): %-upload: %-bundle
	@cd "$$(dirname $(call BUNDLE,$*))" && \
	    sandbox-upload -t PERSONAL_SEARCH_DAEMON -d \
		$*-$$(git log -n1 --pretty=format:"%h") \
		-A 'ttl=inf' -a any $*-bundle.tar.gz

benchmark: $(projects-benchmarks)

$(projects-benchmarks): %-benchmark: build/%/benchmark/classes

.SECONDEXPANSION:

$(projects): %: $$(call project-jar,%) \
    $$(foreach project,% $$(call project-deps,%,main),\
    $$(call project-execs,$$(project))) checkstyle findbugs

$(projects-bundles): %-bundle : %-install src/scripts/bin_with_preload.sh \
    src/scripts/java.sh \
    build/libldpreload.so \
    build/minigzip \
    $$(call project-bundles-sources,%)
	@echo "[Packaging $*]"
	-@rm -rf $(call BUNDLE,$*) $(call BUNDLE,$*).tar.gz $(call BUNDLE,$*).tar.gz.try
	@mkdir -p "$$(dirname $(call BUNDLE,$*))"
	@cp -r -L $(call DEST,$*) $(call BUNDLE,$*)
	@cp src/scripts/bin_with_preload.sh $(call BUNDLE,$*)
	@cp src/scripts/java.sh $(call BUNDLE,$*)
	@cp build/libldpreload.so $(call BUNDLE,$*)
	@cp build/minigzip $(call BUNDLE,$*)
	@for bundle in $(call project-bundles,$*); do \
	    cp -r -L $$bundle/* $(call BUNDLE,$*); done
	@tar --exclude instancectl.conf -czC "$$(dirname $(call BUNDLE,$*))" \
	    -f $(call BUNDLE,$*).tar.gz.try $$(basename $(call BUNDLE,$*))
	@mv $(call BUNDLE,$*).tar.gz.try $(call BUNDLE,$*).tar.gz

$(projects-jars): build/%.jar: \
    $$(call project-all-resources,%,main) $$(call project-all-main-classes,%)
	@echo "[Preparing $@]"
	-@rm -f $@.try $@.keep
	@touch $@.keep
	@$(JAR) cMf $@.try $(subst build/,-C build/ ,$@.keep)
	@for i in $(call project-all-main-classes,$*) \
	    $(foreach project,$(call project-deps,$*,main) $*,\
	    $(wildcard src/$(project)/main/resources));do \
	    $(JAR) uMf $@.try -C $$i . || exit 1; done
	@rm -f $@.keep
	@mv $@.try $@

$(projects-main-classes): build/%/main/classes: \
    $$(call project-java-sources,%/main) \
    $$(call project-all-libs,%,main)\
    $$(call project-all-dlls,%,main)\
    $$(call project-main-classes,%)
	@echo "[Compiling $*]"
	-@rm -rf build/$*/main/classes build/$*/main/try.classes
	@mkdir -p build/$*/main/try.classes
	@$(JAVAC) $(call JAVAC_OPTS,$*) $(addprefix -cp ,\
	    $(subst $(space),:,$(strip $(call project-all-libs,$*,main) \
		$(call project-main-classes,$*)))) \
	    -d build/$*/main/try.classes \
	    $(filter-out \
		$(call project-javacc-generated-sources,$*/main) \
		$(call project-jute-generated-sources,$*/main) \
		$(call project-protobuf-generated-sources,$*/main),\
		$(call project-java-sources,$*/main)) \
	    $(wildcard $(addsuffix /*.java,$(dir \
		$(call project-javacc-generated-sources,$*/main)))) \
	    $(call dirs-listing,\
		$(dir $(call project-jute-generated-sources,$*/main)),\
		-type f -name \*.java) \
	    $(call dirs-listing,\
		$(dir $(call project-protobuf-generated-sources,$*/main)),\
		-type f -name \*.java)
	@mv build/$*/main/try.classes build/$*/main/classes

$(projects-benchmark-classes): build/%/benchmark/classes: \
    build/%.jar $$(call project-java-sources,%/benchmark) \
    $$(call project-all-libs,%,benchmark)\
    $$(call project-all-dlls,%,benchmark)\
    $$(call project-main-classes,%) \
    $$(addprefix build/,$$(addsuffix /test/classes,\
	$$(filter $(projects-with-tests),%)))
	@echo "[Compiling benchmark for $*]"
	-@rm -rf build/$*/benchmark/classes build/$*/benchmark/try.classes
	@mkdir -p build/$*/benchmark/try.classes
	@$(JAVAC) $(call JAVAC_OPTS,$*) $(addprefix -cp ,\
	    $(subst $(space),:,$(strip $(call project-all-libs,$*,main) \
		$(call project-all-libs,$*,main) \
		$(wildcard build/$*/test/classes) $(junit) build/$*.jar \
		$(foreach project,\
		    $(call project-deps,$*,main) $(call project-deps,$*,test) \
		    $(call project-deps,$*,benchmark),\
		    build/$(project)/main/classes)))) \
	    -d build/$*/benchmark/try.classes \
	    $(filter-out \
		$(call project-javacc-generated-sources,$*/benchmark) \
		$(call project-protobuf-generated-sources,$*/benchmark) \
		$(call project-jute-generated-sources,$*/benchmark),\
		$(call project-java-sources,$*/benchmark)) \
	    $(wildcard $(addsuffix /*.java,$(dir \
		$(call project-javacc-generated-sources,$*/benchmark))))\
	    $(call dirs-listing,\
		$(dir $(call project-jute-generated-sources,$*/benchmark)),\
		-type f -name \*.java) \
	    $(call dirs-listing,\
		$(dir $(call project-protobuf-generated-sources,$*/benchmark)),\
		-type f -name \*.java)
	@mv build/$*/benchmark/try.classes build/$*/benchmark/classes

$(projects-javacc-generated-sources): build/%/.fake: \
    $$(wildcard src/$$(subst /java/,/javacc/,%)/*.jj)
	@echo "[JavaCC processing $<]"
	-@rm -rf $(dir $@)
	@$(JAVACC) -OUTPUT_DIRECTORY:$(dir $@) \
	    $(wildcard src/$(subst /java/,/javacc/,$*)/*.jj)
	@touch $@

$(projects-jflex-generated-sources): build/%.java: \
    src/$$(subst /java/,/jflex/,%).lex
	@echo "[JFlex processing $<]"
	@mkdir -p $@.try
	@$(JAVA) $(JAVA_OPTS) -jar lib/jflex-full-1.7.0.jar \
	    --nobak -q -d $@.try $<
	@mv $@.try/$(notdir $@) $@
	@rmdir $@.try

$(projects-jute-generated-sources): build/%/.fake: \
    src/$$(subst /java/,/jute/,%) build/jute.jar
	@echo "[Jute processing $<]"
	-@rm -rf $(dir $@)
	@mkdir -p $(dir $@)
	@cd $(dir $@) && $(JAVA) $(JAVA_OPTS) -cp ../../../../jute.jar \
	    org.apache.jute.compiler.generated.Rcc -l java \
	    ../../../../../$<
	@touch $@

$(projects-protobuf-generated-sources): build/%/.fake: \
    src/$$(subst /java/,/protobuf/,%)
	@echo "[Protobuf processing $<]"
	-@rm -rf $(dir $@)
	@mkdir -p $(dir $@)
	@$(PROTOC) --java_out=$(dir $@) -I$(dir $<) -Isrc/protobuf/main/protobuf $<
	@touch $@

$(projects-ragel-generated-sources): build/%.java: \
    src/$$(subst /java/,/ragel/,%).rl
	@echo "[Ragel processing $<]"
	@mkdir -p $(dir $@)
	@ragel -J -o $@.try $<
	@mv $@.try $@

$(foreach project,$(projects-with-tests),build/$(project)/test/classes): \
    build/%/test/classes: $(junit) $$(call project-java-sources,%/test) \
	$$(call project-all-libs,%,test)\
	$$(call project-all-dlls,%,test)\
	build/%.jar $$(call project-test-classes,%) \
	$$(foreach project,$$(call project-deps,%,test),\
	    $$(wildcard src/$$(project)/main/resources))
	@echo "[Compiling tests for $*]"
	-@rm -rf build/$*/test/classes build/$*/test/try.classes
	@mkdir -p build/$*/test/try.classes
	@$(JAVAC) $(call JAVAC_OPTS,$*) $(addprefix -cp ,\
	    $(subst $(space),:,$(strip $(call project-all-libs,$*,test) \
		$(junit) build/$*.jar $(call project-test-classes,$*) \
		$(foreach project,$(call project-deps,$*,test),\
		    $(wildcard src/$(project)/main/resources))))) \
	    -d build/$*/test/try.classes \
	    $(filter-out \
		$(call project-javacc-generated-sources,$*/test) \
		$(call project-protobuf-generated-sources,$*/test) \
		$(call project-jute-generated-sources,$*/test),\
		$(call project-java-sources,$*/test)) \
	    $(wildcard $(addsuffix /*.java,$(dir \
		$(call project-javacc-generated-sources,$*/test))))\
	    $(call dirs-listing,\
		$(dir $(call project-jute-generated-sources,$*/test)),\
		-type f -name \*.java) \
	    $(call dirs-listing,\
		$(dir $(call project-protobuf-generated-sources,$*/test)),\
		-type f -name \*.java)
	@mv build/$*/test/try.classes build/$*/test/classes

$(projects-execs): build/report/%.exec: lib/jacocoagent-$(jacoco-version).jar \
    build/$$(firstword $$(subst /, ,%))/test/classes \
    build/$$(firstword $$(subst /, ,%)).jar \
    $$(call project-resources,$$(firstword $$(subst /, ,%))/test) \
    $$(call project-all-dlls,$$(firstword $$(subst /, ,%)),test) \
    $$(call project-bundles-sources,$$(firstword $$(subst /, ,%)),test)
	@echo "[Executing test $*]"
	-@rm -rf $@ $@.try $@.txt $@.txt.try
	@mkdir -p $(dir $@)
	@begin=`date +%s%N` && \
	LANG=en_US.UTF-8 $(JAVA) $(JAVA_OPTS) $(JAVA_TEST_OPTS) \
	    -javaagent:lib/jacocoagent-$(jacoco-version).jar=destfile=$@.try \
	    -Djava.io.tmpdir=$(dir $@) \
	    $(addprefix -Djava.library.path=,$(subst $(space),:,\
		$(sort $(foreach dll,\
		$(call project-all-dlls,$(firstword $(subst /, ,$*)),test),\
		$(dir $(dll)))))) \
	    -cp $(subst $(space),:,$(strip $(junit) $(foreach project,\
		$(firstword $(subst /, ,$*)), build/$(project).jar \
		build/$(project)/test/classes src/$(project)/test/resources \
		$(call project-all-libs,$(project),test)\
		$(foreach dep,\
		    $(filter-out $(call project-deps,$(project),main),\
			$(call project-deps,$(project),test)),\
		    build/$(dep)/main/classes \
		    $(wildcard src/$(dep)/main/resources))))) \
	    $(strip $(foreach project,$(firstword $(subst /, ,$*)) \
		$(call project-deps,$(firstword $(subst /, ,$*)),test),\
		$($(project)-java-opts))) \
	    org.junit.runner.JUnitCore \
	    $(patsubst %.exec,%,$(lastword $(subst /, ,$*))) >$@.txt.try 2>&1 \
	    && \
	end=`date +%s%N` && \
	time=`expr '(' $$end - $$begin ')' / 1000000` && \
	name=`echo $*|sed 's/.*[.]//'` && \
	printf '%-32s completed in %6d ms\n' $$name $$time
	@mv $@.txt.try $@.txt
	@mv $@.try $@

build/zlib: Makefile projects.mk
ifeq ($(ALLOW_CLONE), true)
	-@rm -rf build/zlib build/zlib.try
	@git clone https://github.com/madler/zlib build/zlib.try        
	@mv build/zlib.try build/zlib
endif

build/zlib_fast: Makefile projects.mk
ifeq ($(ALLOW_CLONE), true)
	-@rm -rf build/zlib_fast build/zlib_fast.try
	@git clone https://github.com/cloudflare/zlib build/zlib_fast.try
	@cd build/zlib_fast.try && ./configure
	@mv build/zlib_fast.try build/zlib_fast
endif

build/zstd: Makefile projects.mk
ifeq ($(ALLOW_CLONE), true)
	-@rm -rf build/zstd build/zstd.try
	@git clone --branch v0.7.5 --depth 1 https://github.com/Cyan4973/zstd build/zstd.try
	@mv build/zstd.try build/zstd
endif

build/sqlite: Makefile projects.mk
	-@rm -rf build/sqlite build/sqlite.try
ifeq ($(ALLOW_CLONE), true)
	@wget --no-check-certificate -O build/sqlite.tar.gz https://www.sqlite.org/2019/sqlite-autoconf-3270200.tar.gz
endif
	@cd build && tar xvf sqlite.tar.gz && mv sqlite-autoconf-3270200 sqlite.try
	@cd build/sqlite.try && CFLAGS= ./configure --prefix=$(shell pwd)/build/sqlite.try && make install
	@cp build/sqlite.try/lib/libsqlite3* build/
	@mv build/sqlite.try build/sqlite

build/libsqlite-cache.so: build/sqlite src/sqlite-cache/sqlite-cache.c src/sqlite-cache/sqlite-cache2.c
	@echo "[Building libsqlite-cache.so]"
	-@rm -rf build/libsqlite-cache-unstripped.so build/libsqlite-cache.so
	@$(CC) -std=c99 -Duint="unsigned int" -Ibuild/sqlite/include \
	    $(CFLAGS) $(LDFLAGS) \
	    -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes \
	    -shared \
	    build/sqlite/.libs/sqlite3.o \
	    src/sqlite-cache/sqlite-cache.c src/sqlite-cache/sqlite-cache2.c \
	    -o build/libsqlite-cache-unstripped.so
	@mv build/libsqlite-cache-unstripped.so build/libsqlite-cache.so

build/liblmdb-cache.so: src/lmdb-cache/lmdb-cache.c src/lmdb-cache/mdb.c src/lmdb-cache/midl.c
	@echo "[Building liblmdb-cache.so]"
	-@rm -rf build/liblmdb-cache-unstripped.so build/liblmdb-cache.so
	@$(CC) -Isrc/lmdb-cache/ \
	    $(CFLAGS) $(LDFLAGS) \
	    -W -Wall -Wno-unused-parameter -Wbad-function-cast -Wuninitialized \
	    -shared \
	    src/lmdb-cache/lmdb-cache.c \
	    src/lmdb-cache/mdb.c src/lmdb-cache/midl.c \
	    -o build/liblmdb-cache-unstripped.so
	@mv build/liblmdb-cache-unstripped.so build/liblmdb-cache.so

#	    build/sqlite/lib/libsqlite3.a \
#	@strip -s build/libsqlite-cache-unstripped.so

build/libzlib_fast.so: build/zlib_fast src/compress/zlib_fast.c
	@echo "[Building libzlib_fast.so]"
	-@rm -rf build/libzlib_fast-unstripped.so build/libzlib_fast.so
	@$(CC) -std=c90 -Duint="unsigned int" -Ibuild/zlib_fast \
	    $(CFLAGS) $(ZLIB_FAST_CFLAGS) $(LDFLAGS) \
	    -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes \
	    -shared \
	    build/zlib_fast/*.c \
	    build/zlib_fast/contrib/amd64/crc32-pclmul_asm.S \
	    src/compress/zlib_fast.c \
	    -o build/libzlib_fast-unstripped.so
	@strip -s build/libzlib_fast-unstripped.so
	@mv build/libzlib_fast-unstripped.so build/libzlib_fast.so

build/minigzip: build/zlib_fast/test/minigzip.c
	@echo "[Building minigzip]"
	-@rm -rf $@ $@.try
	@$(CC) -std=c90 -Duint="unsigned int" -Ibuild/zlib_fast \
	    $(CFLAGS) $(ZLIB_FAST_CFLAGS) $(LDFLAGS) \
	    -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes \
	    $< build/zlib_fast/*.c \
	    build/zlib_fast/contrib/amd64/crc32-pclmul_asm.S \
	    -o $@.try
	@mv $@.try $@

build/libcompress.so: \
    build/libzlib_fast.so build/zlib build/zstd \
    src/compress/compress.h src/compress/main.c src/compress/lzma.c \
    src/compress/Inflater.c \
    src/compress/Deflater.c src/compress/jlong_md.h src/compress/jni_util.h
	@echo "[Building $@]"
	-@rm -rf $@
	@$(CC) -std=c99 -Ibuild/zstd/lib -Ibuild/zstd/lib/common \
	    -Ibuild/zlib -Isrc/compress/lzma/ \
	    $(CFLAGS) $(LDFLAGS) \
	    -DZSTD_LEGACY_SUPPORT=0 \
	    -D_7ZIP_ST \
	    -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes \
	    -shared build/zlib/*.c \
	    build/zstd/lib/compress/zstd_compress.c \
	    build/zstd/lib/decompress/zstd_decompress.c \
	    build/zstd/lib/compress/huf_compress.c \
	    build/zstd/lib/decompress/huf_decompress.c \
	    build/zstd/lib/compress/fse_compress.c \
	    build/zstd/lib/common/fse_decompress.c \
	    build/zstd/lib/common/zstd_common.c \
	    build/zstd/lib/common/entropy_common.c \
	    build/zstd/lib/common/xxhash.c \
	    src/compress/lzma/*.c \
	    src/compress/lzma.c \
	    src/compress/main.c \
	    src/compress/Deflater.c \
	    src/compress/Inflater.c \
	    -lcrypto -lssl -ldl \
	    -o build/libcompress-unstripped.so
	@strip -s build/libcompress-unstripped.so
	@mv build/libcompress-unstripped.so $@

build/libjniwrapper-main.so build/libjniwrapper-test.so: \
    build/libjniwrapper-%.so: src/jniwrapper/%.c
	@echo "[Building $@]"
	-@rm -rf $@
	@$(CC) -std=c99 $(CFLAGS) $(LDFLAGS) -Werror -Wall -Wextra \
	    -shared src/jniwrapper/$*.c \
	    -o build/libjniwrapper-$*-unstripped.so
	@strip -s build/libjniwrapper-$*-unstripped.so
	@mv build/libjniwrapper-$*-unstripped.so $@

build/libldpreload.so: src/ldpreload/ldpreload.c
	@echo "[Building libldpreload.so]"
	@rm -rf $@
	@$(CC) -std=c99 $(CFLAGS) $(LDFLAGS) -ldl -nostartfiles -shared \
	    -Wall -Wextra -Wundef -Wshadow -Wcast-align -Wstrict-prototypes \
	    -o build/libldpreload-unstripped.so src/ldpreload/ldpreload.c
	@strip -s build/libldpreload-unstripped.so
	@mv build/libldpreload-unstripped.so $@

build/libfast-md5.so: src/fast-md5/MD5.c
	@echo "[Building $@]"
	-@rm -rf $@
	@$(CC) -std=c99 $(CFLAGS) $(LDFLAGS) -Werror -Wall -Wextra \
	    -shared src/fast-md5/MD5.c -o build/libfast-md5-unstripped.so
	@mv build/libfast-md5-unstripped.so $@

build/projects.dot: Makefile projects.mk | build
	-@rm -f $@.try
	@echo "digraph projects {" > $@.try
	@echo $(foreach project,$(projects),\
	    $(foreach dep,$($(project)-main-deps),\
		'"'$(project)'" -> "'$(dep)'";')) >> $@.try
	@echo "}" >> $@.try
	@mv -f $@.try $@

