mercury

Mercury "undefined reference" compilation error when using local module


I have a module exporting nat/1 to test/generate natural numbers:

:- module nat.

:- interface.

:- import_module int.

:- pred nat(int).
:- mode nat(in) is det.
:- mode nat(out) is multi.

:- implementation.

:- pragma promise_pure(nat/1).
nat(_::in).
nat(0::out).
nat(X::out) :- nat(Y), X = Y + 1.

and a main module in the same directory to try it out:

:- module main.

:- interface.
:- import_module io.

:- pred main(io__state::di, io__state::uo) is cc_multi.

:- implementation.
:- import_module nat.

main(!IO) :- nat(X), print(X, !IO).

I run mmc --make-int nat.m which successfully generates the interface files, but then when I run mmc main.m I get the following error:

/usr/bin/ld: main.o: in function `<predicate 'main'/2 mode 0>':
main.c:(.text+0x45): undefined reference to `<predicate 'nat.nat'/1 mode 1>'
collect2: error: ld returned 1 exit status

I'm using MMC version 20.06.1, on x86_64-pc-linux-gnu.

Am I missing something obvious? Code improvements are also very welcome.


Solution

  • After "mmc --make-int nat.m", the command you need to run is not "mmc main.m", but "mmc main.m nat.m". The former compiles only main.m, while the latter also compiles nat.m. Both attempt to build an executable from the resulting object files, but the former will fail, since the definition of the "nat" predicate would be in the object file it does not generate.

    In general, instead of trying to manage the creation of interface files, object files and executables manually, it is much easier to use an automated build system: either the mmake script, or mmc --make.

    As for code improvements, I would suggest replacing io__state with just plain io, which is a lot shorter. We added "io" as a synonym for the "state" type in io.m specifically to make this possible.