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 case "docsection": 211 // General documentation. 212 reader.skipTag(); 213 break; 214 default: 215 warning("Unexpected tag: ", reader.front.value, " in GirPackage: ", name, reader); 216 } 217 reader.popFront(); 218 } 219 } 220 221 void parseConstant(T)(XMLReader!T reader) 222 { 223 if ( reader.front.attributes["name"].startsWith("STOCK_") ) 224 { 225 GirEnumMember member = GirEnumMember(wrapper); 226 member.parse(reader); 227 member.name = member.name[6..$]; 228 229 stockIDs.members ~= member; 230 return; 231 } 232 else if ( "c:type" in reader.front.attributes && reader.front.attributes["c:type"].startsWith("GDK_KEY_") ) 233 { 234 GirEnumMember member = GirEnumMember(wrapper); 235 member.parse(reader); 236 member.name = "GDK_"~ member.name[4..$]; 237 238 gdkKeys.members ~= member; 239 return; 240 } 241 // The version attribute of the namspace tag is usualy set to MAJOR.0. 242 else if ( reader.front.attributes["name"].startsWith("MAJOR_VERSION") ) 243 { 244 _version.major = to!uint(reader.front.attributes["value"]); 245 } 246 else if ( reader.front.attributes["name"].startsWith("MINOR_VERSION") ) 247 { 248 _version.minor = to!uint(reader.front.attributes["value"]); 249 } 250 else if ( reader.front.attributes["name"].startsWith("MICRO_VERSION") ) 251 { 252 _version.micro = to!uint(reader.front.attributes["value"]); 253 } 254 255 GirConstant constant = new GirConstant(wrapper, this); 256 constant.parse(reader); 257 258 if (constant.name != "true" && constant.name != "false") 259 collectedConstants[constant.name] = constant; 260 } 261 262 void parseFunction(T)(XMLReader!T reader) 263 { 264 GirFunction funct = new GirFunction(wrapper, null); 265 funct.parse(reader); 266 collectedFunctions[funct.name] = funct; 267 268 checkVersion(funct.libVersion); 269 } 270 271 GirPackage getNamespace(string name) 272 { 273 if ( name.empty ) 274 return null; 275 276 if ( name !in namespaces ) 277 { 278 if ( auto inc = name in includes ) 279 { 280 if ( inc.skip ) return null; 281 282 namespaces[name] = inc.parse(wrapper, srcDir); 283 } 284 else 285 { 286 foreach ( inc; includes.byValue.filter!(inc => inc.name !in namespaces) ) 287 namespaces[inc.name] = inc.parse(wrapper, srcDir); 288 289 if ( !includes.byValue.filter!(inc => inc.name !in namespaces).empty ) 290 return getNamespace(name); 291 else 292 return null; 293 } 294 } 295 296 return namespaces.get(name, null); 297 } 298 299 GirStruct getStruct(string name) 300 { 301 GirPackage pack = this; 302 303 if ( name.canFind(".") ) 304 { 305 string[] vals = name.split("."); 306 307 if ( !getNamespace(vals[0]) ) 308 return null; 309 310 pack = namespaces[vals[0]]; 311 name = vals[1]; 312 } 313 return pack.collectedStructs.get(name, pack.collectedStructs.get("lookup"~name, null)); 314 } 315 316 GirEnum getEnum(string name) 317 { 318 GirPackage pack = this; 319 320 if ( name.canFind(".") ) 321 { 322 string[] vals = name.split("."); 323 324 if ( !getNamespace(vals[0]) ) 325 return null; 326 327 pack = namespaces[vals[0]]; 328 name = vals[1]; 329 } 330 return pack.collectedEnums.get(name, null); 331 } 332 333 void checkVersion(string _version) 334 { 335 if (this._version < _version) 336 this._version = GirVersion(_version); 337 } 338 339 void checkVersion(GirVersion _version) 340 { 341 if (this._version < _version) 342 this._version = _version; 343 } 344 345 void writeClasses() 346 { 347 try 348 { 349 if ( !exists(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"))) ) 350 mkdirRecurse(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"))); 351 } 352 catch (FileException ex) 353 { 354 error("Failed to create directory: ", ex.msg); 355 } 356 357 foreach ( strct; collectedStructs ) 358 strct.writeClass(); 359 } 360 361 void writeTypes() 362 { 363 string buff = wrapper.licence; 364 auto indenter = new IndentedStringBuilder(); 365 366 buff ~= "module "~ name ~".c.types;\n\n"; 367 368 buff ~= getTypeImports(); 369 370 buff ~= indenter.format(lookupAliases); 371 foreach ( a; collectedAliases ) 372 { 373 buff ~= "\n"; 374 buff ~= indenter.format(a.getAliasDeclaration()); 375 } 376 377 buff ~= indenter.format(lookupEnums); 378 foreach ( e; collectedEnums ) 379 { 380 buff ~= "\n"; 381 buff ~= indenter.format(e.getEnumDeclaration()); 382 } 383 384 buff ~= indenter.format(lookupStructs); 385 foreach ( s; collectedStructs ) 386 { 387 if ( s.noExternal || s.noDeclaration ) 388 continue; 389 390 buff ~= "\n"; 391 buff ~= indenter.format(s.getStructDeclaration()); 392 } 393 394 buff ~= indenter.format(lookupFuncts); 395 foreach ( f; collectedCallbacks ) 396 { 397 buff ~= "\n"; 398 buff ~= indenter.format(f.getCallbackDeclaration()); 399 } 400 401 buff ~= indenter.format(lookupConstants); 402 foreach ( c; collectedConstants ) 403 { 404 buff ~= "\n"; 405 buff ~= indenter.format(c.getConstantDeclaration()); 406 } 407 408 if ( stockIDs.members !is null ) 409 { 410 stockIDs.cName = "StockID"; 411 stockIDs.doc = "StockIds"; 412 buff ~= "\n"; 413 buff ~= indenter.format(stockIDs.getEnumDeclaration()); 414 } 415 416 if ( gdkKeys.members !is null ) 417 writeGdkKeys(); 418 419 wrapper.writeFile(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"), "c/types.d"), buff, true); 420 } 421 422 void writeGdkKeys() 423 { 424 string buff = wrapper.licence; 425 426 buff ~= "module "~ name ~".Keysyms;\n\n"; 427 428 buff ~= "/**\n"; 429 buff ~= " * GdkKeysyms.\n"; 430 buff ~= " */\n"; 431 buff ~= "public enum GdkKeysyms\n"; 432 buff ~= "{\n"; 433 434 foreach ( member; gdkKeys.members ) 435 { 436 buff ~= "\t"~ tokenToGtkD(member.name, wrapper.aliasses, false) ~" = "~ member.value ~",\n"; 437 } 438 439 buff ~= "}\n"; 440 buff ~= "alias Keysyms = GdkKeysyms;\n"; 441 442 wrapper.writeFile(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"), "Keysyms.d"), buff, true); 443 } 444 445 void writeLoaderTable() 446 { 447 string buff = wrapper.licence; 448 449 buff ~= "module "~ name ~".c.functions;\n\n"; 450 buff ~= "import std.stdio;\n"; 451 buff ~= "import "~ name ~".c.types;\n"; 452 453 if ( name == "glib" ) 454 buff ~= "import gobject.c.types;\n"; 455 if ( name == "gdk" || name == "pango" ) 456 buff ~= "import cairo.c.types;\n"; 457 458 buff ~= "import gtkd.Loader;\n\n"; 459 buff ~= getLibraries(); 460 buff ~= "\n\nshared static this()\n{"; 461 462 foreach ( strct; collectedStructs ) 463 { 464 if ( strct.functions.empty || strct.noExternal ) 465 continue; 466 467 buff ~= "\n\t// "~ name ~"."~ strct.name ~"\n\n"; 468 469 foreach ( funct; strct.functions ) 470 { 471 if ( funct.type == GirFunctionType.Callback || funct.type == GirFunctionType.Signal || funct.name.empty ) 472 continue; 473 474 buff ~= "\tLinker.link("~ funct.cType ~", \""~ funct.cType ~"\", LIBRARY_"~ name.replace(".","").toUpper() ~");\n"; 475 } 476 } 477 478 //WORKAROUND: Windows has two functions with different names in the 32 and 64 bit versions. 479 if (name == "glib") 480 { 481 buff ~= "\n\tversion(Win64)\n"; 482 buff ~= "\t{\n"; 483 buff ~= "\t\tLinker.link(g_module_name, \"g_module_name_uft8\", LIBRARY_GLIB);\n"; 484 buff ~= "\t\tLinker.link(g_module_open, \"g_module_open_utf8\", LIBRARY_GLIB);\n"; 485 buff ~= "\t}\n"; 486 } 487 488 buff ~= "}\n\n" 489 ~ "__gshared extern(C)\n" 490 ~ "{\n"; 491 492 foreach ( strct; collectedStructs ) 493 { 494 if ( strct.functions.empty || strct.noExternal ) 495 continue; 496 497 buff ~= "\n\t// "~ name ~"."~ strct.name ~"\n\n"; 498 499 foreach ( funct; strct.functions ) 500 { 501 if ( funct.type == GirFunctionType.Callback || funct.type == GirFunctionType.Signal || funct.name.empty ) 502 continue; 503 504 buff ~= "\t"~ funct.getLinkerExternal() ~"\n"; 505 } 506 } 507 508 buff ~= "}\n\n"; 509 510 foreach ( strct; collectedStructs ) 511 { 512 if ( strct.functions.empty || strct.noExternal ) 513 continue; 514 515 buff ~= "\n// "~ name ~"."~ strct.name ~"\n\n"; 516 517 foreach ( funct; strct.functions ) 518 { 519 if ( funct.type == GirFunctionType.Callback || funct.type == GirFunctionType.Signal || funct.name.empty ) 520 continue; 521 522 if (name == "glgdk") 523 buff ~= "alias glc_"~ funct.cType ~" "~ funct.cType ~";\n"; 524 else 525 buff ~= "alias c_"~ funct.cType ~" "~ funct.cType ~";\n"; 526 } 527 } 528 529 wrapper.writeFile(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"), "c", "functions.d"), buff, true); 530 } 531 532 void writeExternalFunctions() 533 { 534 string buff = wrapper.licence; 535 536 buff ~= "module "~ name ~".c.functions;\n\n"; 537 buff ~= "import std.stdio;\n"; 538 buff ~= "import "~ name ~".c.types;\n"; 539 540 if ( name == "glib" ) 541 buff ~= "import gobject.c.types;\n"; 542 if ( name == "gdk" || name == "pango" ) 543 buff ~= "import cairo.c.types;\n\n"; 544 545 buff ~= getLibraries(); 546 547 buff ~= "\n\n__gshared extern(C)\n" 548 ~ "{\n"; 549 550 foreach ( strct; collectedStructs ) 551 { 552 if ( strct.functions.empty || strct.noExternal ) 553 continue; 554 555 buff ~= "\n\t// "~ name ~"."~ strct.name ~"\n\n"; 556 557 foreach ( funct; strct.functions ) 558 { 559 if ( funct.type == GirFunctionType.Callback || funct.type == GirFunctionType.Signal || funct.name.empty ) 560 continue; 561 562 buff ~= "\t"~ funct.getExternal() ~"\n"; 563 } 564 } 565 566 buff ~= "}"; 567 568 wrapper.writeFile(buildNormalizedPath(wrapper.outputDir, srcDir, name.replace(".","/"), "c", "functions.d"), buff, true); 569 } 570 571 private string getLibraries() 572 { 573 string lib = "version (Windows)\n\t"; 574 lib ~= "static immutable LIBRARY_"~ name.replace(".","").toUpper() ~" = ["~ getDllNames() ~"];"; 575 lib ~= "\nelse version (OSX)\n\t"; 576 lib ~= "static immutable LIBRARY_"~ name.replace(".","").toUpper() ~" = ["~ getDylibNames() ~"];"; 577 lib ~= "\nelse\n\t"; 578 lib ~= "static immutable LIBRARY_"~ name.replace(".","").toUpper() ~" = ["~ getSoNames() ~"];"; 579 580 return lib; 581 } 582 583 private auto dllRegex = ctRegex!(`([a-z0-9_]+)(-[0-9\.]+)?(-[0-9]+)?\.dll`); 584 private auto dylibRegex = ctRegex!(`([a-z0-9_]+)(-[0-9\.]+?)?(\.[0-9]+)?\.dylib`); 585 private auto soRegex = ctRegex!(`([a-z0-9_]+)(-[0-9\.]+)?\.so(\.[0-9]+)?`); 586 587 private string getDllNames() 588 { 589 version (Windows) 590 { 591 //TODO: Only the gir files form msys are currently supported on windows. 592 593 string libs; 594 595 foreach ( lib; libraries ) 596 { 597 auto match = matchFirst(lib, dllRegex); 598 599 //Msys 600 libs ~= "\""~ lib; 601 602 //wingtk 603 libs ~= ";"; 604 libs ~= match[1].replace("lib", ""); 605 if ( !match[2].empty ) 606 libs ~= "-"~ match[2][1..$]; 607 if ( !match[3].empty && match[2].canFind('.') ) 608 libs ~= "-"~ match[3][1..$]; 609 else if ( !match[3].empty && !match[2].empty ) 610 libs ~= "-"~ match[2][$-1] ~"."~ match[3][1..$]; 611 libs ~= ".dll"; 612 613 //vcpkg 614 libs ~= ";"; 615 libs ~= match[1].replace("lib", ""); 616 if ( !match[2].empty && match[2].canFind('.') ) 617 libs ~= "-"~ match[2][1..$].split('.')[0]; 618 else if ( !match[2].empty ) 619 libs ~= "-"~ match[2][1..$]; 620 libs ~= ".dll\""; 621 622 if ( lib != libraries.back ) 623 libs ~= ", "; 624 } 625 626 return libs; 627 } 628 else version (OSX) 629 { 630 string libs; 631 632 foreach ( lib; libraries ) 633 { 634 auto match = matchFirst(lib, dylibRegex); 635 636 //Msys 637 libs ~= "\""~ match[1]; 638 if ( !match[2].empty ) 639 libs ~= "-"~ match[2][1..$]; 640 if ( !match[3].empty ) 641 libs ~= "-"~ match[3][1..$]; 642 libs ~= ".dll"; 643 644 //wingtk 645 libs ~= ";"; 646 libs ~= match[1].replace("lib", ""); 647 if ( !match[2].empty ) 648 libs ~= "-"~ match[2][1..$]; 649 if ( !match[3].empty && match[2].canFind('.') ) 650 libs ~= "-"~ match[3][1..$]; 651 else if ( !match[3].empty && !match[2].empty ) 652 libs ~= "-"~ match[2][$-1] ~"."~ match[3][1..$]; 653 libs ~= ".dll"; 654 655 //vcpkg 656 libs ~= ";"; 657 libs ~= match[1].replace("lib", ""); 658 if ( !match[2].empty && match[2].canFind('.') ) 659 libs ~= "-"~ match[2][1..$].split('.')[0]; 660 else if ( !match[2].empty ) 661 libs ~= "-"~ match[2][1..$]; 662 libs ~= ".dll\""; 663 664 if ( lib != libraries.back ) 665 libs ~= ", "; 666 } 667 668 return libs; 669 } 670 else 671 { 672 string libs; 673 674 foreach ( lib; libraries ) 675 { 676 auto match = matchFirst(lib, soRegex); 677 678 //Msys 679 libs ~= "\""~ match[1]; 680 if ( !match[2].empty ) 681 libs ~= "-"~ match[2][1..$]; 682 if ( !match[3].empty ) 683 libs ~= "-"~ match[3][1..$]; 684 libs ~= ".dll"; 685 686 //wingtk 687 libs ~= ";"; 688 libs ~= match[1].replace("lib", ""); 689 if ( !match[2].empty ) 690 libs ~= "-"~ match[2][1..$]; 691 if ( !match[3].empty && match[2].canFind('.') ) 692 libs ~= "-"~ match[3][1..$]; 693 else if ( !match[3].empty && !match[2].empty ) 694 libs ~= "-"~ match[2][$-1] ~"."~ match[3][1..$]; 695 libs ~= ".dll"; 696 697 //vcpkg 698 libs ~= ";"; 699 libs ~= match[1].replace("lib", ""); 700 if ( !match[2].empty && match[2].canFind('.') ) 701 libs ~= "-"~ match[2][1..$].split('.')[0]; 702 else if ( !match[2].empty ) 703 libs ~= "-"~ match[2][1..$]; 704 libs ~= ".dll\""; 705 706 if ( lib != libraries.back ) 707 libs ~= ", "; 708 } 709 710 return libs; 711 } 712 } 713 714 private string getDylibNames() 715 { 716 version (Windows) 717 { 718 string libs; 719 720 foreach ( lib; libraries ) 721 { 722 auto match = matchFirst(lib, dllRegex); 723 724 libs ~= "\""~ match[1]; 725 if ( !match[2].empty ) 726 libs ~= "-"~ match[2][1..$]; 727 if ( !match[3].empty ) 728 libs ~= "."~ match[3][1..$]; 729 libs ~= ".dylib\""; 730 731 if ( lib != libraries.back ) 732 libs ~= ", "; 733 } 734 735 return libs; 736 } 737 else version (OSX) 738 { 739 return "\""~ libraries.join("\", \"") ~"\""; 740 } 741 else 742 { 743 string libs; 744 745 foreach ( lib; libraries ) 746 { 747 auto match = matchFirst(lib, soRegex); 748 749 libs ~= "\""~ match[1]; 750 if ( !match[2].empty ) 751 libs ~= "-"~ match[2][1..$]; 752 if ( !match[3].empty ) 753 libs ~= "."~ match[3][1..$]; 754 libs ~= ".dylib\""; 755 756 if ( lib != libraries.back ) 757 libs ~= ", "; 758 } 759 760 return libs; 761 } 762 } 763 764 private string getSoNames() 765 { 766 version (Windows) 767 { 768 string libs; 769 770 foreach ( lib; libraries ) 771 { 772 auto match = matchFirst(lib, dllRegex); 773 774 libs ~= "\""~ match[1]; 775 if ( !match[2].empty && !match[3].empty ) 776 libs ~= "-"~ match[2][1..$]; 777 libs ~= ".so"; 778 if ( !match[2].empty && match[3].empty ) 779 libs ~= "."~ match[2][1..$]; 780 if ( !match[3].empty ) 781 libs ~= "."~ match[3][1..$]; 782 libs ~= "\""; 783 784 if ( lib != libraries.back ) 785 libs ~= ", "; 786 } 787 788 return libs; 789 } 790 else version (OSX) 791 { 792 string libs; 793 794 foreach ( lib; libraries ) 795 { 796 auto match = matchFirst(lib, dylibRegex); 797 798 libs ~= "\""~ match[1]; 799 if ( !match[2].empty ) 800 libs ~= "-"~ match[2][1..$]; 801 libs ~= ".so"; 802 if ( !match[3].empty ) 803 libs ~= "."~ match[3][1..$]; 804 libs ~= "\""; 805 806 if ( lib != libraries.back ) 807 libs ~= ", "; 808 } 809 810 return libs; 811 } 812 else 813 { 814 return "\""~ libraries.join("\", \"") ~"\""; 815 } 816 } 817 818 private string getTypeImports() 819 { 820 string imports; 821 string[] usedNamespaces; 822 string[] packages; 823 824 foreach ( strct; collectedStructs ) 825 { 826 if ( strct.noExternal ) 827 continue; 828 829 usedNamespaces = chain(usedNamespaces, strct.usedNamespaces()).sort.uniq.array; 830 } 831 832 foreach ( ns; usedNamespaces ) 833 { 834 GirPackage pack = getNamespace(ns); 835 836 if ( pack && pack != this && !packages.canFind(pack.name) ) 837 packages ~= pack.name; 838 } 839 840 packages = packages.sort().array; 841 842 foreach ( pack; packages ) 843 { 844 imports ~= "public import "~ pack ~".c.types;\n"; 845 } 846 847 if ( !imports.empty ) 848 imports ~= "\n"; 849 850 return imports; 851 } 852 } 853 854 struct GirInclude 855 { 856 string name; 857 string _version; 858 859 bool skip; 860 string[] lookupText; 861 string lookupFile; 862 size_t lookupLine; 863 864 string girFileName() 865 { 866 return name ~"-"~ _version ~".gir"; 867 } 868 869 GirPackage parse(GirWrapper wrapper, string srcDir) 870 { 871 GirPackage inc = new GirPackage(name.toLower, wrapper, srcDir); 872 inc.parseGIR(wrapper.getAbsoluteGirPath(girFileName())); 873 874 if ( auto text = name in defaultLookupText ) 875 wrapper.proccess(new DefReader(*text, "Default rules"), inc, true); 876 877 wrapper.proccess(new DefReader(lookupText, lookupFile, lookupLine), inc, true); 878 879 return inc; 880 } 881 }