34
35:- module(prolog_versions,
36 [ require_prolog_version/2 37 ]). 38:- autoload(library(apply), [maplist/2, maplist/3]). 39
52
86
87require_prolog_version(Required, Features) :-
88 require_prolog_version(Required),
89 maplist(check_feature, Features).
90
91require_prolog_version(Required) :-
92 parse_version(Required, ReqNumbers, GitReq),
93 current_prolog_flag(version_data, swi(Major, Minor, Patch, _)),
94 VNumbers = [Major, Minor, Patch],
95 atomic_list_concat(VNumbers, '.', VAtom),
96 ( ReqNumbers @< VNumbers
97 -> true
98 ; GitReq = git(ReqRev, ReqHash),
99 ReqNumbers == VNumbers
100 -> ( current_prolog_flag(version_git, GitVersion)
101 -> parse_version(GitVersion, _, git(Rev, Hash)),
102 ( ReqRev < Rev
103 -> true
104 ; ReqRev == Rev,
105 ( ( ReqHash == '-' ;
106 ReqHash == Hash
107 )
108 -> true
109 ; prolog_version_error(Required, GitVersion)
110 )
111 -> true
112 ; prolog_version_error(Required, GitVersion)
113 )
114 ; prolog_version_error(Required, VAtom)
115 )
116 ; ReqNumbers == VNumbers
117 -> true
118 ; prolog_version_error(Required, VAtom)
119 ).
120
121prolog_version_error(Required, Found) :-
122 throw(error(prolog_version(Required, Found), _)).
123
124parse_version(String, ReqNumbers, git(GitRev, GitHash)) :-
125 split_string(String, "-", "", [NumberS,GitRevS|Hash]),
126 !,
127 split_string(NumberS, ".", "", List),
128 maplist(number_string, ReqNumbers, List),
129 number_string(GitRev, GitRevS),
130 ( Hash = [HashS]
131 -> atom_string(GitHash, HashS)
132 ; GitHash = '-'
133 ).
134parse_version(String, ReqNumbers, -) :-
135 split_string(String, ".", "", List),
136 maplist(number_string, ReqNumbers, List).
137
138check_feature(warning(Flag)) :-
139 !,
140 ( has_feature(Flag)
141 -> true
142 ; print_message(warning, error(prolog_feature(warning(Flag)), _))
143 ).
144check_feature(Flag) :-
145 has_feature(Flag),
146 !.
147check_feature(Flag) :-
148 throw(error(prolog_feature(Flag), _)).
149
150has_feature(rational) =>
151 current_prolog_flag(bounded, false).
152has_feature(library(Lib)) =>
153 exists_source(library(Lib)).
154has_feature(Flag), atom(Flag) =>
155 current_prolog_flag(Flag, true).
156has_feature(Flag), Flag =.. [Name|Arg] =>
157 current_prolog_flag(Name, Arg).
158
159 162
163:- multifile
164 prolog:error_message//1. 165
166prolog:error_message(prolog_version(Required, Found)) -->
167 { current_prolog_flag(executable, Exe) },
168 [ 'Application requires at least SWI-Prolog ',
169 ansi(code, '~p', [Required]), ',', nl, ' ',
170 ansi(code, '~p', [Exe]), ' has version ',
171 ansi(code, '~p', [Found])
172 ].
173prolog:error_message(prolog_feature(warning(Feature))) -->
174 [ 'This version of SWI-Prolog does not optimally support your application because', nl,
175 ' '
176 ],
177 missing_feature(Feature).
178prolog:error_message(prolog_feature(Feature)) -->
179 [ 'This version of SWI-Prolog cannot run your application because', nl,
180 ' '
181 ],
182 missing_feature(Feature).
183
184missing_feature(threads) -->
185 [ 'multi-threading is not available' ].
186missing_feature(rational) -->
187 [ 'it has no support for rational numbers' ].
188missing_feature(bounded(false)) -->
189 [ 'it has no support for unbounded arithmetic' ].
190missing_feature(library(Lib)) -->
191 [ 'it does not provide library(~q)'-[Lib] ].
192missing_feature(Feature) -->
193 [ 'it does not support ~p'-[Feature] ]