summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rwxr-xr-xtool/update-deps286
2 files changed, 172 insertions, 118 deletions
diff --git a/ChangeLog b/ChangeLog
index e43a7c538e..05c17371c3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Thu Nov 20 23:17:11 2014 Tanaka Akira <akr@fsij.org>
+
+ * tool/update-deps: Insert all dependencies found by compiler.
+
Thu Nov 20 15:51:01 2014 NARUSE, Yui <naruse@ruby-lang.org>
* ext/nkf/depend (nkf.o): add nkf.c as dependency.
diff --git a/tool/update-deps b/tool/update-deps
index f98707a674..3ab69dd1a9 100755
--- a/tool/update-deps
+++ b/tool/update-deps
@@ -25,6 +25,7 @@
require 'optparse'
require 'stringio'
require 'pathname'
+require 'open3'
require 'pp'
ENV['LC_ALL'] = 'C'
@@ -34,6 +35,9 @@ $opt_a = false
$opt_actual_fix = false
$i_not_found = false
+DEPENDENCIES_SECTION_START_MARK = "\# AUTOGENERATED DEPENDENCIES START\n"
+DEPENDENCIES_SECTION_END_MARK = "\# AUTOGENERATED DEPENDENCIES END\n"
+
def optionparser
op = OptionParser.new
op.banner = 'Usage: ruby tool/update-deps'
@@ -45,7 +49,11 @@ end
def read_make_deps(cwd)
dependencies = {}
- make_p = `make -p all miniruby ruby golf 2> /dev/null`
+ make_p, make_p_stderr, make_p_status = Open3.capture3("make -p all miniruby ruby golf")
+ if !make_p_status.success?
+ puts make_p_stderr
+ raise "make failed"
+ end
dirstack = [cwd]
curdir = nil
make_p.scan(%r{Entering\ directory\ ['`](.*)'|
@@ -108,7 +116,7 @@ end
# raise ArgumentError, "can not find #{filename} (hint: #{hint0})"
#end
-def read_single_actual_deps(path_i, cwd)
+def read_single_cc_deps(path_i, cwd)
files = {}
path_i.each_line.with_index {|line, lineindex|
next if /\A\# \d+ "(.*)"/ !~ line
@@ -130,7 +138,7 @@ def read_single_actual_deps(path_i, cwd)
dep = compiler_wd + dep
end
if !dep.file?
- warn "file not found: #{dep}"
+ warn "warning: file not found: #{dep}"
next
end
next if !dep.to_s.start_with?(cwd.to_s) # omit system headers.
@@ -139,18 +147,18 @@ def read_single_actual_deps(path_i, cwd)
deps
end
-def read_actual_deps(cwd)
+def read_cc_deps(cwd)
deps = {}
Pathname.glob('**/*.o').sort.each {|fn_o|
fn_i = fn_o.sub_ext('.i')
if !fn_i.exist?
- warn "not found: #{fn_i}"
+ warn "warning: not found: #{fn_i}"
$i_not_found = true
next
end
path_o = cwd + fn_o
path_i = cwd + fn_i
- deps[path_o] = read_single_actual_deps(path_i, cwd)
+ deps[path_o] = read_single_cc_deps(path_i, cwd)
}
deps
end
@@ -165,12 +173,12 @@ def concentrate(dependencies, cwd)
rel
}
if %r{\A\.\.(/|\z)} =~ target.to_s
- warn "out of tree target: #{target}"
+ warn "warning: out of tree target: #{target}"
next
end
sources = sources.reject {|s|
if %r{\A\.\.(/|\z)} =~ s.to_s
- warn "out of tree source: #{s}"
+ warn "warning: out of tree source: #{s}"
true
else
false
@@ -226,7 +234,7 @@ def in_makefile(target, source)
["enc/depend", target2, source2]
when %r{\Aext/}
unless File.exist?("#{File.dirname(target)}/extconf.rb")
- warn "not found: #{File.dirname(target)}/extconf.rb"
+ warn "warning: not found: #{File.dirname(target)}/extconf.rb"
end
target2 = File.basename(target)
case source
@@ -235,10 +243,10 @@ def in_makefile(target, source)
when %r{\A\.ext/include/[^/]+/ruby/} then source2 = "$(arch_hdrdir)/ruby/#{$'}"
when %r{\A#{Regexp.escape File.dirname(target)}/extconf\.h\z} then source2 = "$(RUBY_EXTCONF_H)"
when %r{\A#{Regexp.escape File.dirname(target)}/} then source2 = $'
- when 'id.h' then source2 = '{$(VPATH)}id.h'
- when 'parse.h' then source2 = '{$(VPATH)}parse.h'
- when 'lex.c' then source2 = '{$(VPATH)}lex.c'
- when 'probes.h' then source2 = '{$(VPATH)}probes.h'
+ when 'id.h' then source2 = '$(topdir)/id.h'
+ when 'parse.h' then source2 = '$(topdir)/parse.h'
+ when 'lex.c' then source2 = '$(topdir)/lex.c'
+ when 'probes.h' then source2 = '$(topdir)/probes.h'
else source2 = "$(top_srcdir)/#{source}"
end
["#{File.dirname(target)}/depend", target2, source2]
@@ -247,144 +255,186 @@ def in_makefile(target, source)
end
end
-def compare_deps(make_deps, actual_deps, out=$stdout)
- targets = sort_paths(actual_deps.keys)
- targets.each {|target|
- actual_sources = actual_deps[target]
- if !make_deps.has_key?(target)
- warn "no makefile dependency for #{target}"
- else
- make_sources = make_deps[target]
- sort_paths(actual_sources | make_sources).each {|source|
- makefile, target2, source2 = in_makefile(target, source)
- lines = begin
- File.readlines(makefile)
- rescue Errno::ENOENT
- []
- end
- #depline = "#{target2}: #{source2} \# #{target}: #{source}\n"
- depline = "#{target2}: #{source2}\n"
- if !make_sources.include?(source)
- out.puts "add #{makefile} : #{depline}"
- elsif !actual_sources.include?(source)
- if lines.include? depline
- out.puts "delL #{makefile} : #{depline}" # delL stands for del line
- else
- out.puts "delP #{makefile} : #{depline}" # delP stands for del prerequisite
- end
- else
- if $opt_a
- if lines.include? depline
- out.puts "okL #{makefile} : #{depline}" # okL stands for ok line
- else
- out.puts "okP #{makefile} : #{depline}" # okP stands for ok prerequisite
- end
- end
- end
- }
- end
+def show_deps(tag, deps)
+ targets = sort_paths(deps.keys)
+ targets.each {|t|
+ sources = sort_paths(deps[t])
+ sources.each {|s|
+ puts "#{tag} #{t}: #{s}"
+ }
}
end
-def main_show(out=$stdout)
+def detect_dependencies(out=$stdout)
cwd = Pathname.pwd
make_deps = read_make_deps(cwd)
#pp make_deps
make_deps = concentrate(make_deps, cwd)
#pp make_deps
- actual_deps = read_actual_deps(cwd)
- #pp actual_deps
- actual_deps = concentrate(actual_deps, cwd)
- #pp actual_deps
- compare_deps(make_deps, actual_deps, out)
+ cc_deps = read_cc_deps(cwd)
+ #pp cc_deps
+ cc_deps = concentrate(cc_deps, cwd)
+ #pp cc_deps
+ return make_deps, cc_deps
end
-def extract_deplines(problems)
- adds = {}
- dels = {}
- problems.each_line {|line|
- case line
- when /\Aadd (\S+) : (\S.*\n)\z/
- (adds[$1] ||= []) << $2
- when /\AdelL (\S+) : (\S.*\n)\z/
- (dels[$1] ||= []) << $2
- when /\AdelP (\S+) : (\S.*\n)\z/
- (dels[$1] ||= []) << $2
- when /\AokL (\S+) : (\S.*\n)\z/
- when /\AokP (\S+) : (\S.*\n)\z/
- (adds[$1] ||= []) << $2
- end
+def compare_deps(make_deps, cc_deps, out=$stdout)
+ targets = make_deps.keys | cc_deps.keys
+
+ makefiles = {}
+
+ make_lines_hash = {}
+ make_deps.each {|t, sources|
+ sources.each {|s|
+ makefile, t2, s2 = in_makefile(t, s)
+ makefiles[makefile] = true
+ make_lines_hash[makefile] ||= Hash.new(false)
+ make_lines_hash[makefile]["#{t2}: #{s2}"] = true
+ }
}
- return adds, dels
-end
-DEPENDENCIES_SECTION_START_MARK = "\# AUTOGENERATED DEPENDENCIES START\n"
-DEPENDENCIES_SECTION_END_MARK = "\# AUTOGENERATED DEPENDENCIES END\n"
+ cc_lines_hash = {}
+ cc_deps.each {|t, sources|
+ sources.each {|s|
+ makefile, t2, s2 = in_makefile(t, s)
+ makefiles[makefile] = true
+ cc_lines_hash[makefile] ||= Hash.new(false)
+ cc_lines_hash[makefile]["#{t2}: #{s2}"] = true
+ }
+ }
-def main_actual_fix(problems)
- adds, dels = extract_deplines(problems)
- (adds.keys | dels.keys).sort.each {|makefile|
+ makefiles.keys.sort.each {|makefile|
+ cc_lines = cc_lines_hash[makefile] || Hash.new(false)
+ make_lines = make_lines_hash[makefile] || Hash.new(false)
content = begin
File.read(makefile)
rescue Errno::ENOENT
''
end
- if /^#{Regexp.escape DEPENDENCIES_SECTION_START_MARK}((?:.*\n)*)#{Regexp.escape DEPENDENCIES_SECTION_END_MARK}/ =~ content
+ if /^#{Regexp.escape DEPENDENCIES_SECTION_START_MARK}
+ ((?:.*\n)*)
+ #{Regexp.escape DEPENDENCIES_SECTION_END_MARK}/x =~ content
pre_post_part = [$`, $']
- lines = $1.lines.to_a
+ current_lines = Hash.new(false)
+ $1.each_line {|line| current_lines[line.chomp] = true }
+ (cc_lines.keys | current_lines.keys | make_lines.keys).sort.each {|line|
+ status = [cc_lines[line], current_lines[line], make_lines[line]]
+ case status
+ when [true, true, true]
+ # no problem
+ when [true, true, false]
+ out.puts "warning #{makefile} : #{line} (make doesn't detect written dependency)"
+ when [true, false, true]
+ out.puts "add_auto #{makefile} : #{line} (harmless)" # This is automatically updatable.
+ when [true, false, false]
+ out.puts "add_auto #{makefile} : #{line} (harmful)" # This is automatically updatable.
+ when [false, true, true]
+ out.puts "del_cc #{makefile} : #{line}" # Not automatically updatable because build on other OS may need the dependency.
+ when [false, true, false]
+ out.puts "del_cc #{makefile} : #{line} (Curious. make doesn't detect this dependency.)" # Not automatically updatable because build on other OS may need the dependency.
+ when [false, false, true]
+ out.puts "del_make #{makefile} : #{line}" # Not automatically updatable because the dependency is written manually.
+ else
+ raise "unexpected status: #{status.inspect}"
+ end
+ }
else
- pre_post_part = nil
- lines = []
+ (cc_lines.keys | make_lines.keys).sort.each {|line|
+ status = [cc_lines[line], make_lines[line]]
+ case status
+ when [true, true]
+ # no problem
+ when [true, false]
+ out.puts "add_manual #{makefile} : #{line}" # Not automatically updatable because makefile has no section to update automatically.
+ when [false, true]
+ out.puts "del_manual #{makefile} : #{line}" # Not automatically updatable because makefile has no section to update automatically.
+ else
+ raise "unexpected status: #{status.inspect}"
+ end
+ }
end
+ }
+end
- lines_original = lines.dup
+def main_show(out=$stdout)
+ make_deps, cc_deps = detect_dependencies(out)
+ compare_deps(make_deps, cc_deps, out)
+end
- if dels[makefile]
- lines -= dels[makefile]
- end
- if adds[makefile]
- lines.concat(adds[makefile] - lines)
+def extract_deplines(problems)
+ adds = {}
+ others = {}
+ problems.each_line {|line|
+ case line
+ when /\Aadd_auto (\S+) : ((\S+): (\S+))/
+ (adds[$1] ||= []) << [line, "#{$2}\n"]
+ when /\A(?:del_cc|del_make|add_manual|del_manual|warning) (\S+) : /
+ (others[$1] ||= []) << line
+ else
+ raise "unexpected line: #{line.inspect}"
end
+ }
+ return adds, others
+end
- if lines == lines_original
- next
+def main_actual_fix(problems)
+ adds, others = extract_deplines(problems)
+ (adds.keys | others.keys).sort.each {|makefile|
+ content = begin
+ File.read(makefile)
+ rescue Errno::ENOENT
+ nil
end
- lines.sort!
-
- if pre_post_part
- new_content = [
- pre_post_part.first,
- DEPENDENCIES_SECTION_START_MARK,
- *lines,
- DEPENDENCIES_SECTION_END_MARK,
- pre_post_part.last
- ].join
- tmp_makefile = "#{makefile}.new#{$$}"
- File.write(tmp_makefile, new_content)
- File.rename tmp_makefile, makefile
- puts "modified: #{makefile}"
+ if content &&
+ /^#{Regexp.escape DEPENDENCIES_SECTION_START_MARK}
+ ((?:.*\n)*)
+ #{Regexp.escape DEPENDENCIES_SECTION_END_MARK}/x =~ content
+ pre_dep_post = [$`, $1, $']
else
+ pre_dep_post = nil
+ end
+
+ if pre_dep_post && adds[makefile]
+ pre_lines, dep_lines, post_lines = pre_dep_post
+ dep_lines = dep_lines.lines.to_a
+ add_lines = adds[makefile].map(&:last)
+ new_lines = (dep_lines | add_lines).sort.uniq
new_content = [
+ pre_lines,
DEPENDENCIES_SECTION_START_MARK,
- *lines,
+ *new_lines,
DEPENDENCIES_SECTION_END_MARK,
+ post_lines
].join
- if !File.exist?(makefile)
- if !lines.empty?
- File.open(makefile, 'w') {|f|
- f.print new_content
- }
- puts "created: #{makefile}"
- end
+ if content != new_content
+ puts "modified: #{makefile}"
+ tmp_makefile = "#{makefile}.new.#{$$}"
+ File.write(tmp_makefile, new_content)
+ File.rename tmp_makefile, makefile
+ (add_lines - lines).each {|line| puts " added #{line}" }
else
+ puts "not modified: #{makefile}"
+ end
+ if others[makefile]
+ others[makefile].each {|line| puts " #{line}" }
+ end
+ else
+ if pre_dep_post
+ puts "no addtional lines: #{makefile}"
+ elsif content
puts "no dependencies section: #{makefile}"
- (lines_original - lines).each {|line|
- puts " del: #{line}"
- }
- (lines - lines_original).each {|line|
- puts " add: #{line}"
- }
+ else
+ puts "no makefile: #{makefile}"
+ end
+ if adds[makefile]
+ puts " warning: dependencies section was exist at previous phase."
+ end
+ if adds[makefile]
+ adds[makefile].map(&:first).each {|line| puts " #{line}" }
+ end
+ if others[makefile]
+ others[makefile].each {|line| puts " #{line}" }
end
end
}
@@ -410,5 +460,5 @@ end
run
if $i_not_found
- warn "missing *.i files, see help in #$0 and ensure ccache is disabled"
+ warn "warning: missing *.i files, see help in #$0 and ensure ccache is disabled"
end