#-----------------------------------------------------------------------------#
# vim: ts=8 sw=8 noexpandtab
#-----------------------------------------------------------------------------#
#
# This directory contains an example of how to create and use a stand-alone
# interface. Stand-alone interfaces allow exported Mercury procedures to be
# called from "foreign" applications, that is applications whose entry point
# is something other than a Mercury main/2 predicate. (By "exported" Mercury
# procedure we mean one that is the subject of a pragma foreign_export
# declaration.)
#
# A stand-alone interface consists of an object / header file pair. These
# define a pair of functions whose respective tasks are to initialise and
# shutdown the Mercury runtime plus a given set of Mercury libraries that the
# foreign application may wish to use. It is important to initialise the
# Mercury runtime before calling any Mercury procedures. The header file
# created as part of the stand-alone interface is compatible with either C or
# C++.
#
# Stand-alone interfaces are created by invoking the compiler with the
# `--generate-standalone-interface' option. The Mercury libraries that the
# foreign application may wish to use are specified via the usual mechanisms,
# e.g. the `--ml' and `--mld' options. The Mercury standard library is always
# included amongst the set of libraries.
#
# In this example there is a small foreign application written in C contained
# in the file c_main.c. This application calls some Mercury procedures
# defined in the Mercury library `mercury_lib' (which is contained in the file
# mercury_lib.m). The program also manipulates the value of a mutable defined
# in this library.
#
# To build the application we first compile `mercury_lib'. For this example
# we don't bother installing it since that would just lead to the command
# lines being unwieldy. We then build the stand-alone interface, which in
# this example is called mercury_lib_int. Finally, we compile c_main.c and
# link them all together. Specific details concerning each step in the build
# process are discussed below. See c_main.c for details of how to invoke the
# stand-alone interface from C or C++ code.

MMC = mmc

all: c_main

# This variable holds the options required to set the grade.
# By default, it is empty so the example will be built in the default grade.
# To try, for example, a deep profiling grade, set it to:
#
#    GRADEOPT=--grade asm_fast.gc.profdeep
#
GRADEOPT=

# By default, we link our application statically against the Mercury libraries.
# If you wish to use the shared versions of the Mercury libraries, comment
# out the next two lines and uncomment the two following them.
#
# Note that we specify the example mercury_lib library to the linker separately
# here. This is because we have not installed it.
#
MERCURY_LINKAGE = --mercury-linkage static
MERCURY_LIB_LDFLAGS = libmercury_lib.a

# For using shared libraries. (Remember to comment out the versions
# above if you use these.)
#
#MERCURY_LINKAGE = --mercury-linkage shared
#MERCURY_LIB_LDFLAGS = -L. -Wl,-rpath . -lmercury_lib

# Ask the Mercury compiler what C compiler we should use?
#
CC = $(shell $(MMC) --output-cc)

# We need to tell the C compiler to define the macros used to specify the
# compilation grade in which any Mercury libraries we are using were compiled.
# We also need to tell the C compiler where to find the C header files
# associated with those libraries. The simplest way to find out both of these
# is to ask the Mercury compiler what flags it passes to the C compiler.
# This can be done as follows:
#
# CFLAGS = $(shell $(MMC) $(GRADEOPT) --output-cflags)
#
# Note that the output of the `--output-cflags' option also includes any other
# flags that the Mercury compiler passes to the C compiler, for example options
# that control optimisation settings.
#
# We use a finer grained approach here that only queries the Mercury compiler
# about which macros to define for the current grade and what directories to
# search for header files in. This finer grained approach is useful if a
# foreign application is written in, for example, C++ instead of C.  In that
# case not all of the flags output by --output-cflags may be valid for the
# C++ compiler.

# Ask the Mercury compiler what flags to pass to the C compiler in order to
# define the macros used to specify the compilation grade we are using.
#
CFLAGS_FOR_GRADE = $(shell $(MMC) $(GRADEOPT) --output-grade-defines)

# Ask the Mercury compiler what flags to pass to the C compiler in order to
# tell it where to search for C header files that are part of any Mercury
# libraries we are using (including the standard library).
#
CFLAGS_FOR_INCLUDES = $(shell $(MMC) $(GRADEOPT) --use-subdirs \
	--output-c-include-dir-flags)

# Gather together all the flags to pass to the C compiler.
#
CFLAGS = $(CFLAGS_FOR_GRADE) $(CFLAGS_FOR_INCLUDES)

# Ask the Mercury compiler what command it uses to invoke the linker when
# creating an executable?
#
LD = $(shell $(MMC) --output-link-command)

# Ask the Mercury compiler what flags it passes to the linker in order to
# link against the selected set of Mercury libraries?
#
LIB_LDFLAGS = $(shell $(MMC) $(GRADEOPT) $(MERCURY_LINKAGE) --output-library-link-flags)

# Build the example Mercury library, mercury_lib.
# The dependency on the .init file is merely a convenience. It is a good
# choice since it will always be regenerated if one of the .m files in a
# library is changed.
#
# In order to keep the command lines in this makefile sane we don't
# bother installing it. Usually we would be working with an installed
# library.
#
mercury_lib.init: mercury_lib.m
	$(MMC) $(GRADEOPT) --make libmercury_lib

# The following rule creates the stand-alone interface to the mercury_lib
# library, Mercury standard library and Mercury runtime. Since we have not
# installed mercury_lib all the relevant files will have been built in
# this directory; with an installed library we would need to use the
# `--mld' option to specify its location.
#
mercury_lib_int.o: mercury_lib.init
	$(MMC) $(GRADEOPT) --ml mercury_lib \
		--generate-standalone-interface mercury_lib_int

c_main.o: c_main.c mercury_lib.init mercury_lib_int.o
	$(CC) $(CFLAGS) -c c_main.c

c_main: c_main.o mercury_lib_int.o mercury_lib.init
	$(LD) -o c_main c_main.o $(MERCURY_LIB_LDFLAGS) mercury_lib_int.o $(LIB_LDFLAGS)

.PHONY: realclean
realclean:
	-$(MMC) --make mercury_lib.realclean
	/bin/rm -f mercury_lib_int.[cho] c_main.o c_main Deep.data
	/bin/rm -rf Mercury
