diff --git a/ext/etc/depend b/ext/etc/depend index 0e456c05132..0a78e1d43ab 100644 --- a/ext/etc/depend +++ b/ext/etc/depend @@ -1,5 +1,3 @@ -# mkdepend: generated constdefs.h - constdefs.h : $(srcdir)/mkconstants.rb @echo "generating constant definitions" @$(RUBY) $(srcdir)/mkconstants.rb -o constdefs.h diff --git a/ext/rbconfig/sizeof/depend b/ext/rbconfig/sizeof/depend index 860395c48ea..ab00c6b262e 100644 --- a/ext/rbconfig/sizeof/depend +++ b/ext/rbconfig/sizeof/depend @@ -2,9 +2,6 @@ # mkdepend: scan limits.c => template/limits.c.tmpl # mkdepend: scan sizes.c => template/sizes.c.tmpl -# mkdepend: generated limits.c -# mkdepend: generated sizes.c - limits.c: $(top_srcdir)/tool/generic_erb.rb $(top_srcdir)/template/limits.c.tmpl $(Q) $(RUBY) $(top_srcdir)/tool/generic_erb.rb --output=$@ \ $(top_srcdir)/template/limits.c.tmpl \ diff --git a/ext/ripper/depend b/ext/ripper/depend index 2bafb1ff580..fd673294208 100644 --- a/ext/ripper/depend +++ b/ext/ripper/depend @@ -8,9 +8,6 @@ LRAMA = $(BASERUBY) $(top_srcdir)/tool/lrama/exe/lrama # mkdepend: define ripper.y => RIPPER # mkdepend: scan ripper.y => parse.y # mkdepend: scan ripper_init.c => ext/ripper/ripper_init.c.tmpl -# mkdepend: generated eventids1.h -# mkdepend: generated eventids2.h -# mkdepend: generated ripper_init.h # mkdepend: depends eventids2table.c => {$(VPATH)}eventids2table.c # mkdepend: depends ripper.c => {$(VPATH)}ripper.c # mkdepend: depends ripper_init.c => {$(VPATH)}ripper_init.c diff --git a/ext/socket/depend b/ext/socket/depend index 3877acabb00..c5b0d4952b6 100644 --- a/ext/socket/depend +++ b/ext/socket/depend @@ -1,6 +1,3 @@ -# mkdepend: generated constdefs.c -# mkdepend: generated constdefs.h - srcs: constdefs.h constdefs.c getnameinfo.o: getnameinfo.c $(arch_hdrdir)/ruby/config.h addrinfo.h sockport.h rubysocket.h diff --git a/tool/mkdepend.rb b/tool/mkdepend.rb index 427ad680abb..0a97c6e4c6b 100644 --- a/tool/mkdepend.rb +++ b/tool/mkdepend.rb @@ -15,9 +15,6 @@ # `*` and `**` patterns are expanded from matching SOURCE files and # substituted into NAME. Both sides must have the same pattern count. # -# # mkdepend: generated NAME -# Treat NAME as generated without reading it. -# # # mkdepend: depends NAME => DEPENDENCY... # Associate NAME with dependencies. They replace NAME when it is # included and are added when NAME is a source being scanned. Make @@ -40,7 +37,7 @@ TOP_SRCDIR = File.expand_path("..", __dir__) class Mkdepend Declarations = Struct.new( - :scan, :generated, :dependencies, :defines, :undefines, + :scan, :dependencies, :defines, :undefines, ) end @@ -48,13 +45,13 @@ class Mkdepend::Scanner attr_reader :unresolved def initialize(root:, include_dirs:, quote_dirs: [], macros: {}, - generated: [], aliases: {}, dependencies: {}, defined: [], + targets: [], aliases: {}, dependencies: {}, defined: [], undefined: []) @root = File.expand_path(root) @include_dirs = include_dirs.map {|dir| File.expand_path(dir, @root)} @quote_dirs = quote_dirs.map {|dir| File.expand_path(dir, @root)} @macros = macros - @generated = generated.to_set + @targets = targets.to_set @aliases = aliases @dependencies = dependencies @defined = defined.to_set @@ -148,7 +145,7 @@ class Mkdepend::Scanner when /\A([A-Za-z_]\w*)/ name = $1 unless @aliases.key?(name) || @dependencies.key?(name) || - @generated.include?(name) + @targets.include?(name) name = @macros[name] end quoted = true @@ -171,7 +168,7 @@ class Mkdepend::Scanner dependencies.add(name) elsif path = resolve(name, current, quoted) visit(path, dependencies, visited) - elsif @generated.include?(name) + elsif @targets.include?(name) dependencies.add(name) else @unresolved.add(name) @@ -202,6 +199,8 @@ class Mkdepend def initialize(root: TOP_SRCDIR) @root = File.expand_path(root) @dependency_declarations = {} + @dependency_targets = {} + @dependency_contents = {} end def expand_scan_declaration(name, source) @@ -227,12 +226,13 @@ class Mkdepend end end - def parse_dependency_declarations(path) - declarations = Declarations.new({}, {}, {}, {}, {}) - return declarations unless File.file?(path) + def parse_dependency_declarations(path, content = nil) + declarations = Declarations.new({}, {}, {}, {}) + content ||= File.read(path) if File.file?(path) + return declarations unless content lineno = 0 - File.foreach(path) do |line| + content.each_line do |line| lineno += 1 case line[/\A#\s*mkdepend:\s*\K.*/] when nil @@ -243,8 +243,6 @@ class Mkdepend raise "#{path}:#{lineno}: invalid mkdepend declaration: #{line.strip}" end declarations.scan.update(scan) - when /\Agenerated\s+(\S+)\s*\z/ - declarations.generated[$1] = nil when /\Adepends\s+(\S+)\s*=>\s*(.+?)\s*\z/ name, dependencies = $1, $2.split if declarations.dependencies.key?(name) @@ -262,18 +260,32 @@ class Mkdepend declarations end - def dependency_declarations(input = nil, source: nil) + def dependency_file_content(path, content = nil) + path = File.expand_path(path, @root) + if content + @dependency_contents[path] = content + elsif @dependency_contents.key?(path) + @dependency_contents[path] + elsif File.file?(path) + @dependency_contents[path] = File.read(path) + end + end + + def dependency_declarations(input = nil, source: nil, content: nil) input ||= dependency_input(source) input = relative_source(input || "depend") @dependency_declarations[input] ||= begin - global = parse_dependency_declarations(File.join(@root, "depend")) if input == "depend" - global + path = File.join(@root, input) + parse_dependency_declarations(path, dependency_file_content(path, content)) else - local = parse_dependency_declarations(File.join(@root, input)) + global = dependency_declarations("depend") + path = File.absolute_path?(input) ? input : File.join(@root, input) + local = parse_dependency_declarations( + path, dependency_file_content(path, content), + ) Declarations.new( global.scan.merge(local.scan), - global.generated.merge(local.generated), global.dependencies.merge(local.dependencies), global.defines.merge(local.defines), global.undefines.merge(local.undefines), @@ -307,6 +319,34 @@ class Mkdepend [key, map[key]] if key end + def dependency_targets(input, content = nil) + input = relative_source(input) + @dependency_targets[input] ||= begin + targets = [] + path = File.absolute_path?(input) ? input : File.join(@root, input) + content = dependency_file_content(path, content) + if content + content.each_line do |line| + if line.start_with?(MARK_START)..line.start_with?(MARK_END) + next + elsif target = line[/\A[^\s#][^:=]*?(?=\s*:(?!=))/] + targets.concat(target.split) + end + end + end + targets.uniq + end + end + + def dependency_target(name, input) + input = relative_source(input) + targets = dependency_targets(input) + candidates = [name] + dir = File.dirname(input) + candidates << name.delete_prefix(dir + "/") unless dir == "." + candidates.uniq.find {|candidate| targets.include?(candidate)} + end + def relative_source(path) expanded = File.expand_path(path) expanded = File.expand_path(path, @root) unless File.exist?(expanded) @@ -356,9 +396,8 @@ class Mkdepend file = relative_source(file) dep = if file.start_with?('$(', '{$(') file - elsif generated = declaration(declarations.generated, file, - declaration_input) - generated[0] + elsif target = dependency_target(file, declaration_input) + target elsif extension_dir extension_dependency(file, extension_dir) else @@ -403,11 +442,11 @@ class Mkdepend "{$(VPATH)}" end - def generated_source?(source, input = nil) + def dependency_source?(source, input = nil) declarations = dependency_declarations(input, source: source) declaration(declarations.scan, source, input) || - declaration(declarations.generated, source, input) || - declaration(declarations.dependencies, source, input) + declaration(declarations.dependencies, source, input) || + dependency_target(source, input || dependency_input(source)) end def dependency_scanner(src, declarations, input) @@ -428,7 +467,7 @@ class Mkdepend ], quote_dirs: [File.join(@root, "include/ruby")], macros: macros, - generated: declarations.generated.keys, + targets: dependency_targets(input), aliases: declarations.scan, dependencies: declarations.dependencies, defined: defined, @@ -508,7 +547,11 @@ class Mkdepend def dependency_files Dir.chdir(@root) do %w[depend enc/depend].concat(Dir.glob("ext/**/depend")).select do |file| - File.file?(file) && File.read(file).include?(MARK_START) + next false unless File.file?(file) + content = File.read(file) + next false unless content.include?(MARK_START) + dependency_file_content(file, content) + true end end end @@ -548,7 +591,7 @@ class Mkdepend missing = "missing/#{src}" return missing if File.file?(File.join(@root, missing)) - return src if generated_source?(src, input) + return src if dependency_source?(src, input) raise "source file not found: #{src} in #{input}" end @@ -620,7 +663,9 @@ class Mkdepend if input.end_with?(".c", ".y") out.puts makedepend(input) else - deps = File.read(input) + deps = dependency_file_content(input) || File.read(input) + dependency_declarations(input, content: deps) + dependency_targets(input, deps) match = MARK_SECTION.match(deps) next unless match raise "missing #{MARK_END} in #{input}" unless match.begin(1) diff --git a/tool/test/test_mkdepend.rb b/tool/test/test_mkdepend.rb index e9a3641e44b..1726fd89a72 100644 --- a/tool/test/test_mkdepend.rb +++ b/tool/test/test_mkdepend.rb @@ -49,7 +49,7 @@ class TestMkdepend < Test::Unit::TestCase root: dir, include_dirs: [dir], macros: {'GENERATED_HEADER' => 'generated.h'}, - generated: %w[parse.h], + targets: %w[parse.h], aliases: {'aliased.h' => 'aliased.h.erb'}, dependencies: {'generated.h' => %w[virtual.h]}, defined: %w[ENABLED], @@ -141,6 +141,14 @@ class TestMkdepend < Test::Unit::TestCase ) console = mkdepend.dependency_declarations('ext/io/console/depend') assert_equal(%w[$(VK_HEADER)], console.dependencies['win32_vk.inc']) + assert_include( + mkdepend.dependency_targets('ext/socket/depend'), + 'constdefs.h', + ) + assert_include( + mkdepend.dependency_targets('ext/ripper/depend'), + 'eventids1.h', + ) assert_path_not_exist(File.expand_path('../mkdepend', __dir__)) end @@ -201,10 +209,9 @@ class TestMkdepend < Test::Unit::TestCase input = File.join(dir, 'ext/example/depend') File.write(input, <<~DEPEND) # mkdepend: scan generated.c => template.c - # mkdepend: generated generated.h - # mkdepend: generated vpath.inc # mkdepend: depends vpath.inc => {$(VPATH)}vpath.inc # mkdepend: depends selected.inc => $(SELECTED_HEADER) + generated.h: template.c #{MARK_START} generated.o: generated.c #{MARK_END} @@ -229,6 +236,7 @@ class TestMkdepend < Test::Unit::TestCase path = File.join(dir, 'depend') [ '# mkdepend: depends ignored.h =>', + '# mkdepend: generated generated.h', '# mkdepend: generated generated.h => $(GENERATED_HEADER)', '# mkdepend: unknown header.h', '# mkdepend: scan generated/*.c => template.c.erb', @@ -263,6 +271,26 @@ class TestMkdepend < Test::Unit::TestCase end end + def test_dependency_metadata_uses_passed_content + Dir.mktmpdir('mkdepend-declarations') do |dir| + path = File.join(dir, 'missing-depend') + content = <<~DEPEND + # mkdepend: depends generated.h => $(GENERATED_HEADER) + generated.h: template.h + #{MARK_START} + generated.o: generated.c + #{MARK_END} + DEPEND + declarations = Mkdepend.new(root: dir). + parse_dependency_declarations(path, content) + assert_equal(%w[$(GENERATED_HEADER)], declarations.dependencies['generated.h']) + assert_equal( + %w[generated.h], + Mkdepend.new(root: dir).dependency_targets(path, content), + ) + end + end + def test_dependency_files files = mkdepend.dependency_files assert_include(files, 'depend') @@ -271,6 +299,24 @@ class TestMkdepend < Test::Unit::TestCase assert(files.all? {|file| File.read(File.join(TOP_SRCDIR, file)).include?(MARK_START)}) end + def test_dependency_files_caches_contents + Dir.mktmpdir('mkdepend-files') do |dir| + path = File.join(dir, 'depend') + ignored = File.join(dir, 'ext/example/depend') + FileUtils.mkdir_p(File.dirname(ignored)) + content = "#{MARK_START}\n#{MARK_END}\n" + File.write(path, content) + File.write(ignored, "manual: rule\n") + mkdepend = Mkdepend.new(root: dir) + + assert_equal(%w[depend], mkdepend.dependency_files) + File.unlink(path) + File.unlink(ignored) + assert_equal(content, mkdepend.dependency_file_content(path)) + assert_nil(mkdepend.dependency_file_content(ignored)) + end + end + def test_unicode_header assert_equal( ['$(UNICODE_HDR_DIR)/name2ctype.h'],