# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
#
# This file is part of the thin-provisioning-tools source.
#
# thin-provisioning-tools is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# thin-provisioning-tools is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with thin-provisioning-tools.  If not, see
# <http://www.gnu.org/licenses/>.

V=@

PROGRAMS=\
	bin/pdata_tools

ifeq ("@TESTING@", "yes")
TESTLIBS=\
	lib/libft.so
endif

.PHONY: all
all: $(PROGRAMS) $(TESTLIBS)

include contrib/Makefile

SOURCE=\
	base/output_file_requirements.cc \
	base/application.cc \
	base/base64.cc \
	base/disk_units.cc \
	base/endian_utils.cc \
	base/error_state.cc \
	base/error_string.cc \
	base/grid_layout.cc \
	base/io_generator.cc \
	base/file_utils.cc \
	base/progress_monitor.cc \
	base/rolling_hash.cc \
	base/sequence_generator.cc \
	base/xml_utils.cc \
	block-cache/block_cache.cc \
	block-cache/copier.cc \
	block-cache/io_engine.cc \
	block-cache/mem_pool.cc \
	caching/cache_check.cc \
	caching/cache_dump.cc \
	caching/cache_metadata_size.cc \
	caching/cache_repair.cc \
	caching/cache_restore.cc \
	caching/cache_writeback.cc \
	caching/commands.cc \
	caching/hint_array.cc \
	caching/mapping_array.cc \
	caching/metadata.cc \
	caching/metadata_dump.cc \
	caching/restore_emitter.cc \
	caching/superblock.cc \
	caching/xml_format.cc \
	era/commands.cc \
	era/era_array.cc \
	era/era_check.cc \
	era/era_detail.cc \
	era/era_dump.cc \
	era/era_invalidate.cc \
	era/era_restore.cc \
	era/metadata.cc \
	era/metadata_dump.cc \
	era/restore_emitter.cc \
	era/superblock.cc \
	era/writeset_tree.cc \
	era/xml_format.cc \
	main.cc \
	persistent-data/block.cc \
	persistent-data/checksum.cc \
	persistent-data/data-structures/bitset.cc \
	persistent-data/data-structures/bloom_filter.cc \
	persistent-data/data-structures/btree.cc \
	persistent-data/data-structures/btree_damage_visitor.cc \
	persistent-data/data-structures/btree_node_checker.cc \
	persistent-data/error_set.cc \
	persistent-data/file_utils.cc \
	persistent-data/hex_dump.cc \
	persistent-data/space-maps/careful_alloc.cc \
	persistent-data/space-maps/core.cc \
	persistent-data/space-maps/disk.cc \
	persistent-data/space-maps/recursive.cc \
	persistent-data/space_map.cc \
	persistent-data/transaction_manager.cc \
	persistent-data/validators.cc \
	thin-provisioning/commands.cc \
	thin-provisioning/cache_stream.cc \
	thin-provisioning/chunk_stream.cc \
	thin-provisioning/device_tree.cc \
	thin-provisioning/fixed_chunk_stream.cc \
	thin-provisioning/human_readable_format.cc \
	thin-provisioning/mapping_tree.cc \
	thin-provisioning/metadata.cc \
	thin-provisioning/metadata_checker.cc \
	thin-provisioning/metadata_counter.cc \
	thin-provisioning/metadata_dumper.cc \
	thin-provisioning/override_emitter.cc \
	thin-provisioning/pool_stream.cc \
	thin-provisioning/restore_emitter.cc \
	thin-provisioning/rmap_visitor.cc \
	thin-provisioning/superblock.cc \
	thin-provisioning/thin_check.cc \
	thin-provisioning/thin_delta.cc \
	thin-provisioning/thin_dump.cc \
	thin-provisioning/thin_ls.cc \
	thin-provisioning/thin_metadata_size.cc \
	thin-provisioning/thin_pool.cc \
	thin-provisioning/thin_repair.cc \
	thin-provisioning/thin_restore.cc \
	thin-provisioning/thin_rmap.cc \
	thin-provisioning/thin_trim.cc \
	thin-provisioning/xml_format.cc

DEVTOOLS_SOURCE=\
	thin-provisioning/damage_generator.cc \
	thin-provisioning/thin_journal.cc \
	thin-provisioning/thin_journal_check.cc \
	thin-provisioning/thin_ll_dump.cc \
	thin-provisioning/thin_ll_restore.cc \
	thin-provisioning/thin_show_duplicates.cc \
	thin-provisioning/thin_generate_damage.cc \
	thin-provisioning/thin_generate_metadata.cc \
	thin-provisioning/thin_generate_mappings.cc \
	thin-provisioning/variable_chunk_stream.cc \
	thin-provisioning/thin_show_metadata.cc \
	thin-provisioning/thin_scan.cc \
	ui/ui.cc

ifeq ("@DEVTOOLS@", "yes")
SOURCE+=$(DEVTOOLS_SOURCE)
endif

ifeq ("@STATIC@", "yes")
SOURCE += thin-provisioning/static_library_emitter.cc
else
SOURCE += thin-provisioning/shared_library_emitter.cc
endif

CC:=@CC@
CXX:=@CXX@
AR:=@AR@
STRIP:=@STRIP@
OBJECTS:=$(subst .cc,.o,$(SOURCE))

ifeq ("@STATIC@", "yes")
EMITTERS += $(PLUGIN_LIBS)
endif

TOP_DIR:=@top_srcdir@
TOP_BUILDDIR:=@top_builddir@
CFLAGS+=-g -Wall -O3 -fPIC
CFLAGS+=@LFS_FLAGS@
CXXFLAGS+=-g -Wall -fPIC -fno-strict-aliasing -std=c++11

ifeq ("@DEVTOOLS@", "yes")
CXXFLAGS+=-DDEV_TOOLS
endif

CXXFLAGS+=@CXXOPTIMISE_FLAG@
CXXFLAGS+=@CXXDEBUG_FLAG@
CXXFLAGS+=@CXX_STRERROR_FLAG@
CXXFLAGS+=@LFS_FLAGS@
INCLUDES+=-I$(TOP_BUILDDIR) -I$(TOP_DIR) -I$(TOP_DIR)/thin-provisioning
LIBS:=-laio -lexpat -lboost_iostreams -ldl

ifeq ("@DEVTOOLS@", "yes")
LIBS+=-lncurses
endif

ifeq ("@STATIC_CXX@", "yes")
CXXLIB+=-Wl,-Bstatic -lstdc++ -Wl,-Bdynamic -Wl,--as-needed
else
CXXLIB+=-lstdc++
endif

ifeq ("@STATIC@", "yes")
LDFLAGS+=-static
endif

INSTALL:=@INSTALL@
PREFIX:=@prefix@
BINDIR:=$(DESTDIR)$(PREFIX)/sbin
DATADIR:=$(DESTDIR)$(PREFIX)/share
MANPATH:=$(DATADIR)/man

vpath %.cc $(TOP_DIR)

INSTALL_DIR = $(INSTALL) -m 755 -d
INSTALL_PROGRAM = $(INSTALL) -m 755
INSTALL_DATA = $(INSTALL) -p -m 644

ifeq ("@TESTING@", "yes")
TEST_INCLUDES=\
	-I$(TOP_DIR) \
	-Igoogletest/googlemock/include \
	-Igoogletest/googletest/include
else
TEST_INCLUDES=
endif

.SUFFIXES: .d .txt .8

%.o: %.cc
	@echo "    [CXX] $<"
	@mkdir -p $(dir $@)
	$(V) $(CXX) -c $(INCLUDES) $(CXXFLAGS) -o $@ $<
	$(V) $(CXX) -MM -MT $(subst .cc,.o,$<) $(INCLUDES) $(TEST_INCLUDES) $(CXXFLAGS) $< > $*.$$$$; \
	sed 's,\([^ :]*\)\.o[ :]*,\1.o \1.gmo $* : Makefile ,g' < $*.$$$$ > $*.d; \
	$(RM) $*.$$$$

%.o: %.c
	@echo "    [CC] $<"
	@mkdir -p $(dir $@)
	$(V) $(CC) -c $(INCLUDES) $(CFLAGS) -o $@ $<
	$(V) $(CC) -MM -MT $(subst .cc,.o,$<) $(INCLUDES) $(TEST_INCLUDES) $(CFLAGS) $< > $*.$$$$; \
	sed 's,\([^ :]*\)\.o[ :]*,\1.o \1.gmo $* : Makefile ,g' < $*.$$$$ > $*.d; \
	$(RM) $*.$$$$

%.8: %.txt bin/txt2man
	@echo "    [txt2man] $<"
	@mkdir -p $(dir $@)
	$(V) bin/txt2man -p -t $(basename $(notdir $<)) $< > $@

#----------------------------------------------------------------

lib/libpdata.a: $(OBJECTS) $(EMITTERS)
	@echo "    [AR]  $<"
	@mkdir -p $(dir $@)
	$(V)$(AR) -rv $@ $(OBJECTS) $(EMITTERS) > /dev/null 2>&1

bin/pdata_tools: $(OBJECTS) $(EMITTERS)
	@echo "    [LD]  $@"
	@mkdir -p $(dir $@)
	$(V) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $+ $(LIBS) $(CXXLIB)

#----------------------------------------------------------------

DEPEND_FILES=\
	$(subst .cc,.d,$(SOURCE)) \
	$(subst .cc,.d,$(TEST_SOURCE)) \
	$(subst .cc,.d,$(CXX_PROGRAM_SOURCE)) \
	$(subst .c,.d,$(C_PROGRAM_SOURCE))

.PHONY: clean distclean

clean:
	find . -name \*.o -delete
	find . -name \*.gmo -delete
	find . -name \*.d -delete
	$(RM) $(TEST_PROGRAMS) $(PROGRAMS) $(GMOCK_OBJECTS) lib/*.a lib/*.so

distclean: clean
	$(RM) config.cache config.log config.status configure.h version.h Makefile unit-tests/Makefile

TOOLS:=\
	cache_check \
	cache_dump \
	cache_metadata_size \
	cache_repair \
	cache_restore \
	cache_writeback \
	thin_check \
	thin_delta \
	thin_dump \
	thin_ls \
	thin_repair \
	thin_restore \
	thin_rmap \
	thin_metadata_size \
	thin_trim \
	era_check \
	era_dump \
	era_invalidate \
	era_restore

MANPAGES:=$(patsubst %,man8/%.8,$(TOOLS))

install: bin/pdata_tools $(MANPAGES)
	$(INSTALL_DIR) $(BINDIR)
	$(INSTALL_PROGRAM) bin/pdata_tools $(BINDIR)
	$(STRIP) $(BINDIR)/pdata_tools
	ln -s -f pdata_tools $(BINDIR)/cache_check
	ln -s -f pdata_tools $(BINDIR)/cache_dump
	ln -s -f pdata_tools $(BINDIR)/cache_metadata_size
	ln -s -f pdata_tools $(BINDIR)/cache_repair
	ln -s -f pdata_tools $(BINDIR)/cache_restore
	ln -s -f pdata_tools $(BINDIR)/cache_writeback
	ln -s -f pdata_tools $(BINDIR)/thin_check
	ln -s -f pdata_tools $(BINDIR)/thin_delta
	ln -s -f pdata_tools $(BINDIR)/thin_dump
	ln -s -f pdata_tools $(BINDIR)/thin_ls
	ln -s -f pdata_tools $(BINDIR)/thin_repair
	ln -s -f pdata_tools $(BINDIR)/thin_restore
	ln -s -f pdata_tools $(BINDIR)/thin_rmap
	ln -s -f pdata_tools $(BINDIR)/thin_metadata_size
	ln -s -f pdata_tools $(BINDIR)/thin_trim
	ln -s -f pdata_tools $(BINDIR)/era_check
	ln -s -f pdata_tools $(BINDIR)/era_dump
	ln -s -f pdata_tools $(BINDIR)/era_invalidate
	ln -s -f pdata_tools $(BINDIR)/era_restore
	$(INSTALL_DIR) $(MANPATH)/man8
	$(INSTALL_DATA) man8/cache_check.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/cache_dump.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/cache_metadata_size.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/cache_repair.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/cache_restore.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/cache_writeback.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_check.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_delta.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_dump.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_ls.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_repair.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_restore.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_rmap.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_metadata_size.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/era_check.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/era_dump.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/era_restore.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/era_invalidate.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_trim.8 $(MANPATH)/man8
ifeq ("@DEVTOOLS@", "yes")
	ln -s -f pdata_tools $(BINDIR)/thin_show_duplicates
	ln -s -f pdata_tools $(BINDIR)/thin_ll_dump
	ln -s -f pdata_tools $(BINDIR)/thin_show_duplicates
	ln -s -f pdata_tools $(BINDIR)/thin_generate_metadata
	ln -s -f pdata_tools $(BINDIR)/thin_scan
endif

.PHONY: install install-rust-tools rust-tools

rust-tools:
	cargo build --release

install-rust-tools: man8/thin_metadata_pack.8 man8/thin_metadata_unpack.8 rust-tools
	$(INSTALL_PROGRAM) target/release/thin_metadata_pack  $(BINDIR)
	$(INSTALL_PROGRAM) target/release/thin_metadata_unpack  $(BINDIR)
	$(STRIP) $(BINDIR)/thin_metadata_pack
	$(STRIP) $(BINDIR)/thin_metadata_unpack
	$(INSTALL_DATA) man8/thin_metadata_pack.8 $(MANPATH)/man8
	$(INSTALL_DATA) man8/thin_metadata_unpack.8 $(MANPATH)/man8

ifeq ("@TESTING@", "yes")
include unit-tests/Makefile

LIBFT_SOURCE=\
	ft-lib/bcache.c \
	ft-lib/crc32c.c \
	ft-lib/dm-ioctl.c

LIBFT_OBJECTS=$(subst .c,.o,$(LIBFT_SOURCE))

lib/libft.so: $(LIBFT_OBJECTS)
	@echo "    [LD]" $@
	$(V) gcc -shared -o $@ $+ -laio

.PHONEY: functional-test unit-test

functional-test: bin/pdata_tools lib/libft.so
	cd functional-tests && ./run-tests run

test: functional-test unit-test
endif

-include $(DEPEND_FILES)

