PageRenderTime 66ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/ext/tk/extconf.rb

https://github.com/ahwuyeah/ruby
Ruby | 2094 lines | 1783 code | 177 blank | 134 comment | 257 complexity | 1d877a5a74d1f44a398e0d3b6298f317 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-3.0, Unlicense, GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. ##############################################################
  2. # extconf.rb for tcltklib
  3. # release date: 2010-07-30
  4. ##############################################################
  5. require 'mkmf'
  6. TkLib_Config = {}
  7. TkLib_Config['search_versions'] =
  8. # %w[8.9 8.8 8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0 7.6 4.2]
  9. # %w[8.7 8.6 8.5 8.4 8.3 8.2 8.1 8.0]
  10. # %w[8.7 8.6 8.5 8.4 8.0] # to shorten search steps
  11. %w[8.5 8.4] # At present, Tcl/Tk8.6 is not supported.
  12. TkLib_Config['unsupported_versions'] =
  13. %w[8.8 8.7 8.6] # At present, Tcl/Tk8.6 is not supported.
  14. TkLib_Config['major_nums'] = '87'
  15. ##############################################################
  16. TkLib_Config['enable-shared'] = enable_config("shared")
  17. ##############################################################
  18. # use old extconf.rb ?
  19. ##############################################################
  20. if with_config('tk-old-extconf')
  21. require File.join(File.dirname(__FILE__), 'old-extconf.rb')
  22. exit
  23. end
  24. ##############################################################
  25. # check configs
  26. ##############################################################
  27. ($cleanfiles ||= "") << 'config_list'
  28. config_list_file = 'config_list'
  29. config_list_file_source = File.join(File.dirname(__FILE__),'config_list.in')
  30. if !File.exist?(config_list_file) ||
  31. File.ctime(config_list_file_source) > File.ctime(config_list_file)
  32. old_config_list_file = config_list_file_source
  33. else
  34. old_config_list_file = config_list_file
  35. end
  36. current_configs = {'with'=>{}, 'enable'=>{}}
  37. # setup keys by config_list.in
  38. IO.foreach(config_list_file_source){|line|
  39. line.chomp!
  40. line.lstrip!
  41. next if line.empty? || line =~ /^\#/ #
  42. mode, key, value = line.split(/\s+/, 3)
  43. value ||= ""
  44. current_configs[mode][key] = value rescue nil
  45. }
  46. # define current value of keys
  47. IO.foreach(old_config_list_file){|line|
  48. line.chomp!
  49. line.lstrip!
  50. next if line.empty? || line =~ /^\#/ #
  51. mode, key, value = line.split(/\s+/, 3)
  52. value ||= ""
  53. if current_configs[mode] && current_configs[mode].has_key?(key)
  54. current_configs[mode][key] = value
  55. end
  56. }
  57. update_flag = false
  58. current_configs['with'].each_key{|key|
  59. if (value = with_config(key).to_s) != current_configs['with'][key]
  60. update_flag = true
  61. current_configs['with'][key] = value
  62. end
  63. }
  64. current_configs['enable'].each_key{|key|
  65. if (value = enable_config(key).to_s) != current_configs['enable'][key]
  66. update_flag = true
  67. current_configs['enable'][key] = value
  68. end
  69. }
  70. # update current_configs
  71. if update_flag || !File.exist?(config_list_file)
  72. open(config_list_file, 'w'){|fobj|
  73. fobj.print("# values of current configure options (generated by extconf.rb)\n");
  74. ['with', 'enable'].each{|mode|
  75. current_configs[mode].each_key{|key|
  76. fobj.print("#{mode} #{key} #{current_configs[mode][key]}\n")
  77. }
  78. }
  79. }
  80. end
  81. if update_flag
  82. puts "Configure options for Ruby/Tk may be updated."
  83. puts "So, delete files which depend on old configs."
  84. File.delete(*Dir.glob("*.#{CONFIG['DLEXT']}", File::FNM_CASEFOLD))
  85. File.delete(*Dir.glob("*.#{$OBJEXT}", File::FNM_CASEFOLD))
  86. File.delete('Makefile') rescue nil
  87. else
  88. makefile = 'Makefile'
  89. if File.exist?(makefile) &&
  90. File.ctime(config_list_file) > File.ctime(makefile)
  91. # no need to update Makefile
  92. exit
  93. end
  94. end
  95. ##############################################################
  96. # fuctions
  97. ##############################################################
  98. def is_win32?
  99. /mswin|mingw|cygwin|bccwin/ =~ RUBY_PLATFORM
  100. end
  101. def is_macosx?
  102. /darwin/ =~ RUBY_PLATFORM
  103. end
  104. def maybe_64bit?
  105. /64|universal|s390x/ =~ RUBY_PLATFORM
  106. end
  107. def check_tcltk_version(version)
  108. return [nil, nil] unless version.kind_of? String
  109. tclver, tkver = version.split(',')
  110. tclver = tclver.strip
  111. return [tclver, tkver.strip] if tkver
  112. dot = major = minor_dot = minor = plvl_dot = plvl = ext = nil
  113. if tclver =~ /^(\d)(\.?)(\d)(\.?)(\d*)(.*)$/
  114. major = $1; minor_dot = $2; minor = $3; plvl_dot = $4; plvl = $5; ext = $6
  115. dot = ! minor_dot.empty?
  116. if plvl_dot.empty? && ! plvl.empty?
  117. minor << plvl
  118. end
  119. elsif tclver =~ /^(\d)(\.?)(\d?)(.*)$/
  120. major = $1; minor_dot = $2; minor = $3; ext = $4
  121. dot = ! minor_dot.empty?
  122. else # unknown -> believe user
  123. return [tclver, tkver]
  124. end
  125. # check Tcl7.6 / Tk4.2 ?
  126. if major == "7" # Tcl7.6 ( not support Tclversion < 7.6 )
  127. # Tk4.2
  128. tkver = "4" + ((dot)? ".": "") + ((minor.empty)? "": "2") + ext
  129. elsif major == "4" # Tk4.2 ( not support Tkversion < 4.2 )
  130. # Tcl7.6
  131. tkver = tclver
  132. tclver = "7" + ((dot)? ".": "") + ((minor.empty)? "": "6") + ext
  133. end
  134. tkver = tclver unless tkver
  135. [tclver, tkver]
  136. end
  137. def get_shlib_versions(major = 8, minor_max = 9, minor_min = 0, ext = "")
  138. if tclcfg = TkLib_Config["tclConfig_info"]
  139. major = tclcfg['TCL_MAJOR_VERSION'].to_i
  140. minor_min = tclcfg['TCL_MINOR_VERSION'].to_i
  141. elsif TkLib_Config["tcltkversion"]
  142. tclver, tkver = TkLib_Config["tcltkversion"]
  143. if tclver =~ /8\.?(\d)(.*)/
  144. minor_min = $1.to_i
  145. ext = $2
  146. else
  147. # unsupported version
  148. return [""]
  149. end
  150. end
  151. # if disable-stubs, version is fixed.
  152. minor_max = minor_min unless TkLib_Config["tcltk-stubs"]
  153. vers = []
  154. minor_max.downto(minor_min){|minor|
  155. vers << "#{major}.#{minor}#{ext}" unless ext.empty?
  156. vers << "#{major}.#{minor}"
  157. }
  158. vers << ""
  159. end
  160. def get_shlib_path_head
  161. path_head = []
  162. path_dirs = []
  163. if TkLib_Config["ActiveTcl"].kind_of?(String) # glob path
  164. # path_head << TkLib_Config["ActiveTcl"]
  165. path_head.concat Dir.glob(TkLib_Config["ActiveTcl"], File::FNM_CASEFOLD).sort.reverse
  166. # path_dirs.concat Dir.glob(File.join(TkLib_Config["ActiveTcl"], 'lib'), File::FNM_CASEFOLD).sort.reverse
  167. end
  168. if CROSS_COMPILING
  169. elsif is_win32?
  170. if TkLib_Config["ActiveTcl"]
  171. path_head.concat ["c:/ActiveTcl", "c:/Program Files/ActiveTcl",
  172. "c:/Program Files (x86)/ActiveTcl"]
  173. end
  174. path_head.concat [
  175. "c:/Tcl", "c:/Program Files/Tcl", "c:/Program Files (x86)/Tcl",
  176. "/Tcl", "/Program Files/Tcl", "/Program Files (x86)/Tcl"
  177. ]
  178. path_head.uniq!
  179. #path_head.each{|dir| path_dirs << dir.dup if File.directory? dir}
  180. path_head.each{|dir| path_dirs << File.expand_path(dir) if File.directory? dir}
  181. # for MinGW
  182. ["/usr/local/lib64", "/usr/lib64", "/usr/local/lib", "/usr/lib"].each{|dir|
  183. #path_dirs << dir if File.directory? dir
  184. path_dirs << File.expand_path(dir) if File.directory? dir
  185. }
  186. path_dirs |= ENV['LIBRARY_PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['LIBRARY_PATH']
  187. path_dirs |= ENV['PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['PATH']
  188. else
  189. [
  190. '/opt', '/pkg', '/share',
  191. '/usr/local/opt', '/usr/local/pkg', '/usr/local/share', '/usr/local',
  192. '/usr/opt', '/usr/pkg', '/usr/share', '/usr/contrib', '/usr'
  193. ].each{|dir|
  194. next unless File.directory?(dir)
  195. path_dirs << "#{dir}/lib64" if maybe_64bit?
  196. path_dirs << "#{dir}/lib"
  197. path_dirs << "#{dir}" unless Dir.glob("#{dir}/lib*.*", File::FNM_CASEFOLD).empty?
  198. dirnames = []
  199. if TkLib_Config["ActiveTcl"]
  200. dirnames.concat ["ActiveTcl"]
  201. end
  202. dirnames.concat ["TclTk","Tcl_Tk","Tcl-Tk"]
  203. dirnames.each{|name|
  204. path_dirs << "#{dir}/#{name}" if File.directory?("#{dir}/#{name}")
  205. path_head << "#{dir}/#{name}" unless Dir.glob("#{dir}/#{name}[-89_]*", File::FNM_CASEFOLD).empty?
  206. }
  207. }
  208. end
  209. unless TkLib_Config["space-on-tk-libpath"]
  210. path_head.delete_if{|path| path =~ / /}
  211. path_dirs.delete_if{|path| path =~ / /}
  212. end
  213. [path_head, path_dirs]
  214. end
  215. def find_macosx_framework
  216. use_framework = is_macosx? && TkLib_Config["ActiveTcl"]
  217. use_framework ||= (tcl_hdr = with_config("tcl-framework-header"))
  218. use_framework ||= (tk_hdr = with_config("tk-framework-header"))
  219. tcl_hdr = nil unless tcl_hdr.kind_of? String
  220. tk_hdr = nil unless tk_hdr.kind_of? String
  221. TkLib_Config["tcl-framework-header"] = tcl_hdr
  222. TkLib_Config["tk-framework-header"] = tk_hdr
  223. use_framework ||= (tcl_dir = with_config("tcl-framework-dir"))
  224. tcl_dir = nil unless tcl_dir.kind_of? String
  225. if !tcl_dir && tcl_hdr
  226. # e.g. /Library/Frameworks/Tcl.framework/Headers
  227. # ==> /Library/Frameworks/Tcl.framework
  228. tcl_dir = File.dirname(tcl_hdr.strip.chomp('/'))
  229. end
  230. TkLib_Config["tcl-framework-dir"] = tcl_dir
  231. use_framework ||= (tk_dir = with_config("tk-framework-dir"))
  232. tk_dir = nil unless tk_dir.kind_of? String
  233. if !tk_dir && tk_hdr
  234. # e.g. /Library/Frameworks/Tk.framework/Headers
  235. # ==> /Library/Frameworks/Tk.framework
  236. tk_dir = File.dirname(tk_hdr.strip.chomp('/'))
  237. end
  238. TkLib_Config["tk-framework-dir"] = tk_dir
  239. if tcl_dir && !tk_dir
  240. tk_dir = File.join(File.dirname(tcl_dir), 'Tk.framework')
  241. TkLib_Config["tk-framework-dir"] = tk_dir
  242. elsif !tcl_dir && tk_dir
  243. tcl_dir = File.join(File.dirname(tk_dir), 'Tcl.framework')
  244. TkLib_Config["tcl-framework-dir"] = tcl_dir
  245. end
  246. if tcl_dir && tk_dir
  247. TkLib_Config["tcltk-framework"] = File.dirname(tcl_dir) unless TkLib_Config["tcltk-framework"]
  248. return [tcl_dir, tk_dir]
  249. end
  250. # framework is disabled?
  251. if with_config("tcltk-framework") == false ||
  252. enable_config("tcltk-framework") == false
  253. return false
  254. end
  255. use_framework ||= (framework_dir = with_config("tcltk-framework"))
  256. if framework_dir.kind_of? String
  257. TkLib_Config["tcltk-framework"] = framework_dir.strip.chomp('/')
  258. return [File.join(TkLib_Config["tcltk-framework"], 'Tcl.framework'),
  259. File.join(TkLib_Config["tcltk-framework"], 'Tk.framework')]
  260. end
  261. unless enable_config("tcltk-framework", use_framework) ||
  262. enable_config("mac-tcltk-framework", use_framework)
  263. TkLib_Config["tcltk-framework"] = false
  264. return false
  265. end
  266. paths = [
  267. #"~/Library/Frameworks",
  268. "/Library/Frameworks",
  269. "/Network/Library/Frameworks", "/System/Library/Frameworks"
  270. ]
  271. paths.reverse! unless TkLib_Config["ActiveTcl"] # system has higher priority
  272. paths.map{|dir| dir.strip.chomp('/')}.each{|dir|
  273. next unless File.exist?(File.join(dir, "Tcl.framework", "Headers"))
  274. next unless File.directory?(tcldir = File.join(dir, "Tcl.framework"))
  275. next unless File.exist?(File.join(dir, "Tk.framework", "Headers"))
  276. next unless File.directory?(tkdir = File.join(dir, "Tk.framework"))
  277. TkLib_Config["tcltk-framework"] = dir
  278. return [tcldir, tkdir]
  279. }
  280. nil
  281. end
  282. def collect_tcltk_defs(tcl_defs_str, tk_defs_str)
  283. conflicts = [
  284. 'PACKAGE_NAME', 'PACKAGE_TARNAME', 'PACKAGE_VERSION',
  285. 'PACKAGE_STRING', 'PACKAGE_BUGREPORT'
  286. ]
  287. begin
  288. # Ruby 1.9.x or later
  289. arch_config_h = RbConfig.expand($arch_hdrdir + "/ruby/config.h")
  290. if File.exist?(arch_config_h)
  291. keys = []
  292. IO.foreach(arch_config_h){|line|
  293. if line =~ /^#define +([^ ]+)/
  294. keys << $1
  295. end
  296. }
  297. conflicts = keys
  298. end
  299. rescue
  300. # ignore, use default
  301. end
  302. if tcl_defs_str
  303. tcl_defs = tcl_defs_str.split(/ ?-D/).map{|s|
  304. s =~ /^([^=]+)(.*)$/
  305. [$1, $2]
  306. }
  307. else
  308. tcl_defs = []
  309. end
  310. if tk_defs_str
  311. tk_defs = tk_defs_str.split(/ ?-D/).map{|s|
  312. s =~ /^([^=]+)(.*)$/
  313. [$1, $2]
  314. }
  315. else
  316. tk_defs = []
  317. end
  318. defs = tcl_defs | tk_defs
  319. defs.delete_if{|name,value|
  320. conflicts.include?(name) ||
  321. ( (vtcl = tcl_defs.assoc(name)) && (vtk = tk_defs.assoc(name)) &&
  322. vtcl != vtk )
  323. }
  324. defs.map{|ary| s = ary.join(''); (s.strip.empty?)? "": "-D" << s}
  325. end
  326. def parse_tclConfig(file)
  327. # check tclConfig.sh/tkConfig.sh
  328. tbl = Hash.new{|h,k| h[k] = ""}
  329. return tbl unless file
  330. IO.foreach(file){|line|
  331. line.strip!
  332. next if line !~ /^([^\#=][^=]*)=(['"]|)(.*)\2$/
  333. key, val = $1, $3
  334. tbl[key] = val.gsub(/\$\{([^}]+)\}/){|s|
  335. subst = $1
  336. (tbl[subst])? tbl[subst]: s
  337. } rescue nil
  338. }
  339. tbl
  340. end
  341. def get_libpath(lib_flag, lib_spec)
  342. # get libpath from {TCL,Tk}_LIB_FLAG and {TCL,Tk}_LIB_SPEC
  343. lib_spec.gsub(/(#{lib_flag}|-L)/, "").strip
  344. end
  345. def get_tclConfig_dirs
  346. config_dir = []
  347. if CROSS_COMPILING
  348. elsif is_win32?
  349. if TkLib_Config["ActiveTcl"]
  350. dirs = []
  351. if TkLib_Config["ActiveTcl"].kind_of?(String)
  352. dirs << File.join(TkLib_Config["ActiveTcl"], 'lib')
  353. end
  354. dirs.concat [
  355. "c:/ActiveTcl*/lib", "c:/Tcl*/lib",
  356. "c:/Program Files*/ActiveTcl*/lib", "c:/Program Files*/Tcl*/lib",
  357. "/ActiveTcl*/lib", "/Tcl*/lib",
  358. "/Program Files*/ActiveTcl*/lib", "/Program Files*/Tcl*/lib"
  359. ]
  360. else
  361. dirs = [
  362. "c:/Tcl*/lib", "c:/Program Files*/Tcl*/lib",
  363. "/Tcl*/lib", "/Program Files*/Tcl*/lib"
  364. ]
  365. end
  366. dirs = dirs.collect{|d| Dir.glob(d, File::FNM_CASEFOLD)}.flatten.uniq
  367. dirs |= ENV['LIBRARY_PATH'].split(';') if ENV['LIBRARY_PATH']
  368. dirs |= ENV['PATH'].split(';') if ENV['PATH']
  369. exeext = RbConfig::CONFIG['EXEEXT']
  370. ENV['PATH'].split(File::PATH_SEPARATOR).each{|dir|
  371. dir.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
  372. next if Dir.glob(File.join(dir, "{tclsh,wish}*#{exeext}"), File::FNM_CASEFOLD).empty?
  373. dirs << File.expand_path(File.join(dir, '..', 'lib'))
  374. dirs << dir
  375. # dirs << File.expand_path(File.join(dir, '..'))
  376. }
  377. unless TkLib_Config["space-on-tk-libpath"]
  378. dirs.delete_if{|path| path =~ / /}
  379. end
  380. config_dir.concat(dirs.zip(dirs))
  381. else
  382. if framework = find_macosx_framework()
  383. config_dir.unshift(framework)
  384. end
  385. if activeTcl = TkLib_Config['ActiveTcl']
  386. # check latest version at first
  387. if is_macosx?
  388. base = File.expand_path(activeTcl)
  389. config_dir << [
  390. File.join(base, 'Tcl.framework'), File.join(base, 'Tk.framework')
  391. ]
  392. config_dir << [
  393. File.join(base, 'Tcl.framework', 'Versions', 'Current'),
  394. File.join(base, 'Tk.framework', 'Versions', 'Current')
  395. ]
  396. Dir.glob(File.join(base, 'Tcl.framework',
  397. 'Versions', '*')).sort.reverse.each{|dir|
  398. next if dir =~ /Current/
  399. config_dir << [dir, dir.gsub(/Tcl/, 'Tk')]
  400. }
  401. else
  402. config_dir.concat(Dir.glob(File.join(activeTcl, 'lib'), File::FNM_CASEFOLD).sort.reverse)
  403. end
  404. end
  405. config_dir << RbConfig::CONFIG['libdir']
  406. ((maybe_64bit?)? ['lib64', 'lib']: ['lib']).each{|dir|
  407. config_dir.concat [
  408. File.join(RbConfig::CONFIG['exec_prefix'], dir),
  409. File.join(RbConfig::CONFIG['prefix'], dir),
  410. "/usr/local/opt/#{dir}", "/usr/local/pkg/#{dir}",
  411. "/usr/local/share/#{dir}", "/usr/local/#{dir}",
  412. "/usr/opt/#{dir}", "/usr/pkg/#{dir}", "/usr/share/#{dir}",
  413. "/usr/contrib/#{dir}", "/usr/#{dir}"
  414. ]
  415. }
  416. config_dir.concat [
  417. '/opt', '/pkg', '/share',
  418. '/usr/local/opt', '/usr/local/pkg', '/usr/local/share', '/usr/local',
  419. '/usr/opt', '/usr/pkg', '/usr/share', '/usr/contrib', '/usr'
  420. ].map{|dir|
  421. Dir.glob(dir + "/{tcltk,tcl,tk}[#{TkLib_Config['major_nums']}*/lib",
  422. File::FNM_CASEFOLD)
  423. Dir.glob(dir + "/{tcltk,tcl,tk}[#{TkLib_Config['major_nums']}*",
  424. File::FNM_CASEFOLD)
  425. Dir.glob(dir + '/{tcltk,tcl,tk}/lib', File::FNM_CASEFOLD)
  426. Dir.glob(dir + '/{tcltk,tcl,tk}', File::FNM_CASEFOLD)
  427. }.flatten!
  428. exeext = RbConfig::CONFIG['EXEEXT']
  429. ENV['PATH'].split(File::PATH_SEPARATOR).each{|dir|
  430. dir.tr!(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
  431. next if Dir.glob(File.join(dir, "{tclsh,wish}*#{exeext}"), File::FNM_CASEFOLD).empty?
  432. config_dir << File.expand_path(File.join(dir, '..', 'lib'))
  433. }
  434. # for MacOS X
  435. paths = [
  436. #"~/Library/Tcl",
  437. "/Library/Tcl", "/Network/Library/Tcl", "/System/Library/Tcl"
  438. ]
  439. paths.reverse! unless TkLib_Config["ActiveTcl"]
  440. paths.each{|path|
  441. config_dir << path
  442. config_dir.concat(Dir.glob(File.join(path, '{tcl,tk}*'), File::FNM_CASEFOLD).sort.reverse.find_all{|d| File.directory?(d)})
  443. }
  444. paths = [
  445. #"~/Library/Frameworks",
  446. "/Library/Frameworks",
  447. "/Network/Library/Frameworks", "/System/Library/Frameworks"
  448. ]
  449. paths.reverse! unless TkLib_Config["ActiveTcl"]
  450. paths.each{|frmwk|
  451. base = File.expand_path(frmwk)
  452. config_dir << [
  453. File.join(base, 'Tcl.framework'), File.join(base, 'Tk.framework')
  454. ]
  455. config_dir << [
  456. File.join(base, 'Tcl.framework', 'Versions', 'Current'),
  457. File.join(base, 'Tk.framework', 'Versions', 'Current')
  458. ]
  459. Dir.glob(File.join(base, 'Tcl.framework',
  460. 'Versions', '*')).sort.reverse.each{|dir|
  461. next if dir =~ /Current/
  462. config_dir << [dir, dir.gsub(/Tcl/, 'Tk')]
  463. }
  464. }
  465. end
  466. config_dir
  467. end
  468. def get_ext_list()
  469. exts = [CONFIG['DLEXT']]
  470. exts.concat %w(dll) if is_win32?
  471. exts.concat %w(bundle dylib) if is_macosx?
  472. if TkLib_Config["tcltk-stubs"] || TkLib_Config['enable-shared'] == false
  473. exts.unshift "lib" if is_win32?
  474. exts.unshift "a"
  475. exts.unshift CONFIG['LIBEXT']
  476. end
  477. if is_win32?
  478. exts.map!{|ext| [ext.downcase, ext.upcase]}.flatten!
  479. end
  480. exts
  481. end
  482. def libcheck_for_tclConfig(tcldir, tkdir, tclconf, tkconf)
  483. tcllib_ok = tklib_ok = false
  484. if TkLib_Config["tcltk-stubs"]
  485. stub = "stub"
  486. tclfunc = "Tcl_InitStubs"
  487. tkfunc = "Tk_InitStubs"
  488. else
  489. stub = ""
  490. tclfunc = "Tcl_FindExecutable"
  491. tkfunc = "Tk_Init"
  492. end
  493. incflags = ($INCFLAGS ||= "").dup
  494. libpath = ($LIBPATH ||= []).dup
  495. libs_param = ($libs ||= "").dup
  496. tcllibs = nil
  497. mkmf_param = nil
  498. tclver, tkver = TkLib_Config["tcltkversion"]
  499. exts = "(" + get_ext_list.join('|') + ")"
  500. if tclver
  501. tcl_glob = "*tcl#{stub}#{tclver}.*"
  502. tcl_regexp = /^.*(tcl#{stub}#{tclver}.*)\.(#{exts}).*$/
  503. elsif tclconf
  504. tcl_glob = "*tcl#{stub}#{tclconf['TCL_MAJOR_VERSION']}{.,}#{tclconf['TCL_MINOR_VERSION']}*.*"
  505. tcl_regexp = /^.*(tcl#{stub}#{tclconf['TCL_MAJOR_VERSION']}(?:\.|)#{tclconf['TCL_MINOR_VERSION']}.*)\.(#{exts}).*$/
  506. end
  507. if tkver
  508. tk_glob = "*tk#{stub}#{tkver}.*"
  509. tk_regexp = /^.*(tk#{stub}#{tkver}.*)\.(#{exts}).*$/
  510. elsif tkconf
  511. tk_glob = "*tk#{stub}#{tkconf['TK_MAJOR_VERSION']}{.,}#{tkconf['TK_MINOR_VERSION']}*.*"
  512. tk_regexp = /^.*(tk#{stub}#{tkconf['TK_MAJOR_VERSION']}(?:\.|)#{tkconf['TK_MINOR_VERSION']}.*)\.#{exts}.*$/
  513. end
  514. tcllib_ok ||= !tclconf || Dir.glob(File.join(tcldir, tcl_glob), File::FNM_CASEFOLD).find{|file|
  515. if file =~ tcl_regexp
  516. libname = $1
  517. ext = $2.downcase
  518. begin
  519. $INCFLAGS = incflags.dup << " " << tclconf["TCL_INCLUDE_SPEC"]
  520. #puts "check #{file} #{$1} #{tclfunc} #{tcldir}"
  521. #find_library($1, tclfunc, tcldir)
  522. if (tclconf && tclconf["TCL_SHARED_BUILD"] == "0") ||
  523. (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) || ext == "a"
  524. # static link
  525. tcllibs = $libs + " -DSTATIC_BUILD " + file.quote
  526. # FIX ME: avoid pathname trouble (fail to find) on MinGW.
  527. # e.g. TCL_INCLUDE_SPEC describes "-I/usr/local/include",
  528. # but compiler can find "-IC:/msys/1.0/local/include" only.
  529. $INCFLAGS << " -I" << File.join(File.dirname(File.dirname(file)),"include") if is_win32?
  530. else
  531. tcllibs = append_library($libs, libname)
  532. tcllibs = "#{libpathflag([tcldir])} #{tcllibs}"
  533. # FIX ME: avoid pathname trouble (fail to find) on MinGW.
  534. $INCFLAGS << " -I" << File.join(File.dirname(tcldir),"include") if is_win32?
  535. end
  536. $LIBPATH = libpath | [tcldir]
  537. try_func(tclfunc, tcllibs, ["tcl.h"]) ||
  538. ( try_func(tclfunc, tcllibs << " " << tclconf['TCL_LIBS'], ["tcl.h"]) if tclconf['TCL_LIBS'] )
  539. ensure
  540. mkmf_param = {
  541. 'PATH' => file,
  542. 'LIBNAME' => libname,
  543. 'libs' => tcllibs.dup,
  544. 'INCFLAGS' => $INCFLAGS.dup,
  545. 'LIBPATH' => $LIBPATH.dup,
  546. }
  547. $LIBPATH = libpath.dup
  548. $libs = libs_param.dup
  549. end
  550. end
  551. }
  552. tclconf['MKMF_PARAMS'] = mkmf_param if tclconf && tcllib_ok
  553. tklib_ok ||= !tkconf || Dir.glob(File.join(tkdir, tk_glob), File::FNM_CASEFOLD).find{|file|
  554. if file =~ tk_regexp
  555. libname = $1
  556. ext = $2.downcase
  557. begin
  558. #puts "check #{file} #{$1} #{tkfunc} #{tkdir}"
  559. # find_library($1, tkfunc, tkdir)
  560. if (tkconf && tkconf["TCL_SHARED_BUILD"] == "0") ||
  561. (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) || ext == "a"
  562. # static link
  563. tklibs = " -DSTATIC_BUILD " + file.quote
  564. # FIX ME: avoid pathname trouble (fail to find) on MinGW.
  565. $INCFLAGS << " -I" << File.join(File.dirname(File.dirname(file)),"include") if is_win32?
  566. else
  567. tklibs = append_library("", libname)
  568. #tklibs = append_library("", $1)
  569. tklibs = "#{libpathflag([tkdir])} #{tklibs}"
  570. # FIX ME: avoid pathname trouble (fail to find) on MinGW.
  571. $INCFLAGS << " -I" << File.join(File.dirname(tcldir),"include") if is_win32?
  572. end
  573. tklibs << " " << tcllibs if tcllibs
  574. tmp_tklibs = tklibs.dup
  575. $LIBPATH = libpath | [tkdir]
  576. try_func(tkfunc, tklibs, ["tcl.h", "tk.h"]) ||
  577. ( try_func(tkfunc, tklibs << " " << tkconf['TK_LIBS'], ["tcl.h", "tk.h"]) if tkconf['TK_LIBS'] ) ||
  578. ( try_func(tkfunc, (tklibs = tmp_tklibs.dup) << " " << tkconf['TK_XLIBSW'], ["tcl.h", "tk.h"]) if tkconf['TK_XLIBSW'] ) ||
  579. ( try_func(tkfunc, tklibs << " " << tkconf['TK_LIBS'], ["tcl.h", "tk.h"]) if tkconf['TK_LIBS'] )
  580. ensure
  581. mkmf_param = {
  582. 'PATH' => file,
  583. 'LIBNAME' => libname,
  584. 'libs' => tklibs.dup,
  585. 'INCFLAGS' => $INCFLAGS.dup,
  586. 'LIBPATH' => $LIBPATH.dup,
  587. }
  588. $LIBPATH = libpath.dup
  589. $libs = libs_param.dup
  590. end
  591. end
  592. }
  593. $INCFLAGS = incflags.dup
  594. tkconf['MKMF_PARAMS'] = mkmf_param if tkconf && tklib_ok
  595. [tcllib_ok, tklib_ok]
  596. end
  597. def search_tclConfig(*paths) # libdir list or [tcl-libdir|file, tk-libdir|file]
  598. TkLib_Config["tclConfig_paths"] = []
  599. paths.compact!
  600. if paths.empty?
  601. config_dir = get_tclConfig_dirs
  602. elsif paths.length == 1 && !paths[0][0] && !paths[0][1]
  603. config_dir = get_tclConfig_dirs.map{|dir|
  604. if dir.kind_of? Array
  605. [ (paths[0][0] == false)? nil: dir[0],
  606. (paths[0][1] == false)? nil: dir[1] ]
  607. else
  608. [ (paths[0][0] == false)? nil: dir,
  609. (paths[0][1] == false)? nil: dir ]
  610. end
  611. }
  612. else
  613. # fixed tclConfig
  614. config_dir = []
  615. paths.each{|path|
  616. if path.kind_of?(Array)
  617. config_dir << path
  618. else
  619. dirs = Dir.glob(path, File::FNM_CASEFOLD)
  620. config_dir.concat(dirs.zip(dirs))
  621. end
  622. }
  623. end
  624. tclver, tkver = TkLib_Config['tcltkversion']
  625. if tclver && tclver =~ /^\D*(\d)\.?(\d)?/ # ignore PATCH_LEVEL
  626. tclver_major = $1
  627. tclver_minor = $2
  628. else
  629. tclver_major = nil
  630. tclver_minor = nil
  631. end
  632. if tkver && tkver =~ /^\D*(\d)\.?(\d)?/ # ignore PATCH_LEVEL
  633. tkver_major = $1
  634. tkver_minor = $2
  635. else
  636. tkver_major = nil
  637. tkver_minor = nil
  638. end
  639. conf = nil
  640. progress_flag = false
  641. config_dir.uniq!
  642. config_dir.map{|dir|
  643. if dir.kind_of? Array
  644. [ (dir[0])? dir[0].strip.chomp('/'): nil,
  645. (dir[1])? dir[1].strip.chomp('/'): nil ]
  646. else
  647. dir.strip.chomp('/')
  648. end
  649. }.each{|dir|
  650. print("."); progress_flag = true # progress
  651. # print("check #{dir} ==>");
  652. if dir.kind_of? Array
  653. tcldir, tkdir = dir
  654. else
  655. tcldir = tkdir = dir
  656. end
  657. tails = ['Config-shared.sh', 'config-shared.sh', 'Config.sh', 'config.sh']
  658. if tcldir
  659. if File.file?(tcldir)
  660. tclcfg_files = [tcldir] * tails.length
  661. else
  662. tclcfg_files = tails.map{|f| File.join(tcldir, 'tcl' << f)}
  663. end
  664. else
  665. tclcfg_files = [nil] * tails.length
  666. end
  667. if tkdir
  668. if File.file?(tkdir)
  669. tkcfg_files = [tkdir] * tails.length
  670. else
  671. tkcfg_files = tails.map{|f| File.join(tkdir, 'tk' << f)}
  672. end
  673. else
  674. tkcfg_files = [nil] * tails.length
  675. end
  676. tclcfg_files.zip(tkcfg_files).map{|tclpath, tkpath|
  677. [ (tclpath && File.exist?(tclpath))? File.expand_path(tclpath): tclpath,
  678. (tkpath && File.exist?(tkpath))? File.expand_path(tkpath): tkpath ]
  679. }.uniq.each{|tclpath, tkpath|
  680. next if tclpath && !File.exist?(tclpath)
  681. next if tkpath && !File.exist?(tkpath)
  682. # parse tclConfig.sh/tkConfig.sh
  683. tclconf = (tclpath)? parse_tclConfig(tclpath): nil
  684. if tclconf
  685. if tclver && ((tclver_major && tclver_major != tclconf['TCL_MAJOR_VERSION']) || (tclver_minor && tclver_minor != tclconf['TCL_MINOR_VERSION']))
  686. print("\n") if progress_flag
  687. puts "Ignore \"#{tclpath}\" (unmatch with configured version)."
  688. progress_flag = false
  689. next
  690. end
  691. if TkLib_Config['unsupported_versions'].find{|ver| ver == "#{tclconf['TCL_MAJOR_VERSION']}.#{tclconf['TCL_MINOR_VERSION']}"}
  692. print("\n") if progress_flag
  693. puts "Ignore \"#{tclpath}\" (unsupported version of Tcl/Tk)."
  694. progress_flag = false
  695. next
  696. end
  697. end
  698. tkconf = (tkpath)? parse_tclConfig(tkpath): nil
  699. if tkconf
  700. if tkver && ((tkver_major && tkver_major != tkconf['TK_MAJOR_VERSION']) || (tkver_minor && tkver_minor != tkconf['TK_MINOR_VERSION']))
  701. print("\n") if progress_flag
  702. puts "Ignore \"#{tkpath}\" (unmatch with configured version)."
  703. progress_flag = false
  704. next
  705. end
  706. if TkLib_Config['unsupported_versions'].find{|ver| ver == "#{tkconf['TK_MAJOR_VERSION']}.#{tkconf['TK_MINOR_VERSION']}"}
  707. print("\n") if progress_flag
  708. puts "Ignore \"#{tkpath}\" (unsupported version of Tcl/Tk)."
  709. progress_flag = false
  710. next
  711. end
  712. end
  713. # nativethread check
  714. if !TkLib_Config["ruby_with_thread"]
  715. if tclconf
  716. if tclconf['TCL_THREADS'] == '1'
  717. puts "\nWARNING: found #{tclpath.inspect}, but it WITH nativethread-support under ruby WITHOUT nativethread-support. So, ignore it."
  718. TkLib_Config["tcl-NG-path"] << File.dirname(tclpath)
  719. next
  720. end
  721. else
  722. puts "\nWARNING: When not refer tclConfig.sh, cannot check native-thread support on Tcl/Tk libraries. Ruby, which is used now, does NOT support native-thread. So, if Tcl/Tk libraries support native-thread, it will NOT work properly."
  723. end
  724. end
  725. # find tclConfig.sh & tkConfig.sh
  726. conf = [tclconf, tkconf] unless conf
  727. # check Tcl library
  728. if is_macosx? && TkLib_Config["tcltk-framework"]
  729. # if use framework, not check (believe it is installed properly)
  730. tcllib_ok = tklib_ok = true
  731. else
  732. tcllib_ok, tklib_ok =
  733. libcheck_for_tclConfig((tclpath)? File.dirname(tclpath): nil,
  734. (tkpath)? File.dirname(tkpath): nil,
  735. tclconf, tkconf)
  736. end
  737. unless tcllib_ok && tklib_ok
  738. unless tcllib_ok
  739. puts "\nWARNING: found #{tclpath.inspect}, but cannot find valid Tcl library for the tclConfig.sh. So, ignore it."
  740. TkLib_Config["tcl-NG-path"] << File.dirname(tclpath)
  741. end
  742. unless tklib_ok
  743. puts "\nWARNING: found #{tkpath.inspect}, but cannot find valid Tk library for the tkConfig.sh. So, ignore it."
  744. TkLib_Config["tk-NG-path"] << File.dirname(tkpath)
  745. end
  746. next
  747. end
  748. #return [tclpath, tkpath]
  749. # print(" #{[tclpath, tkpath].inspect}");
  750. TkLib_Config["tclConfig_paths"] << [tclpath, tkpath]
  751. }
  752. # print("\n");
  753. }
  754. if is_macosx? && TkLib_Config["tcltk-stubs"]
  755. CONFIG['LDSHARED'] << " -Xlinker -bind_at_load"
  756. if config_string('LDSHAREDXX')
  757. config_string('LDSHAREDXX') << " -Xlinker -bind_at_load"
  758. end
  759. end
  760. if TkLib_Config["tclConfig_paths"].empty?
  761. [nil, nil]
  762. else
  763. # find tclConfig.sh and tkConfig.sh
  764. TkLib_Config["tclConfig_info"], TkLib_Config["tkConfig_info"] = conf
  765. TkLib_Config["tclConfig_paths"][0]
  766. end
  767. end
  768. def get_tclConfig(tclConfig_file, tkConfig_file, tclConfig_dir, tkConfig_dir)
  769. use_tclConfig = tclConfig_file != false && tclConfig_dir != false
  770. use_tkConfig = tkConfig_file != false && tkConfig_dir != false
  771. unless use_tclConfig || use_tkConfig
  772. puts("Don't use [tclConfig.sh, tkConfig.sh]")
  773. return [nil, nil]
  774. end
  775. tclConfig_file = nil unless tclConfig_file.kind_of? String
  776. tkConfig_file = nil unless tkConfig_file.kind_of? String
  777. tclConfig_dir = nil unless tclConfig_dir.kind_of? String
  778. tkConfig_dir = nil unless tkConfig_dir.kind_of? String
  779. if use_tclConfig && !tclConfig_dir
  780. if tclConfig_file
  781. tclConfig_dir = File.dirname(tclConfig_file)
  782. elsif tkConfig_dir
  783. tclConfig_dir = tkConfig_dir
  784. end
  785. end
  786. if use_tkConfig && !tkConfig_dir
  787. if tkConfig_file
  788. tkConfig_dir = File.dirname(tkConfig_file)
  789. elsif tclConfig_dir
  790. tkConfig_dir = tclConfig_dir
  791. end
  792. end
  793. tkConfig_dir ||= tclConfig_dir
  794. if use_tclConfig
  795. TkLib_Config["tclConfig-file"] = tclConfig_file
  796. TkLib_Config["tclConfig-dir"] = tclConfig_dir
  797. else
  798. tclConfig_file = false
  799. tclConfig_dir = false
  800. end
  801. if use_tkConfig
  802. TkLib_Config["tkConfig-file"] = tkConfig_file
  803. TkLib_Config["tkConfig-dir"] = tkConfig_dir
  804. else
  805. tkConfig_file = false
  806. tkConfig_dir = false
  807. end
  808. print ("Don't use tclConfig.sh (specified by configure option).\n") unless use_tclConfig
  809. print ("Don't use tkConfig.sh (specified by configure option).\n") unless use_tkConfig
  810. print("Search ")
  811. print("tclConfig.sh", (tclConfig_dir)? " (in #{tclConfig_dir})": "") if use_tclConfig
  812. print((use_tclConfig)? " and ": "", "tkConfig.sh", (tkConfig_dir)? " (in #{tkConfig_dir})": "") if use_tkConfig
  813. print(".")
  814. if tclConfig_dir || tkConfig_dir || !use_tclConfig || !use_tkConfig
  815. tclConfig, tkConfig =
  816. search_tclConfig([ ((tclConfig_file)? tclConfig_file: tclConfig_dir),
  817. ((tkConfig_file)? tkConfig_file: tkConfig_dir) ])
  818. else
  819. tclConfig, tkConfig = search_tclConfig()
  820. end
  821. print("\n")
  822. # TclConfig_Info = TkLib_Config["tclConfig_info"]
  823. # TkConfig_Info = TkLib_Config["tkConfig_info"]
  824. if tclConfig || tkConfig
  825. dirs = TkLib_Config["tclConfig_paths"].map{|tclpath, tkpath|
  826. [ (tclpath)? File.dirname(tclpath): nil,
  827. (tkpath)? File.dirname(tkpath): nil ]
  828. }
  829. dirs |= dirs
  830. puts("Valid [tclConfig.sh, tkConfig.sh] are found in #{dirs.inspect}")
  831. puts("Use [tclConfig.sh, tkConfig.sh] == #{[tclConfig, tkConfig].inspect}")
  832. $LIBPATH ||= []
  833. $LIBPATH |= [File.dirname(tclConfig)] if tclConfig
  834. $LIBPATH |= [File.dirname(tkConfig)] if tkConfig
  835. #TkLib_Config["tclConfig_paths"].each{|tclcfg, tkcfg|
  836. # $LIBPATH |= [File.dirname(tclcfg)] | [File.dirname(tkcfg)]
  837. #}
  838. else
  839. puts("Fail to find [tclConfig.sh, tkConfig.sh]")
  840. end
  841. [tclConfig, tkConfig]
  842. end
  843. def check_tcl_NG_path(path_list)
  844. path_list.find_all{|path| not TkLib_Config["tcl-NG-path"].include?(path) }
  845. end
  846. def check_tk_NG_path(path_list)
  847. path_list.find_all{|path| not TkLib_Config["tk-NG-path"].include?(path) }
  848. end
  849. def check_NG_path(path_list)
  850. path_list.find_all{|path|
  851. not (TkLib_Config["tcl-NG-path"].include?(path) &&
  852. TkLib_Config["tk-NG-path"].include?(path))
  853. }
  854. end
  855. def check_shlib_search_path(paths)
  856. if !paths || paths.empty?
  857. path_list = []
  858. #if TkLib_Config["ActiveTcl"]
  859. # path_list.concat Dir.glob(TkLib_Config["ActiveTcl"], File::FNM_CASEFOLD).sort.reverse
  860. #end
  861. if TkLib_Config["ActiveTcl"].kind_of?(String) # glob path
  862. path_list.concat Dir.glob(TkLib_Config["ActiveTcl"], File::FNM_CASEFOLD).sort.reverse
  863. end
  864. vers = get_shlib_versions
  865. path_head, path_dirs = get_shlib_path_head
  866. path_list.concat vers.map{|ver|
  867. path_head.map{|head|
  868. if ver.empty?
  869. head + "/lib"
  870. else
  871. dirs = []
  872. if Dir.glob(head, File::FNM_CASEFOLD).find{|dir| dir == head}
  873. dirs << head + "/lib"
  874. end
  875. if !Dir.glob(head + "-*", File::FNM_CASEFOLD).empty?
  876. dirs << head + "-#{ver}/lib" if !Dir.glob(head + "-[89].*", File::FNM_CASEFOLD).empty?
  877. dirs << head + "-#{ver.delete('.')}/lib" if !Dir.glob(head + "-[89][0-9]*", File::FNM_CASEFOLD).empty?
  878. end
  879. if !Dir.glob(head + "[_-]*", File::FNM_CASEFOLD).empty?
  880. dirs << head + "_#{ver}/lib" if !Dir.glob(head + "_[89].*", File::FNM_CASEFOLD).empty?
  881. dirs << head + "-#{ver}/lib" if !Dir.glob(head + "-[89].*", File::FNM_CASEFOLD).empty?
  882. dirs << head + "_#{ver.delete('.')}/lib" if !Dir.glob(head + "_[89][0-9]*", File::FNM_CASEFOLD).empty?
  883. dirs << head + "-#{ver.delete('.')}/lib" if !Dir.glob(head + "-[89][0-9]*", File::FNM_CASEFOLD).empty?
  884. end
  885. dirs
  886. end
  887. }
  888. }.flatten!
  889. path_list.concat path_dirs
  890. else
  891. # paths is a string with PATH environment style
  892. path_list = paths.split((is_win32?)? ';': ':')
  893. end
  894. path_list = check_NG_path(path_list)
  895. path_list.map!{|path| path.strip}
  896. if !CROSS_COMPILING and (is_win32? || is_macosx?)
  897. # exist-dir only
  898. path_list.delete_if{|path| Dir.glob(File.join(path, "*.{a,so,dll,lib}")).empty?}
  899. end
  900. # keep paths for searching dynamic libs
  901. #$LIBPATH |= path_list
  902. path_list.uniq
  903. end
  904. def search_vers_on_path(vers, path, *heads)
  905. exts = get_ext_list.join(',')
  906. files = Dir.glob(File.join(path, "*{#{heads.join(',')}}*.{#{exts}}"), File::FNM_CASEFOLD)
  907. vers.find_all{|ver| files.find{|f| f =~ /(#{ver}|#{ver.delete('.')})/} }
  908. end
  909. def find_tcl(tcllib, stubs, version, *opt_paths)
  910. if TclConfig_Info['MKMF_PARAMS']
  911. # already checked existence of tcl library based on tclConfig.sh
  912. ($INCFLAGS ||= "") << " " << TclConfig_Info['MKMF_PARAMS']['INCFLAGS']
  913. $LIBPATH ||= []; $LIBPATH |= TclConfig_Info['MKMF_PARAMS']['LIBPATH']
  914. ($libs ||= "") << " " << TclConfig_Info['MKMF_PARAMS']['libs']
  915. return [true, nil, nil, nil]
  916. end
  917. # else, no available tclConfig.sh on the system
  918. print "Search Tcl library"
  919. if stubs
  920. func = "Tcl_InitStubs"
  921. lib = "tclstub"
  922. else
  923. func = "Tcl_FindExecutable"
  924. lib = "tcl"
  925. end
  926. if version && ! version.empty?
  927. versions = [version]
  928. else
  929. versions = TkLib_Config['search_versions']
  930. end
  931. default_paths = []
  932. default_paths.concat [
  933. RbConfig::CONFIG['libdir'],
  934. File.join(RbConfig::CONFIG['exec_prefix'], 'lib'),
  935. File.join(RbConfig::CONFIG['prefix'], 'lib'),
  936. "/usr/local/lib", "/usr/pkg/lib", "/usr/contrib/lib", "/usr/lib"
  937. ].find_all{|dir| File.directory?(dir)} unless CROSS_COMPILING
  938. if TkLib_Config["ActiveTcl"].kind_of?(String) # glob path
  939. default_paths.concat Dir.glob(TkLib_Config["ActiveTcl"]).sort.reverse.map{|d| d << "/lib"}
  940. end
  941. if !CROSS_COMPILING and is_win32?
  942. default_paths.concat [
  943. "c:/Tcl/lib","c:/Program Files/Tcl/lib","c:/Program Files (x86)/Tcl/lib",
  944. "/Tcl/lib","/Program Files/Tcl/lib","/Program Files (x86)/Tcl/lib"
  945. ].find_all{|dir| File.directory?(dir)}.map{|dir| File.expand_path(dir)}
  946. # for MinGW
  947. ["/usr/local/lib64", "/usr/lib64", "/usr/local/lib", "/usr/lib"].each{|dir|
  948. default_paths << File.expand_path(dir) if File.directory? dir
  949. }
  950. default_paths |= ENV['LIBRARY_PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['LIBRARY_PATH']
  951. default_paths |= ENV['PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['PATH']
  952. end
  953. default_paths |= TkLib_Config["checked_shlib_dirs"]
  954. unless TkLib_Config["space-on-tk-libpath"]
  955. default_paths.delete_if{|path| path =~ / /}
  956. end
  957. if (paths = opt_paths.compact).empty?
  958. paths = check_tcl_NG_path(default_paths)
  959. end
  960. incflags = ($INCFLAGS ||= "").dup
  961. libpath = ($LIBPATH ||= []).dup
  962. libs_param = ($libs ||= "").dup
  963. tcllibs = nil
  964. exts = "(" + get_ext_list.join('|') + ")"
  965. paths.map{|path|
  966. lib_w_sufx = lib
  967. begin
  968. $LIBPATH |= [path]
  969. inc = [File.join(File.dirname(path),"include"), File.dirname(path)]
  970. inc.each{|f| $INCFLAGS << " -I" << f }
  971. if tcllib
  972. print(".")
  973. if have_library(tcllib, func, ["tcl.h"])
  974. return [true, path, tcllib, nil, *inc]
  975. end
  976. else
  977. sufx_list = ['', 't', 'g', 's', 'x']
  978. search_vers_on_path(versions, path, lib, 'tcl').find{|ver|
  979. dir_enum = Dir.foreach(path)
  980. no_dot_ver = ver.delete('.')
  981. libnames = ["#{lib}#{ver}", "#{lib}#{no_dot_ver}"]
  982. libnames << "tcl#{ver}" << "tcl#{no_dot_ver}" if lib != "tcl"
  983. libnames.find{|libname|
  984. sufx_list.find{|sufx|
  985. print(".")
  986. dir_enum.map{|fname|
  987. if fname =~ /^.*(#{libname}.*#{sufx})\.(#{exts}).*$/
  988. [fname, $1, $2]
  989. end
  990. }.compact.find{|fname, lib_w_sufx, ext|
  991. ext.downcase!
  992. if (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) ||
  993. ext == "a"
  994. # static link
  995. tcllibs = libs_param + " -DSTATIC_BUILD " + fname.quote
  996. else
  997. tcllibs = append_library($libs, lib_w_sufx)
  998. tcllibs = "#{libpathflag([path])} #{tcllibs}"
  999. end
  1000. if try_func(func, tcllibs, ["tcl.h"])
  1001. return [true, path, nil, tcllibs, *inc]
  1002. end
  1003. }
  1004. }
  1005. }
  1006. }
  1007. if (!version && (print(".");try_func(func, libs_param, ["tcl.h"])))
  1008. return [true, path, lib_w_sufx, nil, *inc]
  1009. end
  1010. end
  1011. ensure
  1012. $LIBPATH = libpath.dup
  1013. $libs = libs_param.dup
  1014. $INCFLAGS = incflags.dup
  1015. end
  1016. }
  1017. print("\n") # progress
  1018. [false, nil, nil, nil]
  1019. end
  1020. def parse_TK_LIBS(tklibs)
  1021. sfx = "lib|shlib|dll|so"
  1022. re = /(("|')[^"']+\.(#{sfx})\2|[^"' ]+\.(#{sfx})|-l("|')[^"']+\5|-l[^" ]+)/#'
  1023. tklibs.scan(re).map{|lib,|
  1024. if lib =~ /^("|')([^"]+)\.(#{sfx})\1/
  1025. "\"-l#{$2}\""
  1026. elsif lib =~ /([^" ]+)\.(#{sfx})/
  1027. "-l#{$1}"
  1028. else
  1029. lib
  1030. end
  1031. }.join(' ')
  1032. end
  1033. def find_tk(tklib, stubs, version, *opt_paths)
  1034. if TkConfig_Info['MKMF_PARAMS']
  1035. # already checked existence of tcl library based on tkConfig.sh
  1036. ($INCFLAGS ||= "") << " " << TkConfig_Info['MKMF_PARAMS']['INCFLAGS']
  1037. $LIBPATH ||= []; $LIBPATH |= TkConfig_Info['MKMF_PARAMS']['LIBPATH']
  1038. ($libs ||= "") << " " << TkConfig_Info['MKMF_PARAMS']['libs']
  1039. return [true, nil, nil, nil]
  1040. end
  1041. # else, no available tkConfig.sh on the system
  1042. print "Search Tk library"
  1043. if stubs
  1044. func = "Tk_InitStubs"
  1045. lib = "tkstub"
  1046. else
  1047. func = "Tk_Init"
  1048. lib = "tk"
  1049. end
  1050. if version && ! version.empty?
  1051. versions = [version]
  1052. else
  1053. versions = TkLib_Config['search_versions']
  1054. end
  1055. default_paths = []
  1056. default_paths.concat [
  1057. RbConfig::CONFIG['libdir'],
  1058. File.join(RbConfig::CONFIG['exec_prefix'], 'lib'),
  1059. File.join(RbConfig::CONFIG['prefix'], 'lib'),
  1060. "/usr/local/lib", "/usr/pkg/lib", "/usr/contrib/lib", "/usr/lib"
  1061. ].find_all{|dir| File.directory?(dir)} unless CROSS_COMPILING
  1062. if !CROSS_COMPILING and is_win32?
  1063. default_paths.concat [
  1064. "c:/Tcl/lib","c:/Program Files/Tcl/lib","c:/Program Files (x86)/Tcl/lib",
  1065. "/Tcl/lib","/Program Files/Tcl/lib","/Program Files (x86)/Tcl/lib"
  1066. ].find_all{|dir| File.directory?(dir)}
  1067. # for MinGW
  1068. ["/usr/local/lib64", "/usr/lib64", "/usr/local/lib", "/usr/lib"].each{|dir|
  1069. default_paths << File.expand_path(dir) if File.directory? dir
  1070. }
  1071. default_paths |= ENV['LIBRARY_PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['LIBRARY_PATH']
  1072. default_paths |= ENV['PATH'].split(';').find_all{|dir| File.directory? dir}.map{|dir| File.expand_path(dir)} if ENV['PATH']
  1073. end
  1074. default_paths |= TkLib_Config["checked_shlib_dirs"]
  1075. unless TkLib_Config["space-on-tk-libpath"]
  1076. default_paths.delete_if{|path| path =~ / /}
  1077. end
  1078. if (paths = opt_paths.compact).empty?
  1079. paths = check_tk_NG_path(default_paths)
  1080. end
  1081. incflags = ($INCFLAGS ||= "").dup
  1082. libpath = ($LIBPATH ||= []).dup
  1083. libs_param = ($libs ||= "").dup
  1084. tcllibs = nil
  1085. exts = "(" + get_ext_list.join('|') + ")"
  1086. paths.map{|path|
  1087. lib_w_sufx = lib
  1088. begin
  1089. $LIBPATH |= [path]
  1090. inc = [File.join(File.dirname(path),"include"), File.dirname(path)]
  1091. inc.each{|f| $INCFLAGS << " -I" << f }
  1092. if tklib
  1093. print(".")
  1094. if have_library(tklib, func, ["tcl.h", "tk.h"])
  1095. return [true, path, tklib, nil, *inc]
  1096. end
  1097. else
  1098. sufx_list = ['', 't', 'g', 's', 'x']
  1099. search_vers_on_path(versions, path, lib, 'tk').find{|ver|
  1100. dir_enum = Dir.foreach(path)
  1101. no_dot_ver = ver.delete('.')
  1102. libnames = ["#{lib}#{ver}", "#{lib}#{no_dot_ver}"]
  1103. libnames << "tk#{ver}" << "tk#{no_dot_ver}" if lib != "tk"
  1104. libnames.find{|libname|
  1105. sufx_list.find{|sufx|
  1106. print(".")
  1107. dir_enum.map{|fname|
  1108. if fname =~ /^.*(#{libname}.*#{sufx})\.(#{exts}).*$/
  1109. [fname, $1, $2]
  1110. end
  1111. }.compact.find{|fname, lib_w_sufx, ext|
  1112. if (ext != CONFIG['DLEXT'] && ext == CONFIG['LIBEXT']) ||
  1113. ext == "a"
  1114. # static link
  1115. tklibs = libs_param + " -DSTATIC_BUILD " + fname.quote
  1116. else
  1117. tklibs = append_library($libs, lib_w_sufx)
  1118. tklibs = "#{libpathflag([path])} #{tklibs}"
  1119. end
  1120. if try_func(func, tklibs, ["tcl.h", "tk.h"])
  1121. return [true, path, nil, tklibs, *inc]
  1122. end
  1123. }
  1124. }
  1125. }
  1126. }
  1127. if (!version && (print(".");try_func(func, libs_param, ["tcl.h", "tk.h"])))
  1128. return [true, path, lib_w_sufx, nil, *inc]
  1129. end
  1130. end
  1131. ensure
  1132. $LIBPATH = libpath
  1133. $libs = libs_param
  1134. $INCFLAGS = incflags.dup
  1135. end
  1136. }
  1137. print("\n") # progress
  1138. [false, nil, nil, nil]
  1139. end
  1140. def find_tcltk_library(tcllib, tklib, stubs, tclversion, tkversion,
  1141. tcl_opt_paths, tk_opt_paths)
  1142. st,path,lib,libs,*inc = find_tcl(tcllib, stubs, tclversion, *tcl_opt_paths)
  1143. if !st && TkLib_Config['enable-shared'] == nil
  1144. TkLib_Config['enable-shared'] = false
  1145. st,path,lib,libs,*inc = find_tcl(tcllib, stubs, tclversion, *tcl_opt_paths)
  1146. end
  1147. unless st
  1148. puts("Warning:: cannot find Tcl library. tcltklib will not be compiled (tcltklib is disabled on your Ruby. That is, Ruby/Tk will not work). Please check configure options.")
  1149. return false
  1150. else
  1151. ($LIBPATH ||= []; $LIBPATH |= [path]) if path
  1152. $libs = append_library($libs, lib) if lib
  1153. ($libs ||= "") << " " << libs if libs
  1154. $INCFLAGS ||= ""
  1155. inc.each{|f| $INCFLAGS << " -I" << f}
  1156. end
  1157. st,path,lib,libs,*inc = find_tk(tklib, stubs, tkversion, *tk_opt_paths)
  1158. if !st && TkLib_Config['enable-shared'] == nil
  1159. TkLib_Config['enable-shared'] = false
  1160. st,path,lib,libs,*inc = find_tk(tklib, stubs, tkversion, *tk_opt_paths)
  1161. end
  1162. unless st
  1163. puts("Warning:: cannot find Tk library. tcltklib will not be compiled (tcltklib is disabled on your Ruby. That is, Ruby/Tk will not work). Please check configure options.")
  1164. return false
  1165. else
  1166. ($LIBPATH ||= []; $LIBPATH |= [path]) if path
  1167. $libs = append_library($libs, lib) if lib && !lib.empty?
  1168. ($libs ||= "") << " " << libs if libs
  1169. $INCFLAGS ||= ""
  1170. inc.each{|f| $INCFLAGS << " -I" << f}
  1171. end
  1172. true
  1173. end
  1174. def find_tcltk_header(tclver, tkver)
  1175. base_dir = []
  1176. base_dir.concat [
  1177. File.join(RbConfig::CONFIG['prefix'], 'include'),
  1178. "/usr/local/include", "/usr/pkg/include", "/usr/contrib/include",
  1179. "/usr/include"
  1180. ].find_all{|dir| File.directory?(dir)}.map{|dir| File.expand_path(dir)}
  1181. if !CROSS_COMPILING && is_win32?
  1182. base_dir.concat [
  1183. "c:/Tcl/include","c:/Program Files/Tcl/include",
  1184. "c:/Program Files (x86)/Tcl/include",
  1185. "/Tcl/include","/Program Files/Tcl/include",
  1186. "/Program Files (x86)/Tcl/include"
  1187. ].find_all{|dir| File.directory?(dir)}.map{|dir| File.expand_path(dir)}
  1188. if ENV['CPATH']
  1189. base_dir |= ENV['CPATH'].split(';').find_all{|dir| File.directory?(dir)}.map{|dir| File.expand_path(dir)}
  1190. end
  1191. end
  1192. base_dir |= TkLib_Config["checked_shlib_dirs"]
  1193. unless TkLib_Config["space-on-tk-libpath"]
  1194. base_dir.delete_if{|path| path =~ / /}
  1195. end
  1196. # tcl.h
  1197. if TclConfig_Info['MKMF_PARAMS']
  1198. # already checked existence of tcl headers based on tclConfig.sh
  1199. have_tcl_h = true
  1200. else
  1201. print "\nSearch tcl.h"
  1202. if enable_config("tcl-h-ver-check", true) &&
  1203. tclver && tclver =~ /^\D*(\d)\.?(\d)/
  1204. major = $1; minor = $2
  1205. else
  1206. major = minor = nil
  1207. end
  1208. print(".") # progress
  1209. if major && minor
  1210. # version check on tcl.h
  1211. version_check = proc {|code|
  1212. code << ("#if TCL_MAJOR_VERSION != #{major} || TCL_MINOR_VERSION != #{minor}\n" \
  1213. "#error VERSION does not match\n" \
  1214. "#endif")
  1215. }
  1216. else
  1217. version_check = nil
  1218. end
  1219. have_tcl_h = have_header('tcl.h', &version_check)
  1220. unless have_tcl_h
  1221. if tclver && ! tclver.empty?
  1222. versions = [tclver]
  1223. else
  1224. versions = TkLib_Config['search_versions']
  1225. end
  1226. paths = base_dir.dup
  1227. (versions + [""]).each{|ver|
  1228. paths.concat(base_dir.map{|dir|
  1229. [
  1230. dir + '/tcl' + ver,
  1231. dir + '/tcl' + ver + '/include',
  1232. dir + '/tcl' + ver.delete('.'),
  1233. dir + '/tcl' + ver.delete('.') + '/include'
  1234. ]
  1235. }.flatten)
  1236. }
  1237. paths = paths.map{|dir|
  1238. (File.directory?(dir))? File.expand_path(dir): nil
  1239. }.compact.uniq
  1240. if major || minor
  1241. version_check = proc {|code|
  1242. code << "#if TCL_MAJOR_VERSION != #{major}\n#error MAJOR_VERSION does not match\n#endif\n" if major
  1243. code << "#if TCL_MINOR_VERSION != #{minor}\n#error MINOR_VERSION does not match\n#endif\n" if minor
  1244. code
  1245. }
  1246. else
  1247. version_check = nil
  1248. end
  1249. have_tcl_h = paths.find{|path|
  1250. print(".") # progress
  1251. inc_opt = " -I#{path.quote}"
  1252. if try_header("tcl", inc_opt, &version_check)
  1253. ($INCFLAGS ||= "") << inc_opt
  1254. true
  1255. else
  1256. false
  1257. end
  1258. }
  1259. end
  1260. end
  1261. # tk.h
  1262. if TkConfig_Info['MKMF_PARAMS']
  1263. # already checked existence of tk headers based on tkConfig.sh
  1264. have_tk_h = true
  1265. else
  1266. print "\nSearch tk.h"
  1267. if enable_config("tk-h-ver-check", true) &&
  1268. tkver && tkver =~ /^\D*(\d)\.?(\d)/
  1269. major = $1; minor = $2
  1270. else
  1271. major = minor = nil
  1272. end
  1273. print(".") # progress
  1274. if major && minor
  1275. # version check on tk.h
  1276. version_check = proc {|code|
  1277. code << ("#if TK_MAJOR_VERSION != #{major} || TK_MINOR_VERSION != #{minor}\n" \
  1278. "#error VERSION does not match\n" \
  1279. "#endif")
  1280. }
  1281. else
  1282. version_check = nil
  1283. end
  1284. have_tk_h = have_header('tk.h')
  1285. unless have_tk_h
  1286. if tkver && ! tkver.empty?
  1287. versions = [tkver]
  1288. else
  1289. versions = TkLib_Config['search_versions']
  1290. end
  1291. paths = base_dir.dup
  1292. (versions + [""]).each{|ver|
  1293. paths.concat(base_dir.map{|dir|
  1294. [
  1295. dir + '/tk' + ver,
  1296. dir + '/tk' + ver + '/include',
  1297. dir + '/tk' + ver.delete('.'),
  1298. dir + '/tk' + ver.delete('.') + '/include'
  1299. ]
  1300. }.flatten)
  1301. }
  1302. paths = paths.map{|dir|
  1303. (File.directory?(dir))? File.expand_path(dir): nil
  1304. }.compact.uniq
  1305. if major || minor
  1306. version_check = proc {|code|
  1307. code << "#if TK_MAJOR_VERSION != #{major}\n#error MAJOR_VERSION does not match\n#endif\n" if major
  1308. code << "#if TK_MINOR_VERSION != #{minor}\n#error MINOR_VERSION does not match\n#endif\n" if minor
  1309. code
  1310. }
  1311. else
  1312. version_check = nil
  1313. end
  1314. have_tk_h = paths.find{|path|
  1315. print(".") # progress
  1316. inc_opt = " -I#{path.quote}"
  1317. if try_header(%w'tcl.h tk.h', inc_opt, &version_check)
  1318. ($INCFLAGS ||= "") << inc_opt
  1319. true
  1320. else
  1321. false
  1322. end
  1323. }
  1324. end
  1325. end
  1326. puts "Can't find \"tcl.h\"." unless have_tcl_h
  1327. puts "Can't find \"tk.h\"." unless have_tk_h
  1328. have_tcl_h && have_tk_h
  1329. end
  1330. def setup_for_macosx_framework(tclver, tkver)
  1331. # use framework, but no tclConfig.sh
  1332. unless $LIBS && $LIBS.include?('-framework')
  1333. ($LIBS ||= "") << ' -framework Tk -framework Tcl'
  1334. end
  1335. if TkLib_Config["tcl-framework-header"]
  1336. TclConfig_Info['TCL_INCLUDE_SPEC'][0,0] =
  1337. " -I#{TkLib_Config["tcl-framework-header"].quote} "
  1338. else
  1339. tcl_base = File.join(TkLib_Config["tcltk-framework"], 'Tcl.framework')
  1340. if tclver
  1341. TclConfig_Info['TCL_INCLUDE_SPEC'] <<
  1342. " -I#{File.join(tcl_base, 'Versions', tclver, 'Headers').quote} "
  1343. end
  1344. TclConfig_Info['TCL_INCLUDE_SPEC'] << File.join(tcl_base, 'Headers')
  1345. unless tclver
  1346. dir = Dir.glob(File.join(tcl_base, 'Versions', '*', 'Headers'),
  1347. File::FNM_CASEFOLD).sort.reverse[0]
  1348. TclConfig_Info['TCL_INCLUDE_SPEC'] << "-I#{dir.quote} " if dir
  1349. end

Large files files are truncated, but you can click here to view the full file