#
# Makefile for cligen CLI generator.
#
# ***** BEGIN LICENSE BLOCK *****
# 
# Copyright (C) 2001-2022 Olof Hagsand
#
# This file is part of CLIgen.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Alternatively, the contents of this file may be used under the terms of
# the GNU General Public License Version 2 or later (the "GPL"),
# in which case the provisions of the GPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of the GPL, and not to allow others to
# use your version of this file under the terms of Apache License version 2, indicate
# your decision by deleting the provisions above and replace them with the 
# notice and other provisions required by the GPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the Apache License version 2 or the GPL.
#
# ***** END LICENSE BLOCK *****


prefix		= /usr/local
datarootdir	= ${prefix}/share
exec_prefix	= ${prefix}
bindir		= ${exec_prefix}/bin
libdir		= ${exec_prefix}/lib
srcdir		= .
 # Force a cligen sub-directory
includedir	= ${prefix}/include/cligen

CC		= gcc
LINKAGE         = dynamic
CFLAGS          = -O2 -Wall
CPPFLAGS  	= -DHAVE_CONFIG_H 
ifeq ($(LINKAGE),dynamic)
CPPFLAGS	+= -fPIC
endif

SH_SUFFIX	= .so
LIBSTATIC_SUFFIX = .a
LDFLAGS		= 
ifneq ($(LINKAGE),dynamic)
 # -rdynamic for using -ldl
LDFLAGS 	+=  -rdynamic
endif
LIBS		=  -L.
INCLUDES	= -I. -I. 

HOST_VENDOR     = unknown

INSTALL         = /usr/bin/install -c
INSTALL_LIB     = /usr/bin/install -c
INSTALL_DATA    = /usr/bin/install -c
INSTALL_PROGRAM	= /usr/bin/install -c
LN_S            = ln -s

ifeq ($(HOST_VENDOR),apple)
INSTALLFLAGS =
else
INSTALLFLAGS = -s
endif

CLIGEN_VERSION = 6.1.0_PRE
CLIGEN_MAJOR   = 6
CLIGEN_MINOR   = 1

# Linker-name: libcligen.so
# so-name: libcligen.so.3
# real-name: libcligen.so.3.0
MYLIBDYNAMIC = libcligen$(SH_SUFFIX).$(CLIGEN_MAJOR).$(CLIGEN_MINOR)
MYLIBSO      = libcligen$(SH_SUFFIX).$(CLIGEN_MAJOR)
MYLIBLINK    = libcligen$(SH_SUFFIX)
MYLIBSTATIC  = libcligen$(LIBSTATIC_SUFFIX)

SRC		= cligen_object.c cligen_callback.c cligen_parsetree.c cligen_pt_head.c \
                  cligen_handle.c cligen_cv.c cligen_match.c cligen_result.c \
		  cligen_read.c cligen_io.c cligen_expand.c cligen_syntax.c \
		  cligen_print.c cligen_cvec.c cligen_buf.c cligen_util.c \
		  cligen_history.c cligen_regex.c cligen_getline.c build.c

INCS		= cligen_cv.h cligen_cvec.h cligen_object.h cligen_callback.h cligen_handle.h \
	          cligen_parsetree.h cligen_pt_head.h cligen_result.h \
		  cligen_print.h cligen_read.h cligen_io.h cligen_expand.h \
		  cligen_syntax.h cligen_buf.h cligen_util.h cligen_history.h \
		  cligen_regex.h cligen.h

SRCDIR_INCS	= $(addprefix $(srcdir)/,$(INCS))

OBJS		= $(SRC:.c=.o) 
APPS		= cligen_hello cligen_file cligen_tutorial

YACC		= bison -y
LEX		= flex

all:	cligen $(APPS)

ifeq ($(LINKAGE),dynamic)
all:	 $(MYLIBDYNAMIC)
else
all:	 $(MYSTATIC)
endif

.PHONY: TAGS test
TAGS:
	find . -name '*.[chyl]' -print | etags -

# Run a clixon test container.
# Alt: cd test; ./all.sh
# CFLAGS/LINKAGE is for test_compile.sh for coverage
test:
	(cd test && SKIPLIST="$(SKIPLIST)" CFLAGS="$(CFLAGS)" LINKAGE="$(LINKAGE)" ./all.sh)

distclean: clean
	rm -f Makefile config.log config.status config.h TAGS .depend
	rm -rf autom4te.cache build.c cligen_config.h
	rm -rf doc build-root/rpmbuild
	rm -f build-root/*.tar.xz build-root/*.rpm extras/rpm/Makefile

export BR=$(CURDIR)/build-root

$(BR)/scripts/.version:
ifneq ("$(wildcard /etc/redhat-release)","")
	$(shell $(BR)/scripts/version rpm-string > $(BR)/scripts/.version)
else
	$(shell $(BR)/scripts/version > $(BR)/scripts/.version)
endif

DIST_FILE = $(BR)/cligen-$(shell extras/scripts/version).tar
DIST_SUBDIR = cligen-$(shell extras/scripts/version | cut -f1 -d-)

dist:
	@if git rev-parse 2> /dev/null ; then \
	    git archive \
	      --prefix=$(DIST_SUBDIR)/ \
	      --format=tar \
	      -o $(DIST_FILE) \
	    HEAD ; \
	    git describe > $(BR)/.version ; \
	else \
	    (cd .. ; tar -cf $(DIST_FILE) $(DIST_SUBDIR) --exclude=*.tar) ; \
	    extras/scripts/version > $(BR)/.version ; \
	fi
	@tar --append \
	  --file $(DIST_FILE) \
	  --transform='s,.*/.version,$(DIST_SUBDIR)/extras/scripts/.version,' \
	  $(BR)/.version
	@for f in $$(git status --porcelain | grep '^D' | awk '{print $$2}'); do \
	  tar --delete --file $(DIST_FILE) $(DIST_SUBDIR)/$${f}; \
	done
	@for f in $$(git status --porcelain -u | grep -v '^D' | awk '{print $$2}'); do \
	  tar --append --file $(DIST_FILE) \
	  --transform="s,$${f},$(DIST_SUBDIR)/$${f}," \
	  $${f}; \
	done
	@$(RM) $(BR)/.version $(DIST_FILE).xz
	@xz -v --threads=0 $(DIST_FILE)
	@$(RM) $(BR)/cligen-latest.tar.xz
	@ln -rs $(DIST_FILE).xz $(BR)/cligen-latest.tar.xz

pkg-rpm: dist
	make -C extras/rpm

pkg-srpm: dist
	make -C extras/rpm srpm

%.o : $(srcdir)/%.c
	$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c $<
.c.o:
	$(CC) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) -c $<

# Compute the length of the date command (and add some extra with XXX)
DATELEN = $(shell date +"%Y.%m.%d %H:%M by `whoami` on `hostname`XXXX"|wc -c)

# Should not be rebuilt on install, which causes root ownership of the lib in the build-dir
.PHONY: build.c 
build.c:	
	echo "/* This file is generated from the CLIgen Makefile */" > build.c;
	date +"const char CLIGEN_BUILDSTR[$(DATELEN)]=\"%Y.%m.%d %H:%M by `whoami` on `hostname`"\"\; >> build.c;
	echo "const char CLIGEN_VERSION[64]=\"$(CLIGEN_VERSION)\""\; >> build.c;

# install-bin install-include
install: install-lib install-include

install-bin: $(APPS)
	$(INSTALL) -m 0755 -d $(DESTDIR)$(bindir)
	$(INSTALL_PROGRAM) -m 0755  $(APPS) $(DESTDIR)$(bindir)

ifeq ($(LINKAGE),dynamic)
install-lib: $(MYLIBDYNAMIC)
	$(INSTALL) -m 0755 -d $(DESTDIR)$(libdir)
	$(INSTALL) -m 0644 $(INSTALLFLAGS) $< $(DESTDIR)$(libdir)
	(cd $(DESTDIR)$(libdir) && $(LN_S) -f $< $(MYLIBSO))     # -l:libcligen.so.3
	(cd $(DESTDIR)$(libdir) && $(LN_S) -f $(MYLIBSO) $(MYLIBLINK)) # -l:libcligen.so
else
install-lib: $(MYLIBSTATIC)
	$(INSTALL) -m 0755 -d $(DESTDIR)$(libdir)
	$(INSTALL) -m 0644 $(INSTALLFLAGS) $< $(DESTDIR)$(libdir)
endif

# Installs include files in subdir called 'cligen'. Applications should include
# <cligen/cligen.h>
install-include: $(SRCDIR_INCS)
	install -m 0755 -d $(DESTDIR)$(includedir)
	$(INSTALL_DATA) $(SRCDIR_INCS) $(DESTDIR)$(includedir)

uninstall: 
	rm -f $(DESTDIR)$(libdir)/$(MYLIBDYNAMIC)
	rm -f $(DESTDIR)$(libdir)/$(MYLIBSTATIC)
	for i in $(INCS); do \
		rm -f $(DESTDIR)$(includedir)/$$i; \
	done

# CLIGEN parser src
YACC_SRC        = cligen_parse.y
LEX_SRC         = cligen_parsel
YACCOBJS := lex.cligen_parse.o cligen_parse.tab.o 

clean:  
	rm -f $(APPS) $(OBJS) $(YACCOBJS) 
	rm -f $(MYLIBSTATIC) $(MYLIBDYNAMIC) $(MYLIBSO) $(MYLIBLINK) 
	rm -f *.tab.c *.tab.h *.tab.o 
	rm -f lex.*.c lex.*.o *.core cligen
	rm -f *.gcda *.gcno *.gcov # coverage

%.c : %.y  # cancel implicit yacc rule
%.c : %.l  # cancel implicit lex rule

# top file parse
lex.cligen_parse.c : $(srcdir)/cligen_parse.l cligen_parse.tab.h
	$(LEX) -Pcligen_parse $(srcdir)/cligen_parse.l # -d is debug 

cligen_parse.tab.h: $(srcdir)/cligen_parse.y
	$(YACC) -l -d -b cligen_parse -p cligen_parse $(srcdir)/cligen_parse.y # -t is debug

cligen_parse.tab.c: cligen_parse.tab.h

lex.cligen_parse.o : lex.cligen_parse.c cligen_parse.tab.h
	$(CC) $(INCLUDES) $(CPPFLAGS) -DYY_NO_INPUT $(CFLAGS) -c $<

ifeq ($(LINKAGE),dynamic)
MYLIB=$(MYLIBDYNAMIC)
else
MYLIB=$(MYLIBSTATIC)
endif

# Applications
cligen_hello : $(srcdir)/cligen_hello.c cligen $(MYLIB)
	$(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) $< $(LDFLAGS) $(LIBS) -o $@ $(MYLIB)

cligen_file :	$(srcdir)/cligen_file.c cligen $(MYLIB)
	$(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) $< $(LDFLAGS) $(LIBS) -o $@ $(MYLIB)

cligen_tutorial :$(srcdir)/cligen_tutorial.c cligen $(MYLIB)
	$(CC) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) $< $(LDFLAGS) $(LIBS) -o $@ $(MYLIB)

$(MYLIBDYNAMIC) : $(OBJS) $(YACCOBJS)
ifeq ($(HOST_VENDOR),apple)
	$(CC) -shared -o $@ $(OBJS) $(YACCOBJS) -undefined dynamic_lookup -o $(MYLIB) $(LIBS)
else
	$(CC) -shared -o $@ $(OBJS) $(YACCOBJS) -Wl,-soname=$(MYLIB) $(LIBS)
endif

# link-name is needed for application linking
$(MYLIBSO) : $(MYLIB)

$(MYLIBLINK) : $(MYLIB)

$(MYLIBSTATIC) : $(OBJS) $(YACCOBJS)
	ar -crs $@ $(OBJS) $(YACCOBJS)

# recursive link to handle application include files, if you have not installed
# .h files in $(includefile)
cligen : 
	cd $(srcdir) && rm -rf $@ && ln -sf . $@

.PHONY: doc
doc : 
	doxygen Doxyfile

.PHONY: depend
depend:
	$(CC) $(DEPENDFLAGS) -DHAVE_CONFIG_H $(INCLUDES) $(CFLAGS) -MM $(SRC) cligen_file.c cligen_hello.c cligen_tutorial.c > .depend

#include .depend
