diff: changes for user-defined libraries

Fergus Henderson fjh at cs.mu.oz.au
Tue Jul 15 17:32:31 AEST 1997


Hi,

Can someone please review this one?

Simplify the process for creating and using Mercury libraries,
and document it in the user guide.

compiler/modules.m:
	Add rules for creating the `.a', `.so', and `.init' files.
	The `.so' file is creating using ml's new `--make-shared-lib' option.

scripts/Mmake.vars.in:
	Add definitions for AR, ARFLAGS, RANLIB, and RANLIBFLAGS,
	for use by the new rules generated in `.dep' files by modules.m.

Mmake.common.in:
	Remove RANLIB, since it's now defined in scripts/Mmake.vars.in.

doc/user_guide.texi:
	Add a chapter on libraries.
	Also a few other minor changes.

Index: doc/user_guide.texi
===================================================================
RCS file: /home/staff/zs/imp/mercury/doc/user_guide.texi,v
retrieving revision 1.87
diff -u -r1.87 user_guide.texi
--- user_guide.texi	1997/05/19 02:17:42	1.87
+++ user_guide.texi	1997/07/15 07:08:00
@@ -77,8 +77,10 @@
 * Introduction::    General overview
 * Filenames::       File naming conventions
 * Using mc::        Compiling and linking programs with the Mercury compiler
+* Running::         Execution of programs built with the Mercury compiler
 * Using Prolog::    Building and debugging Mercury programs with Prolog
 * Using Mmake::     ``Mercury Make'', a tool for building Mercury programs
+* Libraries::       Creating and using libraries of Mercury modules
 * Profiling::       The Mercury profiler @samp{mprof}, a tool for analyzing
                     program performance
 * Invocation::      List of options for the Mercury compiler
@@ -161,6 +163,8 @@
 @file{.o} files are object code,
 @file{.no} files are NU-Prolog object code, and
 @file{.ql} files are SICStus Prolog object code.
+In addition, @file{.pic_o} files are object code files
+that contain position-independent code (PIC).
 
 @node Using mc
 @chapter Using the Mercury compiler
@@ -184,7 +188,7 @@
 @samp{mc} will put the executable into a file called @file{@var{module}},
 not @file{a.out}.
 
-For programs that consist of more than one module, we recommend
+For programs that consist of more than one module, we @emph{strongly} recommend
 that you use Mmake (@pxref{Using Mmake}).  Mmake will perform
 all the steps listed below, using automatic dependency analysis
 to ensure that things are done in the right order, and that
@@ -278,6 +282,9 @@
 You can use that option to see what is actually going on.
 For the full set of options of @samp{mc}, see @ref{Invocation}.
 
+ at node Running
+ at chapter Running programs
+
 Once you have created an executable for a Mercury program,
 you can go ahead and execute it.  You may however wish to specify
 certain options to the Mercury runtime system.
@@ -453,7 +460,12 @@
 @section Hazards of using Prolog
 
 There are some Mercury programs which are not valid Prolog programs.
-In particular, Mercury will always reorder goals
+In particular, Mercury programs that use functions will generally not
+be valid Prolog programs (with the exception that the basic arithmetic
+functions such as @samp{+}, @samp{-}, etc., will work fine if you use
+Prolog's @samp{is} predicate).
+
+Also, Mercury will always reorder goals
 to ensure that they are mode-correct
 (or report a mode error if it cannot do so),
 but Prolog systems will not always do so,
@@ -518,7 +530,8 @@
 and therefore you must run @samp{mmake @var{program}.depend}
 for each program.
 
-If there is a file called @samp{Mmake} in the current directory,
+If there is a file called @samp{Mmake} or @samp{Mmakefile} in the
+current directory,
 Mmake will include that file in its automatically-generated Makefile.
 The @samp{Mmake} file can override the default values of
 various variables used by Mmake's builtin rules,
@@ -575,6 +588,12 @@
 The resulting executable will start up in the SICStus Prolog interpreter
 rather than calling main/2.
 
+ at item lib at var{main-module}
+Builds a library whose top-level module is @var{main-module}.
+This will build a static object library, a shared object library
+(for platforms that support it), and the necessary interface files.
+ at xref{Libraries} for more information.
+
 @item @var{main-module}.clean
 Removes the automatically generated files
 that contain the compiled code of the program
@@ -584,8 +603,8 @@
 belonging to the named @var{main-module} or its imported modules.
 
 @item @var{main-module}.change_clean
-Removes files that need updating if changing garbage collection method or
-starting to use inter-module optimization.
+Removes files that need updating when changing garbage collection method or
+when enabling inter-module optimization.
 Specifically, this will remove all the @samp{.c}, @samp{.s}, @samp{.o},
 @samp{.dep} and executable files belonging to the named @var{main-module}
 or its imported modules.
@@ -664,7 +683,169 @@
 In particular, GNU Make has support for running jobs in parallel,
 which is very useful if you have a machine with more than one CPU.
 
- at c ---------------------------------------------------------------------------
+ at node Libraries
+ at chapter Libraries
+
+Often you will want to use a particular set of Mercury modules
+in more than one program. The Mercury implementation 
+includes support for developing libraries, i.e. sets of Mercury modules
+intended for reuse.  It allows separate compilation of libraries
+and, on many platforms, it supports shared object libraries.
+
+ at menu
+* Writing libraries::
+* Building libraries::
+* Installing libraries::
+* Using libraries::
+ at end menu
+
+ at node Writing libraries
+ at section Writing libraries
+
+A Mercury library is identified by a top-level module, which must
+directly or indirectly use (import) all of the modules in that
+library.  It may be as simple as this @file{mypackage.m} file:
+
+ at example
+:- module mypackage.
+:- import_module foo, bar, baz.
+ at end example
+
+ at node Building libraries
+ at section Building libraries
+
+Generally Mmake will do most of the work of building
+libraries automatically.  Here's a sample @code{Mmakefile} for
+creating a library.
+
+ at example
+MAIN_TARGET = libmypackage
+ at c XXX
+ at c MCFLAGS = --intermodule-optimization $(EXTRA_MCFLAGS)
+
+depend: mypackage.depend
+ at end example
+
+The Mmake target @samp{lib at var{foo}} is a built-in target for
+creating a library whose top-level module is @samp{@var{foo}.m}.
+The automatically generated Make rules for the target @samp{lib at var{foo}}
+will create all the files needed to use the library.
+
+Mmake will create static (non-shared) object libraries
+and, on most platforms, shared object libraries;
+however, we do not yet support the creation of dynamic link
+libraries (DLLs) on Windows.
+Static libraries are created using the standard tools @samp{ar}
+and @samp{ranlib}.
+Shared libraries are created using the @samp{--make-shared-lib}
+option to @samp{ml}. 
+The automatically-generated Make rules for @samp{libmypackage}
+will look something like this:
+
+ at example
+libmypackage: libmypackage.a libmypackage.so \
+		$(mypackage.ints) $(mypackage.opts) mypackage.init
+
+libmypackage.a: $(mypackage.os)
+	rm -f libmypackage.a
+	$(AR) $(ARFLAGS) libmypackage.a $(mypackage.os)
+	$(RANLIB) $(RANLIBFLAGS) mypackage.a
+
+libmypackage.so: $(mypackage.pic_os)
+	$(ML) $(MLFLAGS) --make-shared-lib -o libmypackage.so \
+		$(mypackage.pic_os) $(MLLIBS)
+
+libmypackage.init:
+	...
+
+clean:
+	rm -f libmypackage.a libmypackage.so
+ at end example
+
+If necessary, you can override the default definitions of the
+variables such as @samp{ML}, @samp{MLFLAGS}, and @samp{MLLIBS}
+to customize the way shared libraries are built.  Similarly
+ at samp{AR}, @samp{ARFLAGS}, @samp{RANLIB}, and @samp{RANLIBFLAGS}
+control the way static libraries are built.
+
+Note that to use a library, as well as the shared or static object library,
+you also need the interface files.  That's why the
+ at samp{libmypackage} target builds @samp{$(mypackage.ints)}.
+Also, if the people using the library are going to use intermodule
+optimization, you need the intermodule optimization interfaces.
+That's why the @samp{libmypackage} target builds @samp{$(mypackage.opts)}.
+In addition, with certain compilation grades, programs will need to
+execute some startup code to initialize the library; the
+ at samp{mypackage.init} file contains information about initialization
+code for the library.
+
+ at c XXX and why the @samp{MCFLAGS} contains @samp{--intermodule-optimization}.
+
+On some platforms, shared objects must be created using position independent
+code (PIC), which requires passing some special options to the C compiler.
+On these platforms, @code{Mmake} will create @file{.pic_o} files,
+and @samp{$(mypackage.pic_os)} will contain a list of the @file{.pic_o} files
+for the library whose top-level module is @samp{mypackage}.
+On other platforms, position independent code is the default,
+and @samp{$(mypackage.pic_os)} will just be the same as @samp{$(mypackage.os)},
+which contains a list of the @file{.o} files for that module.
+
+ at node Installing libraries
+ at section Installing libraries
+
+If you want, once you have built a library, you could then install
+(i.e. copy) the shared object library, the static object library,
+the interface files and the initialization file into a different directory,
+or into several different directories, for that matter -- though it
+is probably easiest for the users of the library if you keep them
+in a single directory.
+Or alternatively, you could package them up into a @samp{tar}, @samp{shar}, or
+ at samp{zip} archive and ship them to the people who will use the
+library.
+
+ at node Using libraries
+ at section Using libraries
+
+To use a library, you need to set the Mmake variables @samp{VPATH},
+ at samp{MCFLAGS}, @samp{MLFLAGS}, and @samp{MLLIBS} to specify the
+name and location of the library or libraries that you wish to use.
+For example, if you want to link in the libraries @samp{mypackage} and
+ at samp{myotherlib}, which were built in the directories
+ at samp{/some/directory/mypackage} and @samp{/some/directory/myotherlib}
+respectively, you could use the following settings:
+
+ at example
+# Specify the location of the `mypackage' and `myotherlib' directories
+MYPACKAGE_DIR = /some/directory/mypackage
+MYOTHERLIB_DIR = /some/directory/myotherlib
+
+# The following stuff tells Mmake to use the two libraries
+VPATH = $(MYPACKAGE_DIR):$(MYOTHERLIB_DIR):$(MMAKE_VPATH)
+MCFLAGS = -I$(MYPACKAGE_DIR) -I$(MYOTHERLIB_DIR) $(EXTRA_MCFLAGS)
+MLFLAGS = -R$(MYPACKAGE_DIR) -R$(MYOTHERLIB_DIR) $(EXTRA_MLFLAGS) \
+          -L$(MYPACKAGE_DIR) -L$(MYOTHERLIB_DIR)
+MLLIBS = -lmypackage -lmyotherlib $(EXTRA_MLLIBS)
+C2INITFLAGS = $(MYPACKAGE_DIR)/mypackage.init \
+              $(MYOTHERLIB_DIR)/myotherlib.init
+ at end example
+
+Here @samp{VPATH} is a colon-separated list of path names specifying
+directories that Mmake will search for interface files.
+The @samp{-I} options in @samp{MCFLAGS} tell @samp{mc} where to find
+the interface files.  The @samp{-R} options in @samp{MLFLAGS} tell
+the loader where to find shared libraries, and the @samp{-L}
+options tell the linker where to find libraries. 
+(Note that the @samp{-R} options must precede the @samp{-L} options.)
+The @samp{-l} options tell the linker which libraries to link with. 
+The extras arguments to @samp{c2init} specified in the @samp{C2INITLFLAGS}
+variable tell @samp{c2init} where to find the @samp{.init} files for the
+libraries, so that it can generate appropriate initialization code.
+
+The example above assumes that the static object library,
+shared object library, interface files and initialization file are
+for each Mercury library being used all put in a single directory,
+which is probably the simplest way of organizing things, but the
+Mercury implementation does not require that.
 
 @node Profiling
 @chapter Profiling
Index: scripts/Mmake.vars.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/scripts/Mmake.vars.in,v
retrieving revision 1.6
diff -u -r1.6 Mmake.vars.in
--- Mmake.vars.in	1997/03/18 05:58:16	1.6
+++ Mmake.vars.in	1997/07/14 11:03:17
@@ -64,6 +64,11 @@
 MSP		= msp
 MSPFLAGS	= $(EXTRA_MSPFLAGS)
 
+AR		= ar
+ARFLAGS		= cr
+RANLIB		= @RANLIB@
+RANLIBFLAGS	=
+
 # $(CFLAGS_FOR_PIC) is passed to the C compiler when creating `.pic_o' files
 # (We use `.pic_o' as the extension for `.o' files that must have
 # position-independent code.)
Index: Mmake.common.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/Mmake.common.in,v
retrieving revision 1.19
diff -u -r1.19 Mmake.common.in
--- Mmake.common.in	1997/06/16 13:35:12	1.19
+++ Mmake.common.in	1997/07/14 11:01:59
@@ -41,9 +41,6 @@
 # Specify the additional compilation models to install the library for
 LIBGRADES  		= @LIBGRADES@
 
-# Specify the ranlib program, if needed.
-RANLIB  		= @RANLIB@
-
 # Specify the name of the Sicstus Prolog interpreter.
 SP			= @SP@
 
Index: compiler/modules.m
===================================================================
RCS file: /home/staff/zs/imp/mercury/compiler/modules.m,v
retrieving revision 1.35
diff -u -r1.35 modules.m
--- modules.m	1997/06/29 23:11:12	1.35
+++ modules.m	1997/07/15 07:22:42
@@ -723,87 +723,87 @@
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".nos = "),
 	write_compact_dependencies_list(Modules, ".no", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".qls = "),
 	write_compact_dependencies_list(Modules, ".ql", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".cs = "),
 	write_compact_dependencies_list(Modules, ".c", Basis, DepStream),
 	write_dependencies_list(ExtraLinkObjs, ".c", DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".os = "),
 	write_compact_dependencies_list(Modules, ".o", Basis, DepStream),
 	write_dependencies_list(ExtraLinkObjs, ".o", DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".pic_os = "),
 	write_compact_dependencies_list(Modules, ".$(EXT_FOR_PIC_OBJECTS)",
 		Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".dirs = "),
 	write_compact_dependencies_list(Modules, ".dir", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".dir_os = "),
 	write_compact_dependencies_list(Modules, ".dir/*.o", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".ss = "),
 	write_compact_dependencies_list(Modules, ".s", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".errs = "),
 	write_compact_dependencies_list(Modules, ".err", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".dates = "),
 	write_compact_dependencies_list(Modules, ".date", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".date3s = "),
 	write_compact_dependencies_list(Modules, ".date3", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".optdates = "),
 	write_compact_dependencies_list(Modules, ".optdate", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".ds = "),
 	write_compact_dependencies_list(Modules, ".d", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".hs = "),
 	write_compact_dependencies_list(Modules, ".h", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".ints = "),
 	write_compact_dependencies_list(Modules, ".int", Basis, DepStream),
 	write_compact_dependencies_separator(Basis, DepStream),
 	write_compact_dependencies_list(Modules, ".int2", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".int3s = "),
 	write_compact_dependencies_list(Modules, ".int3", Basis, DepStream),
-	io__write_string(DepStream, "\n\n"),
+	io__write_string(DepStream, "\n"),
 
 	io__write_string(DepStream, ModuleName),
 	io__write_string(DepStream, ".opts = "),
@@ -829,32 +829,43 @@
 	io__write_strings(DepStream, [
 		ModuleName, ".split.a : $(", ModuleName, ".dir_os)\n",
 		"\trm -f ", ModuleName, ".split.a\n",
-		"\tar cr ", ModuleName, ".split.a\n",
+		"\t$(AR) $(ARFLAGS) ", ModuleName, ".split.a\n",
 		"\tfor dir in $(", ModuleName, ".dirs); do \\\n",
-		"\t	ar q ", ModuleName, ".split.a $$dir/*.o; \\\n",
+		"\t	$(AR) q ", ModuleName, ".split.a $$dir/*.o; \\\n",
 		"\tdone\n",
-		"\tranlib ", ModuleName, ".split.a\n\n"
+		"\t$(RANLIB) $(RANLIBFLAGS) ", ModuleName, ".split.a\n\n"
 	]),
 
-/************
-% I decided to leave the rules for `foo.so' and `foo.a' out,
-% mainly because the rule for `foo.so' is hard to make portable.
-% The rules here would conflict with the one in library/Mmake.
+	io__write_strings(DepStream, [
+		"lib", ModuleName, " : ",
+		"lib", ModuleName, ".a ",
+		"lib", ModuleName, ".$(EXT_FOR_SHARED_LIB) \\\n",
+		"\t\t$(", ModuleName, ".ints) ",
+		"$(", ModuleName, ".opts) ",
+		ModuleName, ".init\n\n"
+	]),
 
 	io__write_strings(DepStream, [
-		ModuleName, ".so : $(", ModuleName, ".pic_os)\n",
-		"\t$(LINK_SHARED_LIB) -o ", ModuleName, ".so ",
-			"$(", ModuleName, ".pic_os)\n\n"
+		"lib", ModuleName, ".so : $(", ModuleName, ".pic_os)\n",
+		"\t$(ML) --make-shared-lib $(MLFLAGS) -o ",
+			"lib", ModuleName, ".so \\\n",
+		"\t\t$(", ModuleName, ".pic_os) $(MLLIBS)\n\n"
 	]),
 
 	io__write_strings(DepStream, [
-		ModuleName, ".a : $(", ModuleName, ".os)\n",
+		"lib", ModuleName, ".a : $(", ModuleName, ".os)\n",
 		"\trm -f ", ModuleName, ".a\n",
-		"\tar cr ", ModuleName, ".a ",
+		"\t$(AR) $(ARFLAGS) lib", ModuleName, ".a ",
 			"$(", ModuleName, ".os)\n",
-		"\tranlib ", ModuleName, ".a\n\n"
+		"\t$(RANLIB) $(RANLIBFLAGS) lib", ModuleName, ".a\n\n"
+	]),
+
+	io__write_strings(DepStream, [
+		ModuleName, ".init : ", ModuleName, ".dep\n",
+		"\tfor file in $(", ModuleName, ".ms); do \\\n",
+		"\t\techo ""INIT mercury__`basename $$file .m`__init""; \\\n",
+		"\tdone > ", ModuleName, ".init\n\n"
 	]),
-************/
 
 	io__write_strings(DepStream, [
 		ModuleName, "_init.c :\n",
@@ -914,8 +925,14 @@
 		"\t-rm -f $(", ModuleName, ".os) ", ModuleName, "_init.o\n",
 		"\t-rm -f $(", ModuleName, ".hs)\n",
 		"\t-rm -f $(", ModuleName, ".ds)\n",
-		"\t-rm -f ", ModuleName, ".dep ", ModuleName, "\n",
-		"\t-rm -f ", ModuleName, ".split ", ModuleName,".split.a\n\n"
+		"\t-rm -f ",
+			ModuleName, " ",
+			ModuleName, ".split ",
+			ModuleName, ".split.a ",
+			ModuleName, ".init ",
+			"lib", ModuleName, ".a ",
+			"lib", ModuleName, ".so ",
+			ModuleName, ".dep\n\n"
 	]),
 
 	io__write_strings(DepStream, [
@@ -938,6 +955,9 @@
 			ModuleName, " ",
 			ModuleName, ".split ",
 			ModuleName, ".split.a ",
+			ModuleName, ".init ",
+			"lib", ModuleName, ".a ",
+			"lib", ModuleName, ".so ",
 			ModuleName, ".nu ",
 			ModuleName, ".nu.save ",
 			ModuleName, ".nu.debug.save ",

-- 
Fergus Henderson <fjh at cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3         |     -- the last words of T. S. Garp.



More information about the developers mailing list