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