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