[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.9 Linking with external libararies

Sometimes you need to link your code with a third-party SML library whose source code is not part of your own project. Perhaps you don't even have the source code but only a collection of `.ui' and `.uo' files.

You may be lucky that the library is written with Mosmake in mind. In that case you can just put a symbolic link to the library in your project directory and include its `Dependencies' file using the cross-directory support we'll discuss in 2.10 Multiple directories. Otherwise you need to do more work youself. (Libraries with Mosmake support do not exist at the time of this writing, but I think it would be cool if they started to emerge :-)).

First of all, you should define a makefile variable to hold the pathname of the directory where the library files reside. In the examples in this section, we'll call it $(MYLIBDIR), but of course you can name it whatever you please. The value of $(MYLIBDIR) should be an absolute path; Mosmake will not try to adjust it when it's used in different directory contexts.

If you plan to distribute your application as source, you should add some mechanism to easily adapt the definition of $(MYLIBDIR) to the user's context. autoconf is a good tool for this.

If the entire library is compiled in structure mode, you might get away with just adding <cl:-I $(MYLIBDIR)> to the `Dependencies' lines for each unit that uses the library. That will add $(MYLIBDIR) to the path where mosmlc searches for unknown structure-mode units. See section 2.8 Extra mosmlc options, for details.

It the library includes toplevel-mode units, you must add explicit dependency information to your `Dependencies' file, as in:

 
aunit: $(MYLIBDIR)/libunit1 anotherunit $(MYLIBDIR)/libunit2

Mosmake recognizes the `$(MYLIBDIR)' at the beginning of a unit name and treats it specially in two ways:

If you use many units from the same library, brace expansion comes in handy:

 
aunit: $(MYLIBDIR)/{libunit1,libunit2} anotherunit

However, just declaring the direct library dependencies is often not enough. If, say, `$(MYLIBDIR)/libunit2' itself imports from `$(MYLIBDIR)/libunit0', the final linking command must be able to find `libunit0.uo'. One way to do this would be to add -I $(MYLIBDIR) to the linking command; another is to tell Mosmake that `$(MYLIBDIR)/libunit0.uo' must be part of the linking. Personally I like the latter approach better, because I want to avoid gratuitously extending the search space for unqualified file names the way `-I' does.

In either case, we need a way of telling Mosmake to include the linker dependencies exactly in the linking commands for programs that use the library. (Recall that Mosmake can build more than one program in a single project, and not all programs may need the libarary).

Adding the necessary extra text to the `Dependencies' line for each unit that uses the library might be a lot of typing (and it may also be difficult to understand and maintain later, because the extra dependencies do not refer to any import from the units that they are apparently attached to). We could couple the library units directly to what is necessary to make them work by saying, respectively,

 
$(MYLIBDIR)/libunit2: <l:-I $(MYLIBDIR)>

or

 
$(MYLIBDIR)/libunit2: $(MYLIBDIR)/libunit0

which would almost work -- except that Mosmake would generate rules for compiling `$(MYLIBDIR)/libunit2.uo' (and `.ui') from `$(MYLIBDIR)/libunit2.sml'. If you (or the user who compiles your code) do not actually have the `.sml' sources for the library, make will complain about them missing, and refuse to compile or link anything that depends on the libarary.

The solution is to add the special flag %NOCOMPILE to the `Dependencies' line for libarary units. That will suppress the generation of compilation rules for the unit in question, but the dependencies you give will still be used when constructing the final link command. Thus, you can say

 
$(MYLIBDIR)/libunit1: %NOCOMPILE <l:-I $(MYLIBDIR)>
$(MYLIBDIR)/libunit2: %NOCOMPILE <l:-I $(MYLIBDIR)>

or

 
$(MYLIBDIR)/libunit0: %NOCOMPILE
$(MYLIBDIR)/libunit1: %NOCOMPILE
$(MYLIBDIR)/libunit2: %NOCOMPILE $(MYLIBDIR)/libunit0


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

This document was generated by Henning Makholm on November, 19 2002 using texi2html