# ================================================================
# NOTE: This makefile is not intended to be used in a packaging system --
# rather, Miller uses autconfig for that. This makefile is intended for users
# who prefer (for whatever reason) to bypass autoconfig.  Please also see
# http://johnkerl.org/miller/doc/build.html#Without_using_autoconfig
# ================================================================

# ================================================================
# Travis does "export CC=gcc", "export CC=clang" so we can pick those up via
# "make -e" in ../.travis.yml.  Note that "CC?=gcc", without make -e, results
# in CC being expanded to cc on my OSX laptop, which is not OK.  Hence make -e.
CC=gcc
CFLAGS=-std=gnu99
IFLAGS=-I. -I..

WFLAGS=-Wall -Werror
# Worth exploring ... but needs handling for unused parameters in functions which comply with interfaces.
# Best option I'm aware of is to replace "void foo(int bar) {...}" with "void foo(int) {...}" throughout.
# WFLAGS=-Wall -Wextra -Werror
# WFLAGS=-Wall -Wextra -pedantic-errors -Werror
# WFLAGS=-Wall -Wextra -pedantic-errors -Werror=unused-variable

LFLAGS=-lm

# You can do make -e INSTALLDIR=/path/to/somewhere/else/bin
INSTALLDIR=/usr/local/bin

CCOPT=$(CC) $(CFLAGS) $(IFLAGS) $(WFLAGS) -O3
#CCDEBUG=$(CC) -g -O1 $(CFLAGS) $(IFLAGS) $(WFLAGS)
CCDEBUG=$(CC) -g $(CFLAGS) $(IFLAGS) $(WFLAGS)

# ----------------------------------------------------------------
# Miller source except put/filter DSLs
NON_DSL_SRCS = \
  *.c \
  cli/*.c \
  lib/*.c \
  containers/*.c \
  stream/*.c \
  input/*.c \
  mapping/*.c \
  output/*.c

# put/filter DSLs
PDSL_OBJS = \
  ./dsls/put_dsl_parse.o \
  ./dsls/put_dsl_lexer.o \
  ./dsls/put_dsl_wrapper.o
FDSL_OBJS = \
  ./dsls/filter_dsl_parse.o \
  ./dsls/filter_dsl_lexer.o \
  ./dsls/filter_dsl_wrapper.o

# Unit-test code
TEST_ARGPARSE_SRCS = \
  lib/mlrutil.c \
  lib/mlr_globals.c \
  lib/string_builder.c \
  cli/argparse.c \
  containers/slls.c \
  containers/sllv.c \
  containers/string_array.c \
  unit_test/test_argparse.c

TEST_BYTE_READERS_SRCS = \
  lib/mlrutil.c \
  lib/mlr_test_util.c \
  lib/mlr_globals.c \
  lib/string_builder.c \
  input/string_byte_reader.c \
  input/stdio_byte_reader.c \
  input/mmap_byte_reader.c \
  unit_test/test_byte_readers.c

TEST_PEEK_FILE_READER_SRCS = \
  lib/mlrutil.c \
  lib/mlr_test_util.c \
  lib/mlr_globals.c \
  lib/string_builder.c \
  input/string_byte_reader.c \
  input/peek_file_reader.c \
  unit_test/test_peek_file_reader.c

TEST_LREC_SRCS = \
  lib/mlrutil.c lib/mlr_globals.c lib/string_builder.c \
  containers/lrec.c containers/header_keeper.c containers/sllv.c \
  containers/slls.c containers/lhmslv.c \
  input/line_readers.c \
  input/file_reader_mmap.c      input/file_reader_stdio.c \
  input/lrec_reader_mmap_csvlite.c  input/lrec_reader_stdio_csvlite.c \
  input/lrec_reader_mmap_dkvp.c input/lrec_reader_stdio_dkvp.c \
  input/lrec_reader_mmap_nidx.c input/lrec_reader_stdio_nidx.c \
  input/lrec_reader_mmap_xtab.c input/lrec_reader_stdio_xtab.c \
  unit_test/test_lrec.c

TEST_MULTIPLE_CONTAINERS_SRCS = \
  lib/mlrutil.c lib/mlr_globals.c lib/string_builder.c \
  containers/lrec.c containers/header_keeper.c containers/sllv.c \
  containers/slls.c \
  containers/string_array.c \
  containers/hss.c \
  containers/lhmsi.c \
  containers/lhmss.c \
  containers/lhmsv.c \
  containers/lhms2v.c \
  containers/lhmslv.c \
  containers/mlrval.c \
  containers/percentile_keeper.c \
  containers/top_keeper.c \
  containers/dheap.c \
  input/line_readers.c \
  input/file_reader_mmap.c      input/file_reader_stdio.c \
  input/lrec_reader_mmap_csvlite.c  input/lrec_reader_stdio_csvlite.c \
  input/lrec_reader_mmap_dkvp.c input/lrec_reader_stdio_dkvp.c \
  input/lrec_reader_mmap_nidx.c input/lrec_reader_stdio_nidx.c \
  input/lrec_reader_mmap_xtab.c input/lrec_reader_stdio_xtab.c \
  unit_test/test_multiple_containers.c

TEST_MLRUTIL_SRCS = \
	lib/mlr_globals.c \
	lib/mlrutil.c \
	lib/string_builder.c \
	unit_test/test_mlrutil.c

TEST_STRING_BUILDER_SRCS = \
	lib/mlrutil.c \
	lib/mlr_globals.c \
	lib/string_builder.c \
	unit_test/test_string_builder.c

TEST_PARSE_TRIE_SRCS = \
	lib/mlrutil.c \
	lib/mlr_globals.c \
	lib/string_builder.c \
	containers/parse_trie.c \
	unit_test/test_parse_trie.c

TEST_LREC_EVALUATORS_SRCS = \
  lib/mlr_globals.c \
  lib/mlrutil.c \
  lib/mtrand.c \
  lib/mlrmath.c \
  lib/string_builder.c \
  containers/mlr_dsl_ast.c \
  containers/sllv.c \
  containers/slls.c \
  containers/lrec.c \
  containers/mlrval.c \
  mapping/lrec_evaluators.c \
  unit_test/test_lrec_evaluators.c

TEST_JOIN_BUCKET_KEEPER_SRCS = \
  lib/mlrutil.c lib/mlr_globals.c lib/string_builder.c lib/context.c \
  containers/parse_trie.c \
  containers/lrec.c \
  containers/sllv.c containers/slls.c containers/lhmslv.c containers/hss.c containers/mixutil.c \
  containers/header_keeper.c \
  containers/join_bucket_keeper.c \
  input/mmap_byte_reader.c \
  input/stdio_byte_reader.c \
  input/line_readers.c \
  input/lrec_reader_in_memory.c input/lrec_readers.c \
  input/lrec_reader_csv.c \
  input/lrec_reader_mmap_csvlite.c input/lrec_reader_stdio_csvlite.c \
  input/lrec_reader_mmap_dkvp.c input/lrec_reader_stdio_dkvp.c \
  input/lrec_reader_mmap_nidx.c input/lrec_reader_stdio_nidx.c \
  input/lrec_reader_mmap_xtab.c input/lrec_reader_stdio_xtab.c \
  input/file_reader_mmap.c input/file_reader_stdio.c \
  input/peek_file_reader.c \
  unit_test/test_join_bucket_keeper.c

EXPERIMENTAL_READER_SRCS = \
  lib/mlrutil.c \
  lib/mlr_globals.c \
  lib/string_builder.c \
  input/stdio_byte_reader.c \
  input/file_reader_mmap.c \
  input/line_readers.c \
  containers/parse_trie.c \
  experimental/getlines.c

# ================================================================
# User-make: creates the executable and runs unit & regression tests
# This is the default target for anyone pulling the repo and trying to
# build it to be able to use it. It just needs flex and the C compiler.
top: mlr tests

install: mlr tests
	cp mlr $(INSTALLDIR)
installhome: mlr tests
	cp mlr $(HOME)/bin

# ================================================================
tags: .always
	ctags -R .

mlr: .always dsls
	$(CCOPT) $(NON_DSL_SRCS) $(PDSL_OBJS) $(FDSL_OBJS) $(LFLAGS) -o mlr
mlr.static: .always dsls
	$(CCOPT) -static $(NON_DSL_SRCS) $(PDSL_OBJS) $(FDSL_OBJS) $(LFLAGS) -o mlr.static

dsls: .always
	make -C dsls -f Makefile.no-autoconfig put_dsl_parse.o
	make -C dsls -f Makefile.no-autoconfig put_dsl_lexer.o
	make -C dsls -f Makefile.no-autoconfig put_dsl_wrapper.o
	make -C dsls -f Makefile.no-autoconfig filter_dsl_parse.o
	make -C dsls -f Makefile.no-autoconfig filter_dsl_lexer.o
	make -C dsls -f Makefile.no-autoconfig filter_dsl_wrapper.o

# ----------------------------------------------------------------
# Other executable variants

# Debug version
mlrg: .always dsls
	$(CCDEBUG) $(NON_DSL_SRCS) $(PDSL_OBJS) $(FDSL_OBJS) $(LFLAGS) -o mlrg

# Profile version. Usage:
# * make mlrp
# * mlrp {arguments>
# * gprof mlrp gmon.out > myfile.txt
# Note: works on Linux; not on OSX.
mlrp: .always dsls
	$(CCDEBUG) -g -pg $(NON_DSL_SRCS) $(PDSL_OBJS) $(FDSL_OBJS) $(LFLAGS) -o mlrp

# ================================================================
tests: unit-test reg-test

unit-test: test-mlrutil test-argparse test-byte-readers test-peek-file-reader test-parse-trie test-lrec test-multiple-containers test-string-builder test-lrec-evaluators test-join-bucket-keeper
	./test-mlrutil
	./test-argparse
	./test-byte-readers
	./test-peek-file-reader
	./test-parse-trie
	./test-lrec
	./test-multiple-containers
	./test-string-builder
	./test-lrec-evaluators
	./test-join-bucket-keeper
	@echo
	@echo DONE

reg-test:
	./reg_test/run

# ----------------------------------------------------------------
# Run this after unit-test expected output has changed, and is verified to be
# OK. (Example: after adding new test cases in test/run.)
regtest-copy:
	cp output/out reg_test/expected

# ----------------------------------------------------------------
# Unit-test executables

test-argparse: .always
	$(CCDEBUG) -D__TEST_ARGPARSE_MAIN__ $(TEST_ARGPARSE_SRCS) -o test-argparse

test-byte-readers: .always
	$(CCDEBUG) -D__TEST_BYTE_READERS_MAIN__ $(TEST_BYTE_READERS_SRCS) -o test-byte-readers

test-peek-file-reader: .always
	$(CCDEBUG) -D__TEST_PEEK_FILE_READER_MAIN__ $(TEST_PEEK_FILE_READER_SRCS) -o test-peek-file-reader

test-lrec: .always
	$(CCDEBUG) -D__TEST_LREC_MAIN__ $(TEST_LREC_SRCS) -o test-lrec

test-multiple-containers: .always
	$(CCDEBUG) -D__TEST_MULTIPLE_CONTAINERS_MAIN__ $(TEST_MULTIPLE_CONTAINERS_SRCS) -o test-multiple-containers -lm

test-mlrutil: .always
	$(CCDEBUG) -D__TEST_MLRUTIL_MAIN__ $(TEST_MLRUTIL_SRCS) -o test-mlrutil

test-string-builder: .always
	$(CCDEBUG) -D__TEST_STRING_BUILDER_MAIN__ $(TEST_STRING_BUILDER_SRCS) -o test-string-builder

test-parse-trie: .always
	$(CCDEBUG) -D__TEST_PARSE_TRIE_MAIN__ $(TEST_PARSE_TRIE_SRCS) -o test-parse-trie

test-lrec-evaluators: .always
	$(CCDEBUG) -D__TEST_LREC_EVALUATORS_MAIN__ $(TEST_LREC_EVALUATORS_SRCS) -o test-lrec-evaluators -lm

test-join-bucket-keeper: .always
	$(CCDEBUG) -D__TEST_JOIN_BUCKET_KEEPER_MAIN__ $(TEST_JOIN_BUCKET_KEEPER_SRCS) -o test-join-bucket-keeper

# ----------------------------------------------------------------
# Standalone mains

termcvt: tools/termcvt.c
	$(CCDEBUG) tools/termcvt.c -o termcvt

getl: .always
	#$(CCDEBUG) $(EXPERIMENTAL_READER_SRCS) -o getl
	$(CCOPT) $(EXPERIMENTAL_READER_SRCS) -o getl

# ================================================================
clean:
	@rm -vf mlr mlrd mlrg mlrp tester
	@make -C dsls -f Makefile.no-autoconfig clean

perfclean profclean:
	@rm -vf gmon.out perf.data perf.data.old

.always:
	@true
