1/* Part of SWI-Prolog 2 3 Author: Jan Wielemaker 4 E-mail: jan@swi-prolog.org 5 WWW: http://www.swi-prolog.org 6 Copyright (c) 2021, SWI-Prolog Solutions b.v. 7 All rights reserved. 8 9 Redistribution and use in source and binary forms, with or without 10 modification, are permitted provided that the following conditions 11 are met: 12 13 1. Redistributions of source code must retain the above copyright 14 notice, this list of conditions and the following disclaimer. 15 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in 18 the documentation and/or other materials provided with the 19 distribution. 20 21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 POSSIBILITY OF SUCH DAMAGE. 33*/ 34 35:- module(prolog_versions, 36 [ require_prolog_version/2 % +Required:atom, +Features:list 37 ]). 38:- autoload(library(apply), [maplist/2, maplist/3]).
Major.Minor[[.Patch][[-GitRev],-GitHash]]]
Example strings are '8.5', '8.5.0', '8.5.0-50', '8.5.0-69-gad38e8ad8`. The last two require fetching the sources from git or using the Windows daily builds.
Features is a list of required or preferred features. Individual features are:
library(Lib)
to be present. Thde library not being
there may indicate an incomplete installation. For example
library(pce) to demand xpce graphics support.current_prolog_flag(Flag, true)
to be true.current_prolog_flag(Flag,
Value)
to be true.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 /******************************* 160 * MESSAGES * 161 *******************************/ 162 163:- multifile 164 prolog:error_message//1. 165 166prologerror_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 ]. 173prologerror_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). 178prologerror_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] ]
Demand specific Prolog versions
This library is provided to make it easier to reason about software versions, in particular require that that hosting Prolog system is of the right version and provides the features required by the library or application.