Mercurial > projects > dstep
comparison scripts/dstepgen.rb @ 6:c0cfd40362ee
Fixed the bridge to work with ldc and dmd. Added a couple of hooks to manipulate the source code
author | Jacob Carlborg <doob@me.com> |
---|---|
date | Wed, 08 Jul 2009 14:29:59 +0200 |
parents | 5a1a6afbfe3a |
children | 9e67a1122e85 |
comparison
equal
deleted
inserted
replaced
5:7a60c3c4d421 | 6:c0cfd40362ee |
---|---|
134 CPP = ['/usr/bin/cpp-4.0', '/usr/bin/cpp-3.3', '/usr/bin/cpp3'].find { |x| File.exist?(x) } | 134 CPP = ['/usr/bin/cpp-4.0', '/usr/bin/cpp-3.3', '/usr/bin/cpp3'].find { |x| File.exist?(x) } |
135 raise "cpp not found" if CPP.nil? | 135 raise "cpp not found" if CPP.nil? |
136 CPPFLAGS = "-D__APPLE_CPP__ -include /usr/include/AvailabilityMacros.h" | 136 CPPFLAGS = "-D__APPLE_CPP__ -include /usr/include/AvailabilityMacros.h" |
137 CPPFLAGS << "-D__GNUC__" unless /\Acpp-4/.match(File.basename(CPP)) | 137 CPPFLAGS << "-D__GNUC__" unless /\Acpp-4/.match(File.basename(CPP)) |
138 | 138 |
139 attr_accessor :frameworks, :headers, :do_64bit | 139 attr_accessor :frameworks, :headers, :do_64bit, :extra |
140 | 140 |
141 def initialize | 141 def initialize |
142 @extern_name = 'extern' | 142 @extern_name = 'extern' |
143 @frameworks = [] | 143 @frameworks = [] |
144 @file_content = nil | 144 @file_content = nil |
486 i += size | 486 i += size |
487 end | 487 end |
488 end | 488 end |
489 | 489 |
490 def structs (header) | 490 def structs (header) |
491 re = /typedef\s+struct\s*\w*\s*((\w+)|\{([^{}]*(\{[^}]+\})?)*\}\s*([^\s]+))\s*(__attribute__\(.+\))?\s*;/ | 491 re = /typedef\s+struct\s*\w*\s*((\w+)|\{([^{}]*(\{[^}]+\})?)*\}\s*([^\s]+))\s*(__attribute__\(.+\))?\s*,?(.+)?;/ |
492 i = 0 | 492 i = 0 |
493 body = nil | 493 body = nil |
494 | |
494 @cpp_result.scan(re).each do |m| | 495 @cpp_result.scan(re).each do |m| |
495 struct = { :name => m[4], :members => [] } | 496 struct = { :name => m[4], :members => [] } |
496 | 497 |
497 unless struct[:name].nil? | 498 unless struct[:name].nil? |
498 if struct[:name][0, 1] == "*" | 499 if struct[:name][0, 1] == "*" |
499 struct[:name].sub!("*", "") | 500 struct[:name].sub!("*", "") |
500 end | 501 end |
501 end | 502 end |
502 | 503 |
503 return_type = nil | 504 return_type = nil |
504 stripped_return_type = nil | 505 stripped_return_type = nil |
505 body = m[2] | 506 body = m[2] |
506 | 507 |
507 if m[2] | 508 if m[2] |
508 m[2].split(/,|;/).map do |i| | 509 m[2].split(/,|;/).map do |i| |
509 str, bytes = i.split(":", 2).map do |x| | 510 str, bytes = i.split(":", 2).map do |x| |
510 x.strip | 511 x.strip |
511 end | 512 end |
512 | 513 |
513 var = get_var_info(str, true) | 514 var = get_var_info(str, true) |
514 | 515 |
515 if var | 516 if var |
516 if var.return_type == "***dummy***" | 517 if var.return_type == "***dummy***" |
517 var.return_type = return_type | 518 var.return_type = return_type |
518 var.stripped_return_type = stripped_return_type | 519 var.stripped_return_type = stripped_return_type |
519 else | 520 else |
520 return_type = var.return_type | 521 return_type = var.return_type |
521 stripped_return_type = var.stripped_return_type | 522 stripped_return_type = var.stripped_return_type |
522 end | 523 end |
523 | 524 |
524 struct[:members] << { :name => var.name, :bytes => bytes, :declaredType => var.return_type, :type => "", :type64 => "" } unless str.empty? || str[0] == ?# | 525 struct[:members] << { :name => var.name, :bytes => bytes, :declaredType => var.return_type, :type => "", :type64 => "" } unless str.empty? || str[0] == ?# |
525 | 526 |
526 names = [] | 527 names = [] |
527 | 528 |
528 tmp = struct[:members].collect do |member| | 529 tmp = struct[:members].collect do |member| |
529 unless names.include?(member[:name]) | 530 unless names.include?(member[:name]) |
530 names << member[:name] | 531 names << member[:name] |
531 member | 532 member |
532 end | 533 end |
533 end | 534 end |
534 | 535 |
535 struct[:members] = tmp.compact | 536 struct[:members] = tmp.compact |
536 end | 537 end |
537 end | 538 end |
538 end | 539 end |
539 | 540 |
540 header.structs << struct if body | 541 header.structs << struct if body |
541 end | 542 end |
542 end | 543 end |
543 | 544 |
544 def functions (header, inline = false) | 545 def functions (header, inline = false) |
907 | 908 |
908 class DStepGenerator | 909 class DStepGenerator |
909 | 910 |
910 VERSION = 1.0 | 911 VERSION = 1.0 |
911 | 912 |
912 attr_accessor :out_file, :scaner, :code_to_inject, :dependencies_switch | 913 attr_accessor :out_file, :scaner, :inject_path, :dependencies_switch, :options, :exclude |
913 | 914 |
914 def initialize | 915 def initialize |
915 @do_64bit = false | 916 @do_64bit = false |
916 @frameworks = [] | 917 @frameworks = [] |
917 @framework_paths = [] | 918 @framework_paths = [] |
924 @scaner = HeaderScaner.new | 925 @scaner = HeaderScaner.new |
925 @scaner.do_64bit = @do_64bit | 926 @scaner.do_64bit = @do_64bit |
926 @umbrella_framework = nil | 927 @umbrella_framework = nil |
927 @handled_dependencies = [] | 928 @handled_dependencies = [] |
928 @dependencies_switch = false | 929 @dependencies_switch = false |
930 @options = [] | |
931 @extra = false | |
932 @exclude = [] | |
929 | 933 |
930 # link to foundation framework by default | 934 # link to foundation framework by default |
931 @compiler_flags = "-framework Foundation" | 935 @compiler_flags = "-framework Foundation" |
932 end | 936 end |
933 | 937 |
937 | 941 |
938 def do_64bit= (do_64bit) | 942 def do_64bit= (do_64bit) |
939 @do_64bit = do_64bit | 943 @do_64bit = do_64bit |
940 @scaner.do_64bit = do_64bit | 944 @scaner.do_64bit = do_64bit |
941 end | 945 end |
946 | |
947 def extra | |
948 @extra | |
949 end | |
950 | |
951 def extra= (extra) | |
952 @extra = extra | |
953 @scaner.extra = extra | |
954 end | |
942 | 955 |
943 def collect | 956 def collect |
944 scaner.scan(@frameworks, @headers) | 957 scaner.scan(@frameworks, @headers) |
945 @classes = scaner.get_classes | 958 @classes = scaner.get_classes |
946 @protocols = scaner.get_protocols | 959 @protocols = scaner.get_protocols |
983 end | 996 end |
984 | 997 |
985 if idx = header_basenames.index("#{name}.h") | 998 if idx = header_basenames.index("#{name}.h") |
986 header_basenames.delete_at(idx) | 999 header_basenames.delete_at(idx) |
987 header_basenames.unshift("#{name}.h") | 1000 header_basenames.unshift("#{name}.h") |
1001 end | |
1002 | |
1003 exclude = false | |
1004 | |
1005 @exclude.each do |e| | |
1006 p e | |
1007 p pnames | |
1008 exclude = true if e =~ pname | |
988 end | 1009 end |
989 | 1010 |
990 if sub_framework | 1011 if sub_framework |
991 pp = framework_path(parent_framework.name) | 1012 pp = framework_path(parent_framework.name) |
992 tmp, pname = pp.scan(/^(.+)\/(\w+)\.framework\/?$/)[0] | 1013 tmp, pname = pp.scan(/^(.+)\/(\w+)\.framework\/?$/)[0] |
993 @import_directives << "#import <#{pname}/#{pname}.h>" | 1014 @import_directives << "#import <#{pname}/#{pname}.h>" |
994 else | 1015 else |
995 @import_directives << header_basenames.map do |x| | 1016 @import_directives << header_basenames.map do |x| |
996 "#import <#{name}/#{x}>" | 1017 "#import <#{name}/#{x}>" |
997 end.join("\n") | 1018 end.join("\n") |
998 end | 1019 end unless exclude |
1020 | |
1021 exclude = false | |
999 | 1022 |
1000 @import_directives << "\n" | 1023 @import_directives << "\n" |
1001 | 1024 |
1002 @compiler_flags ||= "-F\"#{parent_path}\" -framework #{name}" | 1025 @compiler_flags << " -F\"#{parent_path}\" -framework #{name}" unless sub_framework?(framework.name) |
1003 @cpp_flags ||= "" | 1026 @cpp_flags ||= "" |
1004 @cpp_flags << "-F\"#{parent_path}\" " | 1027 @cpp_flags << "-F\"#{parent_path}\" " |
1005 | 1028 |
1006 headers.each do |header| | 1029 headers.each do |header| |
1007 header_file = HeaderFile.new | 1030 header_file = HeaderFile.new |
1012 framework.headers << header_file | 1035 framework.headers << header_file |
1013 end | 1036 end |
1014 | 1037 |
1015 # Memorize the dependencies. | 1038 # Memorize the dependencies. |
1016 @dependencies = DStepGenerator.dependencies_of_framework(path) | 1039 @dependencies = DStepGenerator.dependencies_of_framework(path) |
1017 | |
1018 handle_sub_frameworks(framework) | 1040 handle_sub_frameworks(framework) |
1041 end | |
1042 | |
1043 def sub_framework? (framework) | |
1044 i = framework.index("framework") | |
1045 return false if i.nil? | |
1046 !framework.index("framework", i + 1).nil? | |
1019 end | 1047 end |
1020 | 1048 |
1021 def handle_sub_frameworks (framework) | 1049 def handle_sub_frameworks (framework) |
1022 path = framework_path(framework.name) | 1050 path = framework_path(framework.name) |
1051 @compiler_flags << " -B #{path}/Headers/ " | |
1023 frameworks_path = File.join(path, "Frameworks") | 1052 frameworks_path = File.join(path, "Frameworks") |
1024 frameworks = Dir.glob(File.join(frameworks_path, "*.framework")) | 1053 frameworks = Dir.glob(File.join(frameworks_path, "*.framework")) |
1025 | 1054 |
1026 frameworks.each do |f| | 1055 frameworks.each do |f| |
1027 add_framework(f, true, framework) | 1056 add_framework(f, true, framework) |
1093 compiler_line << arch_flag | 1122 compiler_line << arch_flag |
1094 | 1123 |
1095 bin = unique_tmp_path "bin", "" | 1124 bin = unique_tmp_path "bin", "" |
1096 log = unique_tmp_path "log", ".txt" | 1125 log = unique_tmp_path "log", ".txt" |
1097 | 1126 |
1127 @options.each do |option| | |
1128 @compiler_flags << " #{option} " | |
1129 end | |
1130 | |
1098 line = "#{compiler_line} -o #{bin} #{src.path} #{@compiler_flags} 2>#{log}" | 1131 line = "#{compiler_line} -o #{bin} #{src.path} #{@compiler_flags} 2>#{log}" |
1099 | 1132 |
1100 unless system(line) | 1133 unless system(line) |
1101 msg = "Cannot compile Objective-C code ...aborting\nCommand was: #{line}\n\nLog:\n#{File.read(log)}\n\n" | 1134 msg = "Cannot compile Objective-C code ...aborting\nCommand was: #{line}\n\nLog:\n#{File.read(log)}\n\n" |
1102 $stderr << msg | 1135 $stderr << msg |
1176 header.function_pointers.each do |fp, value| | 1209 header.function_pointers.each do |fp, value| |
1177 types << value.return_type | 1210 types << value.return_type |
1178 | 1211 |
1179 value.args.each do |arg| | 1212 value.args.each do |arg| |
1180 types << arg.type | 1213 types << arg.type |
1181 end | 1214 end unless value.args.nil? |
1182 end | 1215 end |
1183 | 1216 |
1184 types | 1217 types |
1185 end | 1218 end |
1186 | 1219 |
1297 | 1330 |
1298 value.args.each do |arg| | 1331 value.args.each do |arg| |
1299 arg.resolved_type = resolved_types[i] unless enable_64bit | 1332 arg.resolved_type = resolved_types[i] unless enable_64bit |
1300 arg.resolved_type64 = resolved_types[i] if enable_64bit | 1333 arg.resolved_type64 = resolved_types[i] if enable_64bit |
1301 i += 1 | 1334 i += 1 |
1302 end | 1335 end unless value.args.nil? |
1303 end | 1336 end |
1304 | 1337 |
1305 i | 1338 i |
1306 end | 1339 end |
1307 | 1340 |
1383 end | 1416 end |
1384 | 1417 |
1385 i | 1418 i |
1386 end | 1419 end |
1387 | 1420 |
1421 def get_framework_name (framework) | |
1422 i = framework.rindex(".framework") | |
1423 return framework if i.nil? | |
1424 x = framework.rindex("/", i) | |
1425 framework[x + 1 ... i] | |
1426 end | |
1427 | |
1388 def resolve_types (enable_64bit = false) | 1428 def resolve_types (enable_64bit = false) |
1389 code = "#include <stdio.h>\n" | 1429 code = "#include <stdio.h>\n" |
1390 code << "#import <objc/objc-class.h>\n" | |
1391 | |
1392 # @dependencies.each do |f| | |
1393 # # get the framework name | |
1394 # i = f.index('.') | |
1395 # str = f[0 ... i] | |
1396 # i = str.rindex('/') | |
1397 # str = str[i + 1 .. -1] | |
1398 # | |
1399 # code << "#import <#{str}/#{str}.h>\n" | |
1400 # end | |
1401 | |
1402 code << @import_directives | 1430 code << @import_directives |
1403 types = [] | 1431 types = [] |
1404 | 1432 |
1405 code << @code_to_inject + "\n" unless @code_to_inject.nil? | 1433 @frameworks.each do |framework| |
1406 | |
1407 @frameworks.each do |framework| | |
1408 framework.headers.each do |header| | 1434 framework.headers.each do |header| |
1409 | 1435 exclude = false |
1410 header.imports do |import| | 1436 |
1411 code << "#import <#{import}.h>\n" | 1437 @exclude.each do |e| |
1412 end | 1438 exclude = true if e =~ header.name |
1439 end | |
1440 | |
1441 if framework.name[0, 1] == "/" | |
1442 code << "#import \"#{framework.name}/Headers/#{header.name}.h\"\n" unless header.name == "xmmintrin" | |
1443 else | |
1444 code << "#import <#{framework.name}/#{header.name}.h>\n" unless header.name == "xmmintrin" | |
1445 end unless exclude | |
1413 | 1446 |
1414 types << collect_header_types(header, enable_64bit) | 1447 types << collect_header_types(header, enable_64bit) |
1415 end | 1448 |
1416 end | 1449 exclude = false |
1450 end | |
1451 end if @extra | |
1452 | |
1453 @headers.each do |header| | |
1454 exclude = false | |
1455 | |
1456 @exclude.each do |e| | |
1457 exclude = true if e =~ header.name | |
1458 end | |
1459 | |
1460 code << "#import <#{header.name}.h>\n" unless exclude || header.name == "xmmintrin" | |
1461 | |
1462 exclude = false | |
1463 end if @extra | |
1464 | |
1465 File.foreach(@inject_path) do |line| | |
1466 code << line | |
1467 end if !@inject_path.nil? && File.exist?(@inject_path) | |
1468 | |
1469 code << "\n\n" | |
1417 | 1470 |
1418 @headers.each do |header| | 1471 @headers.each do |header| |
1419 types << collect_header_types(header, enable_64bit) | 1472 types << collect_header_types(header, enable_64bit) |
1420 end | 1473 end |
1421 | 1474 |
1426 | 1479 |
1427 code << "int main ()\n{\n" | 1480 code << "int main ()\n{\n" |
1428 types.flatten! | 1481 types.flatten! |
1429 | 1482 |
1430 types.each do |type| | 1483 types.each do |type| |
1431 code << ' printf("%s\n", ' + "@encode(#{type}));\n" | 1484 code << ' printf("%s\n", ' + "@encode(__typeof__(#{type})));\n" unless type.nil? || type.length == 0 |
1432 end | 1485 end |
1433 | 1486 |
1434 code << " return 0;\n}" | 1487 code << " return 0;\n}" |
1435 | 1488 |
1436 resolved_types = [] | 1489 resolved_types = [] |
1507 | 1560 |
1508 header.function_pointers.each do |fp, value| | 1561 header.function_pointers.each do |fp, value| |
1509 xml.functionPointer :name => fp, :variadic => value.variadic do | 1562 xml.functionPointer :name => fp, :variadic => value.variadic do |
1510 value.args.each do |arg| | 1563 value.args.each do |arg| |
1511 xml.arg :declaredType => arg.type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const | 1564 xml.arg :declaredType => arg.type, :type => arg.resolved_type, :type64 => arg.resolved_type64, :const => arg.const |
1512 end | 1565 end unless value.args.nil? |
1513 | 1566 |
1514 xml.returnValue :declaredType => value.return_type, :type => value.resolved_type, :type64 => value.resolved_type64, :const => value.const | 1567 xml.returnValue :declaredType => value.return_type, :type => value.resolved_type, :type64 => value.resolved_type64, :const => value.const |
1515 end | 1568 end |
1516 end | 1569 end |
1517 end | 1570 end |
1660 # opts.on("-d", "--output-dir PATH", "Write ouptut to the given paht, use this with the --framework option") do |opt| | 1713 # opts.on("-d", "--output-dir PATH", "Write ouptut to the given paht, use this with the --framework option") do |opt| |
1661 # die "Output directory can't be specified more than once" if dstep_gen.out_dir | 1714 # die "Output directory can't be specified more than once" if dstep_gen.out_dir |
1662 # dstep_gen.out_dir = opt | 1715 # dstep_gen.out_dir = opt |
1663 # end | 1716 # end |
1664 | 1717 |
1665 opts.on("-c", "--code CODE", "Add code") do |opt| | 1718 opts.on("-c", "--code FILE", "The path to a file with code to inject") do |opt| |
1666 dstep_gen.code_to_inject = opt | 1719 dstep_gen.inject_path = opt |
1667 end | 1720 end |
1668 | 1721 |
1669 opts.on("-d", "--dependencies", "Write framework dependencies and exit") do |opt| | 1722 opts.on("-d", "--dependencies", "Write framework dependencies and exit") do |opt| |
1670 dstep_gen.dependencies_switch = true | 1723 dstep_gen.dependencies_switch = true |
1724 end | |
1725 | |
1726 opts.on("-s", "--option OPTION", "Pass OPTION to the compiler") do |opt| | |
1727 dstep_gen.options << opt | |
1728 end | |
1729 | |
1730 opts.on("-e", "--extra", "Included extra headers headers") do |opt| | |
1731 dstep_gen.extra = true | |
1732 end | |
1733 | |
1734 opts.on("-x", "--exclude HEADER", "Exlude the given header file") do |opt| | |
1735 dstep_gen.exclude << opt | |
1671 end | 1736 end |
1672 | 1737 |
1673 help_msg = "Use the `-h' flag or for help." | 1738 help_msg = "Use the `-h' flag or for help." |
1674 | 1739 |
1675 opts.on("-h", "--help", "Show this message.") do | 1740 opts.on("-h", "--help", "Show this message.") do |