1########################################################################### 2# A module to handle XML descriptors 3# 4# Copyright (C) 2015-2018 Andrey Ponomarenko's ABI Laboratory 5# 6# Written by Andrey Ponomarenko 7# 8# This library is free software; you can redistribute it and/or 9# modify it under the terms of the GNU Lesser General Public 10# License as published by the Free Software Foundation; either 11# version 2.1 of the License, or (at your option) any later version. 12# 13# This library is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16# Lesser General Public License for more details. 17# 18# You should have received a copy of the GNU Lesser General Public 19# License along with this library; if not, write to the Free Software 20# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 21# MA 02110-1301 USA 22########################################################################### 23use strict; 24 25sub createDesc($$) 26{ 27 my ($Path, $LVer) = @_; 28 29 if(not -e $Path) { 30 return undef; 31 } 32 33 if(-d $Path) 34 { # directory with headers files and shared objects 35 return " 36 <version> 37 ".$In::Desc{$LVer}{"TargetVersion"}." 38 </version> 39 40 <headers> 41 $Path 42 </headers> 43 44 <libs> 45 $Path 46 </libs>"; 47 } 48 else 49 { # files 50 if($Path=~/\.(xml|desc)\Z/i) 51 { # standard XML-descriptor 52 return readFile($Path); 53 } 54 elsif(isHeaderFile($Path)) 55 { # header file 56 $In::Opt{"CheckHeadersOnly"} = 1; 57 return " 58 <version> 59 ".$In::Desc{$LVer}{"TargetVersion"}." 60 </version> 61 62 <headers> 63 $Path 64 </headers> 65 66 <libs> 67 </libs>"; 68 } 69 else 70 { # standard XML-descriptor 71 return readFile($Path); 72 } 73 } 74} 75 76sub readDesc($$) 77{ 78 my ($Content, $LVer) = @_; 79 80 if(not $Content) { 81 exitStatus("Error", "XML descriptor is empty"); 82 } 83 if($Content!~/\</) { 84 exitStatus("Error", "incorrect descriptor (see -d1 option)"); 85 } 86 87 $Content=~s/\/\*(.|\n)+?\*\///g; 88 $Content=~s/<\!--(.|\n)+?-->//g; 89 90 my $DescRef = $In::Desc{$LVer}; 91 92 $DescRef->{"Version"} = parseTag(\$Content, "version"); 93 if(my $TV = $DescRef->{"TargetVersion"}) { 94 $DescRef->{"Version"} = $TV; 95 } 96 elsif($DescRef->{"Version"} eq "") #Allow the version to be a string 97 { 98 if($LVer==1) 99 { 100 $DescRef->{"Version"} = "X"; 101 print STDERR "WARNING: version number #1 is not set (use --v1=NUM option)\n"; 102 } 103 else 104 { 105 $DescRef->{"Version"} = "Y"; 106 print STDERR "WARNING: version number #2 is not set (use --v2=NUM option)\n"; 107 } 108 } 109 110 if(not $DescRef->{"Version"}) { 111 exitStatus("Error", "version in the XML descriptor is not specified (section \"version\")"); 112 } 113 if($Content=~/\{RELPATH\}/) 114 { 115 if(my $RelDir = $DescRef->{"RelativeDirectory"}) { 116 $Content =~ s/\{RELPATH\}/$RelDir/g; 117 } 118 else { 119 exitStatus("Error", "you have not specified -relpath* option, but the XML descriptor contains {RELPATH} macro"); 120 } 121 } 122 123 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "headers"))) 124 { 125 if(not -e $Path) { 126 exitStatus("Access_Error", "can't access \'$Path\'"); 127 } 128 129 $DescRef->{"Headers"}{$Path} = keys(%{$DescRef->{"Headers"}}); 130 } 131 if(not defined $DescRef->{"Headers"}) { 132 exitStatus("Error", "can't find header files info in the XML descriptor"); 133 } 134 135 if(not $In::Opt{"CheckHeadersOnly"}) 136 { 137 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "libs"))) 138 { 139 if(not -e $Path) { 140 exitStatus("Access_Error", "can't access \'$Path\'"); 141 } 142 143 $DescRef->{"Libs"}{$Path} = 1; 144 } 145 146 if(not defined $DescRef->{"Libs"}) { 147 exitStatus("Error", "can't find libraries info in the XML descriptor"); 148 } 149 } 150 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers"))) 151 { 152 if(not -d $Path) { 153 exitStatus("Access_Error", "can't access directory \'$Path\'"); 154 } 155 $Path = getAbsPath($Path); 156 push_U($In::Opt{"SysPaths"}{"include"}, $Path); 157 } 158 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs"))) 159 { 160 if(not -d $Path) { 161 exitStatus("Access_Error", "can't access directory \'$Path\'"); 162 } 163 $Path = getAbsPath($Path); 164 push_U($In::Opt{"SysPaths"}{"lib"}, $Path); 165 } 166 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools"))) 167 { 168 if(not -d $Path) { 169 exitStatus("Access_Error", "can't access directory \'$Path\'"); 170 } 171 $Path = getAbsPath($Path); 172 push_U($In::Opt{"SysPaths"}{"bin"}, $Path); 173 $In::Opt{"TargetTools"}{$Path} = 1; 174 } 175 if(my $Prefix = parseTag(\$Content, "cross_prefix")) { 176 $In::Opt{"CrossPrefix"} = $Prefix; 177 } 178 179 $DescRef->{"IncludePaths"} = []; 180 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths"))) 181 { 182 if(not -d $Path) { 183 exitStatus("Access_Error", "can't access directory \'$Path\'"); 184 } 185 $Path = getAbsPath($Path); 186 push(@{$DescRef->{"IncludePaths"}}, $Path); 187 } 188 189 if(not @{$DescRef->{"IncludePaths"}}) { 190 $DescRef->{"AutoIncludePaths"} = 1; 191 } 192 193 $DescRef->{"AddIncludePaths"} = []; 194 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths"))) 195 { 196 if(not -d $Path) { 197 exitStatus("Access_Error", "can't access directory \'$Path\'"); 198 } 199 $Path = getAbsPath($Path); 200 push(@{$DescRef->{"AddIncludePaths"}}, $Path); 201 } 202 203 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths"))) 204 { # skip some auto-generated include paths 205 $Path = getAbsPath($Path); 206 $DescRef->{"SkipIncludePaths"}{$Path} = 1; 207 } 208 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including"))) 209 { # skip direct including of some headers 210 if(my ($CPath, $Type) = classifyPath($Path)) { 211 $DescRef->{"SkipHeaders"}{$Type}{$CPath} = 2; 212 } 213 } 214 foreach my $Option (split(/\s*\n\s*/, parseTag(\$Content, "gcc_options"))) 215 { 216 if($Option!~/\A\-(Wl|l|L)/) 217 { # skip linker options 218 $DescRef->{"CompilerOptions"} .= " ".$Option; 219 } 220 } 221 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_headers"))) 222 { 223 if(my ($CPath, $Type) = classifyPath($Path)) { 224 $DescRef->{"SkipHeaders"}{$Type}{$CPath} = 1; 225 } 226 } 227 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_libs"))) 228 { 229 if(my ($CPath, $Type) = classifyPath($Path)) { 230 $DescRef->{"SkipLibs"}{$Type}{$CPath} = 1; 231 } 232 } 233 if(my $DDefines = parseTag(\$Content, "defines")) 234 { 235 if($DescRef->{"Defines"}) 236 { # multiple descriptors 237 $DescRef->{"Defines"} .= "\n".$DDefines; 238 } 239 else { 240 $DescRef->{"Defines"} = $DDefines; 241 } 242 } 243 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order"))) 244 { 245 if($Order=~/\A(.+):(.+)\Z/) { 246 $DescRef->{"IncludeOrder"}{$1} = $2; 247 } 248 } 249 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "add_namespaces"))) { 250 $DescRef->{"AddNameSpaces"}{$NameSpace} = 1; 251 } 252 if(my $DIncPreamble = parseTag(\$Content, "include_preamble")) 253 { 254 if($DescRef->{"IncludePreamble"}) 255 { # multiple descriptors 256 $DescRef->{"IncludePreamble"} .= "\n".$DIncPreamble; 257 } 258 else { 259 $DescRef->{"IncludePreamble"} = $DIncPreamble; 260 } 261 } 262 263 readFilter($Content, $LVer); 264} 265 266sub readFilter($$) 267{ 268 my ($Content, $LVer) = @_; 269 270 $Content=~s/\/\*(.|\n)+?\*\///g; 271 $Content=~s/<\!--(.|\n)+?-->//g; 272 273 my $DescRef = $In::Desc{$LVer}; 274 275 foreach my $TName (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")), 276 split(/\s*\n\s*/, parseTag(\$Content, "skip_types"))) { 277 $DescRef->{"SkipTypes"}{$TName} = 1; 278 } 279 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")), 280 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols"))) { 281 $DescRef->{"SkipSymbols"}{$Symbol} = 1; 282 } 283 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) { 284 $DescRef->{"SkipNameSpaces"}{$NameSpace} = 1; 285 } 286 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) { 287 $DescRef->{"SkipConstants"}{$Constant} = 1; 288 } 289} 290 291return 1; 292