make/0 functionality for SICStus
Asked Answered
R

2

6

How can I ensure that all modules (and ideally also all other files that have been loaded or included) are up-to-date? When issuing use_module(mymodule), SICStus compares the modification date of the file mymodule.pl and reloads it, if newer. Also include-ed files will trigger a recompilation. But it does not recheck all modules used by mymodule.

Brief, how can I get similar functionality as SWI offers it with make/0?

Repetitive answered 1/1, 2016 at 18:44 Comment(0)
D
7

There is nothing in SICStus Prolog that provides that kind of functionality.

A big problem is that current Prologs are too dynamic for something like make/0 to work reliably except for very simple cases. With features like term expansion, goals executed during load (including file loading goals, which is common), etc., it is not possible to know how to reliably re-load files. I have not looked closely at it, but presumably make/0 in SWI Prolog has the same problem.

I usually just re-start the Prolog process and load the "main" file again, i.e. a file that loads everything I need.

PS. I was not able to get code formatting in the comments, so I put it here instead: Example why make/0 needs to guard against 'user' as the File from current_module/2:

| ?- [user].
% compiling user...
| :- module(m,[p/0]). p. end_of_file.

%  module m imported into user
% compiled user in module m, 0 msec 752 bytes
yes
| ?- current_module(M, F), F==user.
F = user,
M = m ? ;
no
| ?-
Dissimilate answered 1/1, 2016 at 21:35 Comment(3)
I second that. In SWI-Prolog, I use make/0 often for simple programs, but typically get things like ERROR: Socket error: Address already in use with slightly more complex client/server applications, HTTP libraries etc.Parfait
@mat: do you use initialization/1 properly?Repetitive
Ad P.S.: The effect of not testing against user in your example is that the systems prompts interactively upon make which is certainly annoying. Probably, an error in that case would be best - loading an entire module with [user] --- I never did that in my entire life.Repetitive
R
5

So far, I have lived with several hacks:

Up to 0.7 – pre-module times

SICStus always had ensure_loaded/1 of Quintus origin, which was not only a directive (like in ISO), but was also a command. So I wrote my own make-predicate simply enumerating all files:

l :-
   ensure_loaded([f1,f2,f3]).

Upon issuing l., only those files that were modified in the meantime were reloaded.

Probably, I could have written this also like — would I have read the meanual (sic):

l :-
   \+ ( source_file(F), \+ ensure_loaded(F) ).

3.0 – modules

With modules things changed a bit. On the one hand, there were those files that were loaded manually into a module, like ensure_loaded(module:[f1,f2,f3]), and then those that were clean modules. It turned out, that there is a way to globally ensure that a module is loaded — without interfering with the actual import lists simply by stating use_module(m1, []) which is again a directive and a command. The point is the empty list which caused the module to be rechecked and reloaded but thanks to the empty list that statement could be made everywhere.

In the meantime, I use the following module:

:- module(make,[make/0]).

make :-
   \+ ( current_module(_, F), \+ use_module(F, []) ).

This works for all "legal" modules — and as long as the interfaces do not change. What I still dislike is its verboseness: For each checked and unmodified module there is one message line. So I get a page full of such messages when I just want to check that everything is up-to-date. Ideally such messages would only show if something new happens.

| ?- make.
% module m2 imported into make
% module m1 imported into make
% module SU_messages imported into make
yes
| ?- make.
% module m2 imported into make
% module m1 imported into make
% module SU_messages imported into make
yes

An improved version takes @PerMildner's remark into account.

Further files can be reloaded, if they are related to exactly one module. In particular, files loading into module user are included like the .sicstusrc. See above link for the full code.

   % reload files that are implicitly modules, but that are still simple to reload
    \+ (
            source_file(F),
            F \== user,
            \+ current_module(_, F),  % not officially declared as a module
            setof(M,
                P^ExF^ExM^(
                    source_file(M:P,F),
                    \+ current_module(M,ExF), % not part of an official module
                    \+ predicate_property(M:P,multifile),
                    \+ predicate_property(M:P,imported_from(ExM))
                    ),[M]),   % only one module per file, others are too complex
            \+ ensure_loaded(M:F)
    ).

Note that in SWI neither ensure_loaded/1 nor use_module/2 compare file modification dates. So both cannot be used to ensure that the most recent version of a file is loaded.

Repetitive answered 1/1, 2016 at 22:30 Comment(2)
The extraneous import messages are a bug. Note that they only happen when the import list is empty.Dissimilate
You should add a F\==user to guard against the possibility that the module has been defined at the toplevel.Dissimilate

© 2022 - 2024 — McMap. All rights reserved.