mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-16 09:53:36 +00:00
... (mostly) in one place.
compiler/file_names.m:
Change the module_name_to_search_file_name predicate to
- take as input a specification of where the caller intends to search for
the file name returned by this predicate (the new search_which_dirs
input argument),
- use insts to check, at compile time, whether this specification
is compatible with the extension of the file (by intentionally causing
the call to have a mode error if they are not compatible),
- if they are compatible, return a "search authorization" that contains
the information in the search_which_dirs argument in a form that
should be known *only* to file_names.m (which issues the authorization)
and find_module.m (which acts on such authorizations).
To make the above possible, move the search_which_dirs type here
from find_module.m, move many insts on the ext type here from several
other modules, and add some new insts on that type.
Improve documentation.
compiler/find_module.m:
Delete the search_which_dirs type that this diff moves to file_names.m.
Add in its place the search_auth_dirs type, which represents search
authorizations. Make all predicates in this module take search
authorizations instead of search specifications as inputs.
The difference is that only the module_name_to_search_file_name
predicate in file_names.m, and a few functions in this module,
generate search authorizations that involve references to the
various options containing lists of directory names.
compiler/make.file_names.m:
Replace predicates that take a maybe_for_search argument with two
predicates each, one for not for search and one for search. This is
because the for search versions now take two extra arguments:
a search_which_dirs input argument and a search_auth_dirs output argument.
Factor out the common code from the resulting predicate pairs
where this is worth while.
Improve documentation.
compiler/make.timestamp.m:
Replace predicates that take a maybe_for_search argument with two
predicates each, one for not for search and one for search. This is
because the for search versions and the not_for_search versions
now call different predicates, and two separate predicates ends up
being less code that tests around all the calls.
Factor out the common code from the resulting predicate pairs
where this is worth while.
Delete the code that specifies the default list of directories
in which to search for files with given extensions, since it is now
in file_names.m (in a modified form).
compiler/analysis.framework.m:
Delete the inst definitions that this diff moves to file_names.m.
compiler/compile_target_code.m:
compiler/file_kind.m:
Provide more precise insts for the outputs of some predicates.
This is because some of their callers need those insts to satisfy
the new requirements of module_name_to_search_file_name.
compiler/make.top_level.m:
Add a note.
compiler/read_modules.m:
Conform to the changes above. Split the handling of source files
(which do not require search) from the handling of .int* and .*opt files
(which do).
compiler/analysis.file.m:
compiler/check_libgrades.m:
compiler/make.check_up_to_date.m:
compiler/make.get_module_dep_info.m:
compiler/make.module_target.m:
compiler/make.program_target.m:
compiler/mercury_compile_front_end.m:
compiler/mmc_analysis.m:
compiler/options_file.m:
compiler/write_deps_file.m:
Conform to the changes above.
449 lines
18 KiB
Mathematica
449 lines
18 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% vim: ft=mercury ts=4 sw=4 et
|
|
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 2023 The Mercury team.
|
|
% This file may only be copied under the terms of the GNU General
|
|
% Public License - see the file COPYING in the Mercury distribution.
|
|
%---------------------------------------------------------------------------%
|
|
%
|
|
% File: make.timestamp.m.
|
|
% Authors: stayl, wangp.
|
|
%
|
|
% Timestamp handling predicates used to implement `mmc --make'.
|
|
%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- module make.timestamp.
|
|
:- interface.
|
|
|
|
:- import_module libs.
|
|
:- import_module libs.file_util.
|
|
:- import_module libs.globals.
|
|
:- import_module libs.timestamp.
|
|
:- import_module make.make_info.
|
|
:- import_module parse_tree.
|
|
:- import_module parse_tree.find_module.
|
|
|
|
:- import_module io.
|
|
:- import_module list.
|
|
:- import_module maybe.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- func init_target_file_timestamp_map = target_file_timestamp_map.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% Find the timestamp for the given dependency file.
|
|
%
|
|
:- pred get_dependency_timestamp(io.text_output_stream::in, globals::in,
|
|
dependency_file::in, maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% get_target_timestamp(ProgressStream, Globals, TargetFile,
|
|
% MaybeTimestamp, !Info, !IO):
|
|
%
|
|
% Return the timestamp for TargetFile, if it exists.
|
|
%
|
|
:- pred get_target_timestamp(io.text_output_stream::in, globals::in,
|
|
target_file::in, maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
% get_target_timestamp_search(ProgressStream, Globals, TargetFile,
|
|
% MaybeTimestamp, !Info, !IO):
|
|
%
|
|
% Search for TargetFile in the places where its target type indicates
|
|
% it should be searched for, and return its timestamp if it exists.
|
|
%
|
|
:- pred get_target_timestamp_search(io.text_output_stream::in, globals::in,
|
|
target_file::in, maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
% get_file_timestamp(SearchAuthDirs, FileName,
|
|
% SearchDirs, MaybeTimestamp, !Info, !IO):
|
|
%
|
|
% Find the timestamp of the first file matching the given
|
|
% file name in one of the search directories. We return the list of
|
|
% directories we search in SearchDirs, or, if we got MaybeTimestamp
|
|
% from the cache, we return the list of directories we searched
|
|
% when the cache entry was created.
|
|
%
|
|
:- pred get_file_timestamp(search_auth_dirs::in, file_name::in,
|
|
list(dir_name)::out, maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
%---------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module analysis.
|
|
:- import_module analysis.framework.
|
|
:- import_module analysis.operations.
|
|
:- import_module make.file_names.
|
|
:- import_module make.get_module_dep_info.
|
|
:- import_module make.hash.
|
|
:- import_module mdbcomp.
|
|
:- import_module mdbcomp.sym_name.
|
|
:- import_module parse_tree.module_dep_info.
|
|
:- import_module transform_hlds.
|
|
:- import_module transform_hlds.mmc_analysis.
|
|
|
|
:- import_module dir.
|
|
:- import_module map.
|
|
:- import_module require.
|
|
:- import_module string.
|
|
:- import_module version_hash_table.
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
init_target_file_timestamp_map =
|
|
version_hash_table.unsafe_init_default(target_file_hash).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_dependency_timestamp(ProgressStream, Globals, DependencyFile,
|
|
MaybeTimestamp, !Info, !IO) :-
|
|
(
|
|
DependencyFile = dep_file(FileName),
|
|
get_file_timestamp(search_auth_cur_dir, FileName,
|
|
_SearchDirs, MaybeTimestamp, !Info, !IO)
|
|
;
|
|
DependencyFile = dep_target(Target),
|
|
get_target_timestamp_search(ProgressStream, Globals, Target,
|
|
MaybeTimestamp0, !Info, !IO),
|
|
( if
|
|
Target = target_file(_, module_target_c_header(header_mih)),
|
|
MaybeTimestamp0 = ok(_)
|
|
then
|
|
% Don't rebuild the `.o' file if an irrelevant part of a
|
|
% `.mih' file has changed. If a relevant part of a `.mih'
|
|
% file changed, the interface files of the imported module
|
|
% must have changed in a way that would force the `.c' and
|
|
% `.o' files of the current module to be rebuilt.
|
|
MaybeTimestamp = ok(oldest_timestamp)
|
|
else
|
|
MaybeTimestamp = MaybeTimestamp0
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_target_timestamp(ProgressStream, Globals, TargetFile, MaybeTimestamp,
|
|
!Info, !IO) :-
|
|
TargetFile = target_file(ModuleName, TargetType),
|
|
( if TargetType = module_target_analysis_registry then
|
|
% XXX LEGACY
|
|
module_target_to_file_name(Globals, $pred,
|
|
TargetType, ModuleName, FileName, _FileNameProposed, !IO),
|
|
get_target_timestamp_analysis_registry(ProgressStream, Globals,
|
|
TargetFile, FileName, MaybeTimestamp, !Info, !IO)
|
|
else
|
|
( if is_timestamp_in_cache(!.Info, TargetFile, Timestamp) then
|
|
trace [compile_time(flag("target_timestamp_cache")), io(!TIO)] (
|
|
verify_cached_target_file_timestamp(ProgressStream,
|
|
Globals, TargetFile, Timestamp, !.Info, _Info, !TIO)
|
|
),
|
|
MaybeTimestamp = ok(Timestamp)
|
|
else
|
|
% XXX LEGACY
|
|
module_maybe_nested_target_file_to_file_name(ProgressStream,
|
|
Globals, $pred, TargetFile,
|
|
FileName, _FileNameProposed, !Info, !IO),
|
|
get_target_timestamp_uncached(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, MaybeTimestamp, !Info, !IO),
|
|
record_timestamp_if_ok(TargetFile, MaybeTimestamp, !Info)
|
|
)
|
|
).
|
|
|
|
get_target_timestamp_search(ProgressStream, Globals, TargetFile,
|
|
MaybeTimestamp, !Info, !IO) :-
|
|
TargetFile = target_file(ModuleName, TargetType),
|
|
( if TargetType = module_target_analysis_registry then
|
|
% XXX LEGACY
|
|
module_target_to_search_file_name(Globals, $pred,
|
|
TargetType, ModuleName, SearchAuthDirs,
|
|
FileName, _FileNameProposed, !IO),
|
|
get_target_timestamp_analysis_registry_search(ProgressStream, Globals,
|
|
SearchAuthDirs, TargetFile, FileName, MaybeTimestamp, !Info, !IO)
|
|
else
|
|
( if is_timestamp_in_cache(!.Info, TargetFile, Timestamp) then
|
|
trace [compile_time(flag("target_timestamp_cache")), io(!TIO)] (
|
|
verify_cached_target_file_timestamp_search(ProgressStream,
|
|
Globals, TargetFile, Timestamp, !.Info, _Info, !TIO)
|
|
),
|
|
MaybeTimestamp = ok(Timestamp)
|
|
else
|
|
% XXX LEGACY
|
|
module_maybe_nested_target_file_to_search_file_name(ProgressStream,
|
|
Globals, $pred, TargetFile, SearchAuthDirs,
|
|
FileName, _FileNameProposed, !Info, !IO),
|
|
get_target_timestamp_uncached_search(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, SearchAuthDirs,
|
|
MaybeTimestamp, !Info, !IO),
|
|
record_timestamp_if_ok(TargetFile, MaybeTimestamp, !Info)
|
|
)
|
|
).
|
|
|
|
%---------------%
|
|
|
|
% The code points we are called from are hit very frequently, so it is
|
|
% worth caching timestamps by target_file. It avoids having to compute
|
|
% a file name for a target_file first, before looking up its timestamp.
|
|
% XXX Wouldn't the search be even faster if, instead of the module's
|
|
% name, our caller gave us its module_index?
|
|
%
|
|
:- pred is_timestamp_in_cache(make_info::in, target_file::in,
|
|
timestamp::out) is semidet.
|
|
|
|
is_timestamp_in_cache(Info0, TargetFile, Timestamp) :-
|
|
Cache0 = make_info_get_target_file_timestamp_map(Info0),
|
|
version_hash_table.search(Cache0, TargetFile, Timestamp).
|
|
|
|
:- pred record_timestamp_if_ok(target_file::in, maybe_error(timestamp)::in,
|
|
make_info::in, make_info::out) is det.
|
|
|
|
record_timestamp_if_ok(TargetFile, MaybeTimestamp, !Info) :-
|
|
(
|
|
MaybeTimestamp = ok(Timestamp),
|
|
TargetFileTimestampMap0 =
|
|
make_info_get_target_file_timestamp_map(!.Info),
|
|
version_hash_table.det_insert(TargetFile, Timestamp,
|
|
TargetFileTimestampMap0, TargetFileTimestampMap),
|
|
make_info_set_target_file_timestamp_map(TargetFileTimestampMap, !Info)
|
|
;
|
|
MaybeTimestamp = error(_)
|
|
% Do not record errors. These would usually be due to files
|
|
% not yet made, and the result would have to be updated
|
|
% once the file *is* made.
|
|
).
|
|
|
|
%---------------%
|
|
|
|
:- pred verify_cached_target_file_timestamp(io.text_output_stream::in,
|
|
globals::in, target_file::in, timestamp::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
verify_cached_target_file_timestamp(ProgressStream, Globals,
|
|
TargetFile, CachedTimestamp, !Info, !IO) :-
|
|
TargetFile = target_file(ModuleName, TargetType),
|
|
% XXX LEGACY
|
|
module_maybe_nested_target_file_to_file_name(ProgressStream,
|
|
Globals, $pred, TargetFile, FileName, _FileNameProposed, !Info, !IO),
|
|
get_target_timestamp_uncached(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, MaybeFileTimestamp, !Info, !IO),
|
|
abort_for_any_verification_failure(CachedTimestamp,
|
|
MaybeFileTimestamp, !Info).
|
|
|
|
:- pred verify_cached_target_file_timestamp_search(io.text_output_stream::in,
|
|
globals::in, target_file::in, timestamp::in,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
verify_cached_target_file_timestamp_search(ProgressStream, Globals,
|
|
TargetFile, CachedTimestamp, !Info, !IO) :-
|
|
TargetFile = target_file(ModuleName, TargetType),
|
|
% XXX LEGACY
|
|
module_maybe_nested_target_file_to_search_file_name(ProgressStream,
|
|
Globals, $pred, TargetFile, SearchAuthDirs,
|
|
FileName, _FileNameProposed, !Info, !IO),
|
|
get_target_timestamp_uncached_search(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, SearchAuthDirs,
|
|
MaybeFileTimestamp, !Info, !IO),
|
|
abort_for_any_verification_failure(CachedTimestamp,
|
|
MaybeFileTimestamp, !Info).
|
|
|
|
%---------------%
|
|
|
|
% We take a in,out pair of make_info args because we don't want calls
|
|
% to this predicate to be deleted as det code that computes nothing.
|
|
%
|
|
:- pred abort_for_any_verification_failure(timestamp::in,
|
|
maybe_error(timestamp)::in, make_info::in, make_info::out) is det.
|
|
:- pragma no_inline(pred(abort_for_any_verification_failure/4)).
|
|
|
|
abort_for_any_verification_failure(CachedTimestamp, MaybeFileTimestamp,
|
|
Info0, Info) :-
|
|
(
|
|
MaybeFileTimestamp = ok(FileTimestamp),
|
|
( if CachedTimestamp = FileTimestamp then
|
|
Info = Info0
|
|
else
|
|
string.format(
|
|
"target file timestamp differs: %s (cached) vs %s (actual)",
|
|
[s(timestamp_to_string(CachedTimestamp)),
|
|
s(timestamp_to_string(FileTimestamp))], Msg),
|
|
unexpected($pred, Msg)
|
|
)
|
|
;
|
|
MaybeFileTimestamp = error(Error),
|
|
string.format(
|
|
"target file timestamp differs: %s (cached) vs %s (actual)",
|
|
[s(timestamp_to_string(CachedTimestamp)), s(Error)], Msg),
|
|
unexpected($pred, Msg)
|
|
).
|
|
|
|
%---------------%
|
|
|
|
% Special treatment for `.analysis' files. If the corresponding
|
|
% `.analysis_status' file says the `.analysis' file is invalid,
|
|
% then we treat it as out of date.
|
|
%
|
|
:- pred get_target_timestamp_analysis_registry(io.text_output_stream::in,
|
|
globals::in, target_file::in, file_name::in, maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
get_target_timestamp_analysis_registry(ProgressStream, Globals,
|
|
TargetFile, FileName, MaybeTimestamp, !Info, !IO) :-
|
|
TargetFile = target_file(ModuleName, TargetType),
|
|
FileTimestampMap0 = make_info_get_file_timestamp_map(!.Info),
|
|
( if map.search(FileTimestampMap0, FileName, MapValue) then
|
|
MapValue = {_SearchDirs, MaybeTimestamp}
|
|
else
|
|
do_read_module_overall_status(mmc, Globals, ModuleName, Status, !IO),
|
|
(
|
|
( Status = optimal
|
|
; Status = suboptimal
|
|
),
|
|
get_target_timestamp_uncached(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, MaybeTimestamp, !Info, !IO)
|
|
;
|
|
Status = invalid,
|
|
MaybeTimestamp = error("invalid module"),
|
|
map.det_insert(FileName, {[], MaybeTimestamp},
|
|
FileTimestampMap0, FileTimestampMap),
|
|
make_info_set_file_timestamp_map(FileTimestampMap, !Info)
|
|
)
|
|
).
|
|
|
|
:- pred get_target_timestamp_analysis_registry_search(
|
|
io.text_output_stream::in, globals::in, search_auth_dirs::in,
|
|
target_file::in, file_name::in, maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
get_target_timestamp_analysis_registry_search(ProgressStream, Globals,
|
|
SearchAuthDirs, TargetFile, FileName, MaybeTimestamp, !Info, !IO) :-
|
|
TargetFile = target_file(ModuleName, TargetType),
|
|
FileTimestampMap0 = make_info_get_file_timestamp_map(!.Info),
|
|
( if map.search(FileTimestampMap0, FileName, MapValue) then
|
|
MapValue = {_SearchDirs, MaybeTimestamp}
|
|
else
|
|
do_read_module_overall_status(mmc, Globals, ModuleName, Status, !IO),
|
|
(
|
|
( Status = optimal
|
|
; Status = suboptimal
|
|
),
|
|
get_target_timestamp_uncached_search(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, SearchAuthDirs,
|
|
MaybeTimestamp, !Info, !IO)
|
|
;
|
|
Status = invalid,
|
|
MaybeTimestamp = error("invalid module"),
|
|
map.det_insert(FileName, {[], MaybeTimestamp},
|
|
FileTimestampMap0, FileTimestampMap),
|
|
make_info_set_file_timestamp_map(FileTimestampMap, !Info)
|
|
)
|
|
).
|
|
|
|
%---------------%
|
|
|
|
:- pred get_target_timestamp_uncached(io.text_output_stream::in,
|
|
globals::in, module_name::in, module_target_type::in, file_name::in,
|
|
maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
get_target_timestamp_uncached(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, MaybeTimestamp, !Info, !IO) :-
|
|
SearchAuthDirs = search_auth_cur_dir,
|
|
get_file_timestamp(SearchAuthDirs, FileName,
|
|
SearchDirs, MaybeTimestamp0, !Info, !IO),
|
|
get_target_timestamp_handle_any_errors(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, SearchDirs,
|
|
MaybeTimestamp0, MaybeTimestamp, !Info, !IO).
|
|
|
|
:- pred get_target_timestamp_uncached_search(io.text_output_stream::in,
|
|
globals::in, module_name::in, module_target_type::in, file_name::in,
|
|
search_auth_dirs::in, maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
get_target_timestamp_uncached_search(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, SearchAuthDirs, MaybeTimestamp,
|
|
!Info, !IO) :-
|
|
get_file_timestamp(SearchAuthDirs, FileName,
|
|
SearchDirs, MaybeTimestamp0, !Info, !IO),
|
|
get_target_timestamp_handle_any_errors(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, SearchDirs,
|
|
MaybeTimestamp0, MaybeTimestamp, !Info, !IO).
|
|
|
|
% If a `.opt' file in another directory doesn't exist, it just means
|
|
% that a library wasn't compiled with `--intermodule-optimization'.
|
|
% Similarly for `.analysis' files.
|
|
%
|
|
:- pred get_target_timestamp_handle_any_errors(io.text_output_stream::in,
|
|
globals::in, module_name::in, module_target_type::in, file_name::in,
|
|
list(dir_name)::in,
|
|
maybe_error(timestamp)::in, maybe_error(timestamp)::out,
|
|
make_info::in, make_info::out, io::di, io::uo) is det.
|
|
|
|
get_target_timestamp_handle_any_errors(ProgressStream, Globals,
|
|
ModuleName, TargetType, FileName, SearchDirs,
|
|
MaybeTimestamp0, MaybeTimestamp, !Info, !IO) :-
|
|
( if
|
|
MaybeTimestamp0 = error(_),
|
|
( TargetType = module_target_opt
|
|
; TargetType = module_target_analysis_registry
|
|
)
|
|
then
|
|
get_maybe_module_dep_info(ProgressStream, Globals,
|
|
ModuleName, MaybeModuleDepInfo, !Info, !IO),
|
|
( if
|
|
MaybeModuleDepInfo = some_module_dep_info(ModuleDepInfo),
|
|
module_dep_info_get_source_file_dir(ModuleDepInfo, ModuleDir),
|
|
% NOTE This test can't succeed for the non-search caller.
|
|
ModuleDir \= dir.this_directory
|
|
then
|
|
MaybeTimestamp = ok(oldest_timestamp),
|
|
FileTimestampMap0 = make_info_get_file_timestamp_map(!.Info),
|
|
map.set(FileName, {SearchDirs, MaybeTimestamp},
|
|
FileTimestampMap0, FileTimestampMap),
|
|
make_info_set_file_timestamp_map(FileTimestampMap, !Info)
|
|
else
|
|
MaybeTimestamp = MaybeTimestamp0
|
|
)
|
|
else
|
|
MaybeTimestamp = MaybeTimestamp0
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
|
|
get_file_timestamp(SearchAuthDirs, FileName,
|
|
SearchDirs, MaybeTimestamp, !Info, !IO) :-
|
|
FileTimestampMap0 = make_info_get_file_timestamp_map(!.Info),
|
|
( if map.search(FileTimestampMap0, FileName, MapValue) then
|
|
MapValue = {SearchDirs, MaybeTimestamp}
|
|
else
|
|
search_for_file_mod_time(SearchAuthDirs, FileName,
|
|
SearchDirs, SearchResult, !IO),
|
|
(
|
|
SearchResult = ok(TimeT),
|
|
Timestamp = time_t_to_timestamp(TimeT),
|
|
MaybeTimestamp = ok(Timestamp),
|
|
map.det_insert(FileName, {SearchDirs, MaybeTimestamp},
|
|
FileTimestampMap0, FileTimestampMap),
|
|
make_info_set_file_timestamp_map(FileTimestampMap, !Info)
|
|
;
|
|
SearchResult = error(_SearchError),
|
|
% XXX MAKE We should not ignore _SearchError.
|
|
% XXX SEARCH_ERROR SearchDirs
|
|
string.format("file `%s' not found", [s(FileName)], NotFoundMsg),
|
|
MaybeTimestamp = error(NotFoundMsg)
|
|
)
|
|
).
|
|
|
|
%---------------------------------------------------------------------------%
|
|
:- end_module make.timestamp.
|
|
%---------------------------------------------------------------------------%
|