1 /* 2 * This file is part of gir-to-d. 3 * 4 * gir-to-d is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation, either version 3 7 * of the License, or (at your option) any later version. 8 * 9 * gir-to-d is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public License 15 * along with gir-to-d. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 module gtd.GirPackage; 19 20 import std.algorithm; 21 import std.array : join, replace; 22 import std.conv; 23 import std.file; 24 import std.path : baseName, buildNormalizedPath; 25 import std.range : array, back, chain, empty; 26 import std.regex : ctRegex, matchFirst; 27 import std.stdio; 28 import std.string : split, splitLines, strip; 29 import std.uni; 30 31 import gtd.DefReader; 32 import gtd.GirAlias; 33 import gtd.GirConstant; 34 import gtd.GirEnum; 35 import gtd.GirFunction; 36 import gtd.GirStruct; 37 import gtd.GirVersion; 38 import gtd.GirWrapper; 39 import gtd.GlibTypes; 40 import gtd.IndentedStringBuilder; 41 import gtd.LinkedHasMap: Map = LinkedHashMap; 42 import gtd.Log; 43 import gtd.XMLReader; 44 45 final class GirPackage 46 { 47 string name; 48 string cTypePrefix; 49 string srcDir; 50 GirVersion _version; 51 GirWrapper wrapper; 52 53 string[] lookupAliases; /// Aliases defined in the lookupfile. 54 string[] lookupConstants; /// Constants defined in the lookupfile. 55 string[] lookupEnums; /// Enums defined in the lookupfile. 56 string[] lookupFuncts; /// Functions defined in the lookupfile. 57 string[] lookupStructs; /// Structs defined in the lookupfile. 58 59 static GirPackage[string] namespaces; 60 static GirInclude[string] includes; 61 62 string[] libraries; 63 Map!(string, GirAlias) collectedAliases; /// Aliases defined in the gir file. 64 Map!(string, GirFunction) collectedCallbacks; 65 Map!(string, GirConstant) collectedConstants; 66 Map!(string, GirEnum) collectedEnums; /// Enums defined in the gir file. 67 Map!(string, GirFunction) collectedFunctions; 68 Map!(string, GirStruct) collectedStructs; 69 GirEnum stockIDs; /// The StockID enum (Deprecated). 70 GirEnum gdkKeys; /// The GdkKey enum. 71 72 public this(string pack, GirWrapper wrapper, string srcDir) 73 { 74 this.name = pack; 75 this.wrapper = wrapper; 76 this.srcDir = srcDir; 77 this.stockIDs = new GirEnum(wrapper, this); 78 this.gdkKeys = new GirEnum(wrapper, this); 79 80 GirInclude gobject; 81 gobject.name = "GObject"; 82 gobject._version = "2.0"; 83 includes["GObject"] = gobject; 84 } 85 86 void parseGIR(string girFile) 87 { 88 if ( !exists(girFile) ) 89 error("GIR file: '", girFile, "' not found."); 90 91 auto reader = new XMLReader!string(readText(girFile), girFile); 92 93 while ( !reader.empty && reader.front.value != "repository" ) 94 reader.popFront(); 95 96 reader.popFront(); 97 98 while ( !reader.empty && reader.front.value == "include" ) 99 { 100 string incName = reader.front.attributes["name"]; 101 102 GirInclude inc = includes.get(incName, GirInclude.init); 103 inc.name = incName; 104 inc._version = reader.front.attributes["version"]; 105 includes[incName] = inc; 106 107 reader.popFront(); 108 } 109 110 while ( !reader.empty && reader.front.value != "namespace" ) 111 reader.popFront(); 112 113 if ( name.empty ) 114 name = reader.front.attributes["name"].toLower(); 115 116 namespaces[reader.front.attributes["name"]] = this; 117 checkVersion(reader.front.attributes["version"]); 118 119 if ( "c:identifier-prefixes" in reader.front.attributes ) 120 { 121 auto p = reader.front.attributes["c:identifier-prefixes"]; 122 if ( p.length ) 123 cTypePrefix = p.split(',')[0]; 124 } 125 126 if ( "shared-library" in reader.front.attributes ) 127 { 128 version(Windows) 129 libraries ~= reader.front.attributes["shared-library"].split(',').map!(a => a.startsWith("lib")?a:"lib"~a~".dll").array; 130 else version(OSX) 131 libraries ~= reader.front.attributes["shared-library"].split(',').map!(a => a.baseName.startsWith("lib")?a.baseName:"lib"~a.baseName~".dylib").array; 132 else 133 libraries ~= reader.front.attributes["shared-library"].split(',').map!(a => a.startsWith("lib")?a:"lib"~a~".so").array; 134 135 libraries = libraries.sort().uniq.array; 136 } 137 reader.popFront(); 138 139 while ( !reader.empty && !reader.endTag("namespace") ) 140 { 141 if ( reader.front.type == XMLNodeType.EndTag ) 142 { 143 reader.popFront(); 144 continue; 145 } 146 147 switch (reader.front.value) 148 { 149 case "alias": 150 GirAlias gtkAlias = new GirAlias(wrapper); 151 gtkAlias.parse(reader); 152 153 if ( gtkAlias.cType == "GType" ) 154 break; 155 156 collectedAliases[gtkAlias.name] = gtkAlias; 157 break; 158 case "attribute": 159 //TODO: Do we need these attibutes? 160 //dbus.name ccode.ordering deprecated replacement. 161 reader.skipTag(); 162 break; 163 case "glib:boxed": 164 reader.skipTag(); 165 break; 166 case "bitfield": 167 case "enumeration": 168 GirEnum gtkEnum = new GirEnum(wrapper, this); 169 gtkEnum.parse(reader); 170 collectedEnums[gtkEnum.name] = gtkEnum; 171 break; 172 case "class": 173 case "interface": 174 case "record": 175 case "union": 176 GirStruct gtkStruct = new GirStruct(wrapper, this); 177 gtkStruct.parse(reader); 178 179 //Workaround: Dont overwrite the regular pango classes. 180 if ( gtkStruct.cType.among("PangoCairoFont", "PangoCairoFontMap") ) 181 gtkStruct.name = gtkStruct.cType; 182 183 collectedStructs[gtkStruct.name] = gtkStruct; 184 185 //Don't generate classes named Object. 186 if ( gtkStruct.name == "Object" ) 187 gtkStruct.name = "Object"~ cTypePrefix; 188 if ( name == "pango" ) 189 gtkStruct.name = "Pg"~gtkStruct.name; 190 break; 191 case "callback": 192 GirFunction callback = new GirFunction(wrapper, null); 193 callback.parse(reader); 194 collectedCallbacks[callback.name] = callback; 195 break; 196 case "constant": 197 parseConstant(reader); 198 break; 199 case "function": 200 parseFunction(reader); 201 break; 202 case "function-macro": 203 // We are not able to wrap these. 204 reader.skipTag(); 205 break; 206 case "field": 207 // We are not able to wrap these. 208 reader.skipTag(); 209 break; 210 default: 211 error("Unexpected tag: ", reader.front.value, " in GirPackage: ", name, reader); 212 } 213 reader.popFront(); 214 } 215 } 216 217 void parseConstant(T)(XMLReader!T reader) 218 { 219 if ( reader.front.attributes["name"].startsWith("STOCK_") ) 220 { 221 GirEnumMember member = GirEnumMember(wrapper); 222 member.parse(reader); 223 member.name = member.name[6..$]; 224 225 stockIDs.members ~= member; 226 return; 227 } 228 else if ( "c:type" in reader.front.attributes && reader.front.attributes["c:type"].startsWith("GDK_KEY_") ) 229 { 230 GirEnumMember member = GirEnumMember(wrapper); 231 member.parse(reader); 232 member.name = "GDK_"~ member.name[4..$]; 233 234 gdkKeys.members ~= member; 235 return; 236 } 237 // The version attribute of the namspace tag is usualy set to MAJOR.0. 238 else if ( reader.front.attributes["name"].startsWith("MAJOR_VERSION") ) 239 { 240 _version.major = to!uint(reader.front.attributes["value"]); 241 } 242 else if ( reader.front.attributes["name"].startsWith("MINOR_VERSION") ) 243 { 244 _version.minor = to!uint(reader.front.attributes["value"]); 245 } 246 else if ( reader.front.attributes["name"].startsWith("MICRO_VERSION") ) 247 { 248 _version.micro = to!uint(reader.front.attributes["value"]); 249 } 250 251 GirConstant constant = new GirConstant(wrapper, this); 252 constant.parse(reader); 253 254 if (constant.name != "true" && constant.name != "false") 255 collectedConstants[constant.name] = constant; 256 } 257 258 void parseFunction(T)(XMLReader!T reader) 259 { 260 GirFunction funct = new GirFunction(wrapper, null); 261 funct.parse(reader); 262 collectedFunctions[funct.name] = funct; 263 264 checkVersion(funct.libVersion); 265 } 266 267 GirPackage getNamespace(string name) 268 { 269 if ( name.empty ) 270 return null; 271 272 if ( name !in namespaces ) 273 { 274 if ( auto inc = name in includes ) 275 { 276 if ( inc.skip ) return null; 277 278 namespaces[name] = inc.parse(wrapper, srcDir); 279 } 280 else 281 { 282 foreach ( inc; includes.byValue.filter!(inc => inc.name !in namespaces) ) 283 namespaces[inc.name] = inc.parse(wrapper, srcDir); 284 285 if ( !includes.byValue.filter!(inc => inc.name !in namespaces).empty ) 286 return getNamespace(name); 287 else 288 return null; 289 } 290 } 291 292 return namespaces.get(name, null); 293 } 294 295 GirStruct getStruct(string name) 296 { 297 GirPackage pack = this; 298 299 if ( name.canFind(".") ) 300 { 301 string[] vals = name.split("."); 302 303 if ( !getNamespace(vals[0]) ) 304 return null; 305 306 pack = namespaces[vals[0]]; 307 name = vals[1]; 308 } 309 return pack.collectedStructs.get(name, pack.collectedStructs.get("lookup"~name, null)); 310 } 311 312 GirEnum getEnum(string name) 313 { 314 GirPackage pack = this; 315 316 if ( name.canFind(".") ) 317 { 318 string[] vals = name.split("."); 319 320 if ( !getNamespace(vals[0]) ) 321 return null; 322 323 pack = namespaces[vals[0]]; 324 name = vals[1]; 325 } 326 return pack.collectedEnums.get(name, null); 327 } 328 329 void checkVersion(string _version) 330 { 331 if (this._version < _version) 332 this._version = GirVersion(_version); 333 } 334 335 void checkVersion(GirVersion _version) 336 { 337 if (this._version < _version) 338 this._version = _version; 339 } 340 341 void writeClasses() 342 { 343 try 344 { 345 if ( !exists(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"))) ) 346 mkdirRecurse(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"))); 347 } 348 catch (FileException ex) 349 { 350 error("Failed to create directory: ", ex.msg); 351 } 352 353 foreach ( strct; collectedStructs ) 354 strct.writeClass(); 355 } 356 357 void writeTypes() 358 { 359 string buff = wrapper.licence; 360 auto indenter = new IndentedStringBuilder(); 361 362 buff ~= "module "~ name ~".c.types;\n\n"; 363 364 buff ~= getTypeImports(); 365 366 buff ~= indenter.format(lookupAliases); 367 foreach ( a; collectedAliases ) 368 { 369 buff ~= "\n"; 370 buff ~= indenter.format(a.getAliasDeclaration()); 371 } 372 373 buff ~= indenter.format(lookupEnums); 374 foreach ( e; collectedEnums ) 375 { 376 buff ~= "\n"; 377 buff ~= indenter.format(e.getEnumDeclaration()); 378 } 379 380 buff ~= indenter.format(lookupStructs); 381 foreach ( s; collectedStructs ) 382 { 383 if ( s.noExternal || s.noDeclaration ) 384 continue; 385 386 buff ~= "\n"; 387 buff ~= indenter.format(s.getStructDeclaration()); 388 } 389 390 buff ~= indenter.format(lookupFuncts); 391 foreach ( f; collectedCallbacks ) 392 { 393 buff ~= "\n"; 394 buff ~= indenter.format(f.getCallbackDeclaration()); 395 } 396 397 buff ~= indenter.format(lookupConstants); 398 foreach ( c; collectedConstants ) 399 { 400 buff ~= "\n"; 401 buff ~= indenter.format(c.getConstantDeclaration()); 402 } 403 404 if ( stockIDs.members !is null ) 405 { 406 stockIDs.cName = "StockID"; 407 stockIDs.doc = "StockIds"; 408 buff ~= "\n"; 409 buff ~= indenter.format(stockIDs.getEnumDeclaration()); 410 } 411 412 if ( gdkKeys.members !is null ) 413 writeGdkKeys(); 414 415 wrapper.writeFile(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"), "c/types.d"), buff, true); 416 } 417 418 void writeGdkKeys() 419 { 420 string buff = wrapper.licence; 421 422 buff ~= "module "~ name ~".Keysyms;\n\n"; 423 424 buff ~= "/**\n"; 425 buff ~= " * GdkKeysyms.\n"; 426 buff ~= " */\n"; 427 buff ~= "public enum GdkKeysyms\n"; 428 buff ~= "{\n"; 429 430 foreach ( member; gdkKeys.members ) 431 { 432 buff ~= "\t"~ tokenToGtkD(member.name, wrapper.aliasses, false) ~" = "~ member.value ~",\n"; 433 } 434 435 buff ~= "}\n"; 436 buff ~= "alias Keysyms = GdkKeysyms;\n"; 437 438 wrapper.writeFile(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"), "Keysyms.d"), buff, true); 439 } 440 441 void writeLoaderTable() 442 { 443 string buff = wrapper.licence; 444 445 buff ~= "module "~ name ~".c.functions;\n\n"; 446 buff ~= "import std.stdio;\n"; 447 buff ~= "import "~ name ~".c.types;\n"; 448 449 if ( name == "glib" ) 450 buff ~= "import gobject.c.types;\n"; 451 if ( name == "gdk" || name == "pango" ) 452 buff ~= "import cairo.c.types;\n"; 453 454 buff ~= "import gtkd.Loader;\n\n"; 455 buff ~= getLibraries(); 456 buff ~= "\n\nshared static this()\n{"; 457 458 foreach ( strct; collectedStructs ) 459 { 460 if ( strct.functions.empty || strct.noExternal ) 461 continue; 462 463 buff ~= "\n\t// "~ name ~"."~ strct.name ~"\n\n"; 464 465 foreach ( funct; strct.functions ) 466 { 467 if ( funct.type == GirFunctionType.Callback || funct.type == GirFunctionType.Signal || funct.name.empty ) 468 continue; 469 470 buff ~= "\tLinker.link("~ funct.cType ~", \""~ funct.cType ~"\", LIBRARY_"~ name.replace(".","").toUpper() ~");\n"; 471 } 472 } 473 474 //WORKAROUND: Windows has two functions with different names in the 32 and 64 bit versions. 475 if (name == "glib") 476 { 477 buff ~= "\n\tversion(Win64)\n"; 478 buff ~= "\t{\n"; 479 buff ~= "\t\tLinker.link(g_module_name, \"g_module_name_uft8\", LIBRARY_GLIB);\n"; 480 buff ~= "\t\tLinker.link(g_module_open, \"g_module_open_utf8\", LIBRARY_GLIB);\n"; 481 buff ~= "\t}\n"; 482 } 483 484 buff ~= "}\n\n" 485 ~ "__gshared extern(C)\n" 486 ~ "{\n"; 487 488 foreach ( strct; collectedStructs ) 489 { 490 if ( strct.functions.empty || strct.noExternal ) 491 continue; 492 493 buff ~= "\n\t// "~ name ~"."~ strct.name ~"\n\n"; 494 495 foreach ( funct; strct.functions ) 496 { 497 if ( funct.type == GirFunctionType.Callback || funct.type == GirFunctionType.Signal || funct.name.empty ) 498 continue; 499 500 buff ~= "\t"~ funct.getLinkerExternal() ~"\n"; 501 } 502 } 503 504 buff ~= "}\n\n"; 505 506 foreach ( strct; collectedStructs ) 507 { 508 if ( strct.functions.empty || strct.noExternal ) 509 continue; 510 511 buff ~= "\n// "~ name ~"."~ strct.name ~"\n\n"; 512 513 foreach ( funct; strct.functions ) 514 { 515 if ( funct.type == GirFunctionType.Callback || funct.type == GirFunctionType.Signal || funct.name.empty ) 516 continue; 517 518 if (name == "glgdk") 519 buff ~= "alias glc_"~ funct.cType ~" "~ funct.cType ~";\n"; 520 else 521 buff ~= "alias c_"~ funct.cType ~" "~ funct.cType ~";\n"; 522 } 523 } 524 525 wrapper.writeFile(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"), "c", "functions.d"), buff, true); 526 } 527 528 void writeExternalFunctions() 529 { 530 string buff = wrapper.licence; 531 532 buff ~= "module "~ name ~".c.functions;\n\n"; 533 buff ~= "import std.stdio;\n"; 534 buff ~= "import "~ name ~".c.types;\n"; 535 536 if ( name == "glib" ) 537 buff ~= "import gobject.c.types;\n"; 538 if ( name == "gdk" || name == "pango" ) 539 buff ~= "import cairo.c.types;\n\n"; 540 541 buff ~= getLibraries(); 542 543 buff ~= "\n\n__gshared extern(C)\n" 544 ~ "{\n"; 545 546 foreach ( strct; collectedStructs ) 547 { 548 if ( strct.functions.empty || strct.noExternal ) 549 continue; 550 551 buff ~= "\n\t// "~ name ~"."~ strct.name ~"\n\n"; 552 553 foreach ( funct; strct.functions ) 554 { 555 if ( funct.type == GirFunctionType.Callback || funct.type == GirFunctionType.Signal || funct.name.empty ) 556 continue; 557 558 buff ~= "\t"~ funct.getExternal() ~"\n"; 559 } 560 } 561 562 buff ~= "}"; 563 564 wrapper.writeFile(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"), "c", "functions.d"), buff, true); 565 } 566 567 private string getLibraries() 568 { 569 string lib = "version (Windows)\n\t"; 570 lib ~= "static immutable LIBRARY_"~ name.replace(".","").toUpper() ~" = ["~ getDllNames() ~"];"; 571 lib ~= "\nelse version (OSX)\n\t"; 572 lib ~= "static immutable LIBRARY_"~ name.replace(".","").toUpper() ~" = ["~ getDylibNames() ~"];"; 573 lib ~= "\nelse\n\t"; 574 lib ~= "static immutable LIBRARY_"~ name.replace(".","").toUpper() ~" = ["~ getSoNames() ~"];"; 575 576 return lib; 577 } 578 579 private auto dllRegex = ctRegex!(`([a-z0-9_]+)(-[0-9\.]+)?(-[0-9]+)?\.dll`); 580 private auto dylibRegex = ctRegex!(`([a-z0-9_]+)(-[0-9\.]+?)?(\.[0-9]+)?\.dylib`); 581 private auto soRegex = ctRegex!(`([a-z0-9_]+)(-[0-9\.]+)?\.so(\.[0-9]+)?`); 582 583 private string getDllNames() 584 { 585 version (Windows) 586 { 587 //TODO: Only the gir files form msys are currently supported on windows. 588 589 string libs; 590 591 foreach ( lib; libraries ) 592 { 593 auto match = matchFirst(lib, dllRegex); 594 595 //Msys 596 libs ~= "\""~ lib; 597 598 //wingtk 599 libs ~= ";"; 600 libs ~= match[1].replace("lib", ""); 601 if ( !match[2].empty ) 602 libs ~= "-"~ match[2][1..$]; 603 if ( !match[3].empty && match[2].canFind('.') ) 604 libs ~= "-"~ match[3][1..$]; 605 else if ( !match[3].empty && !match[2].empty ) 606 libs ~= "-"~ match[2][$-1] ~"."~ match[3][1..$]; 607 libs ~= ".dll"; 608 609 //vcpkg 610 libs ~= ";"; 611 libs ~= match[1].replace("lib", ""); 612 if ( !match[2].empty && match[2].canFind('.') ) 613 libs ~= "-"~ match[2][1..$].split('.')[0]; 614 else if ( !match[2].empty ) 615 libs ~= "-"~ match[2][1..$]; 616 libs ~= ".dll\""; 617 618 if ( lib != libraries.back ) 619 libs ~= ", "; 620 } 621 622 return libs; 623 } 624 else version (OSX) 625 { 626 string libs; 627 628 foreach ( lib; libraries ) 629 { 630 auto match = matchFirst(lib, dylibRegex); 631 632 //Msys 633 libs ~= "\""~ match[1]; 634 if ( !match[2].empty ) 635 libs ~= "-"~ match[2][1..$]; 636 if ( !match[3].empty ) 637 libs ~= "-"~ match[3][1..$]; 638 libs ~= ".dll"; 639 640 //wingtk 641 libs ~= ";"; 642 libs ~= match[1].replace("lib", ""); 643 if ( !match[2].empty ) 644 libs ~= "-"~ match[2][1..$]; 645 if ( !match[3].empty && match[2].canFind('.') ) 646 libs ~= "-"~ match[3][1..$]; 647 else if ( !match[3].empty && !match[2].empty ) 648 libs ~= "-"~ match[2][$-1] ~"."~ match[3][1..$]; 649 libs ~= ".dll"; 650 651 //vcpkg 652 libs ~= ";"; 653 libs ~= match[1].replace("lib", ""); 654 if ( !match[2].empty && match[2].canFind('.') ) 655 libs ~= "-"~ match[2][1..$].split('.')[0]; 656 else if ( !match[2].empty ) 657 libs ~= "-"~ match[2][1..$]; 658 libs ~= ".dll\""; 659 660 if ( lib != libraries.back ) 661 libs ~= ", "; 662 } 663 664 return libs; 665 } 666 else 667 { 668 string libs; 669 670 foreach ( lib; libraries ) 671 { 672 auto match = matchFirst(lib, soRegex); 673 674 //Msys 675 libs ~= "\""~ match[1]; 676 if ( !match[2].empty ) 677 libs ~= "-"~ match[2][1..$]; 678 if ( !match[3].empty ) 679 libs ~= "-"~ match[3][1..$]; 680 libs ~= ".dll"; 681 682 //wingtk 683 libs ~= ";"; 684 libs ~= match[1].replace("lib", ""); 685 if ( !match[2].empty ) 686 libs ~= "-"~ match[2][1..$]; 687 if ( !match[3].empty && match[2].canFind('.') ) 688 libs ~= "-"~ match[3][1..$]; 689 else if ( !match[3].empty && !match[2].empty ) 690 libs ~= "-"~ match[2][$-1] ~"."~ match[3][1..$]; 691 libs ~= ".dll"; 692 693 //vcpkg 694 libs ~= ";"; 695 libs ~= match[1].replace("lib", ""); 696 if ( !match[2].empty && match[2].canFind('.') ) 697 libs ~= "-"~ match[2][1..$].split('.')[0]; 698 else if ( !match[2].empty ) 699 libs ~= "-"~ match[2][1..$]; 700 libs ~= ".dll\""; 701 702 if ( lib != libraries.back ) 703 libs ~= ", "; 704 } 705 706 return libs; 707 } 708 } 709 710 private string getDylibNames() 711 { 712 version (Windows) 713 { 714 string libs; 715 716 foreach ( lib; libraries ) 717 { 718 auto match = matchFirst(lib, dllRegex); 719 720 libs ~= "\""~ match[1]; 721 if ( !match[2].empty ) 722 libs ~= "-"~ match[2][1..$]; 723 if ( !match[3].empty ) 724 libs ~= "."~ match[3][1..$]; 725 libs ~= ".dylib\""; 726 727 if ( lib != libraries.back ) 728 libs ~= ", "; 729 } 730 731 return libs; 732 } 733 else version (OSX) 734 { 735 return "\""~ libraries.join("\", \"") ~"\""; 736 } 737 else 738 { 739 string libs; 740 741 foreach ( lib; libraries ) 742 { 743 auto match = matchFirst(lib, soRegex); 744 745 libs ~= "\""~ match[1]; 746 if ( !match[2].empty ) 747 libs ~= "-"~ match[2][1..$]; 748 if ( !match[3].empty ) 749 libs ~= "."~ match[3][1..$]; 750 libs ~= ".dylib\""; 751 752 if ( lib != libraries.back ) 753 libs ~= ", "; 754 } 755 756 return libs; 757 } 758 } 759 760 private string getSoNames() 761 { 762 version (Windows) 763 { 764 string libs; 765 766 foreach ( lib; libraries ) 767 { 768 auto match = matchFirst(lib, dllRegex); 769 770 libs ~= "\""~ match[1]; 771 if ( !match[2].empty && !match[3].empty ) 772 libs ~= "-"~ match[2][1..$]; 773 libs ~= ".so"; 774 if ( !match[2].empty && match[3].empty ) 775 libs ~= "."~ match[2][1..$]; 776 if ( !match[3].empty ) 777 libs ~= "."~ match[3][1..$]; 778 libs ~= "\""; 779 780 if ( lib != libraries.back ) 781 libs ~= ", "; 782 } 783 784 return libs; 785 } 786 else version (OSX) 787 { 788 string libs; 789 790 foreach ( lib; libraries ) 791 { 792 auto match = matchFirst(lib, dylibRegex); 793 794 libs ~= "\""~ match[1]; 795 if ( !match[2].empty ) 796 libs ~= "-"~ match[2][1..$]; 797 libs ~= ".so"; 798 if ( !match[3].empty ) 799 libs ~= "."~ match[3][1..$]; 800 libs ~= "\""; 801 802 if ( lib != libraries.back ) 803 libs ~= ", "; 804 } 805 806 return libs; 807 } 808 else 809 { 810 return "\""~ libraries.join("\", \"") ~"\""; 811 } 812 } 813 814 private string getTypeImports() 815 { 816 string imports; 817 string[] usedNamespaces; 818 string[] packages; 819 820 foreach ( strct; collectedStructs ) 821 { 822 if ( strct.noExternal ) 823 continue; 824 825 usedNamespaces = chain(usedNamespaces, strct.usedNamespaces()).sort.uniq.array; 826 } 827 828 foreach ( ns; usedNamespaces ) 829 { 830 GirPackage pack = getNamespace(ns); 831 832 if ( pack && pack != this && !packages.canFind(pack.name) ) 833 packages ~= pack.name; 834 } 835 836 packages = packages.sort().array; 837 838 foreach ( pack; packages ) 839 { 840 imports ~= "public import "~ pack ~".c.types;\n"; 841 } 842 843 if ( !imports.empty ) 844 imports ~= "\n"; 845 846 return imports; 847 } 848 } 849 850 struct GirInclude 851 { 852 string name; 853 string _version; 854 855 bool skip; 856 string[] lookupText; 857 string lookupFile; 858 size_t lookupLine; 859 860 string girFileName() 861 { 862 return name ~"-"~ _version ~".gir"; 863 } 864 865 GirPackage parse(GirWrapper wrapper, string srcDir) 866 { 867 GirPackage inc = new GirPackage(name.toLower, wrapper, srcDir); 868 inc.parseGIR(wrapper.getAbsoluteGirPath(girFileName())); 869 870 if ( auto text = name in defaultLookupText ) 871 wrapper.proccess(new DefReader(*text, "Default rules"), inc, true); 872 873 wrapper.proccess(new DefReader(lookupText, lookupFile, lookupLine), inc, true); 874 875 return inc; 876 } 877 }