class MakeMakefile::Depend
Generates dependency rules for Ruby and C extension sources.
An extension project can update the autogenerated section of its depend file while running extconf.rb:
ruby extconf.rb --update-depend
The depend file must contain these markers:
# AUTOGENERATED DEPENDENCIES START # AUTOGENERATED DEPENDENCIES END
MakeMakefile::Depend scans each source and the headers it includes without invoking a compiler. When updating an extension project, files outside the project tree, such as system and installed Ruby headers, are omitted. Use --depend-root=DIR when the project root cannot be detected from a .git directory.
Attributes
Source tree root used to resolve dependency paths.
Public Class Methods
Finds the nearest ancestor of path containing .git.
Returns path itself when no repository root can be found.
# File lib/mkmf/depend.rb, line 272 def find_root(path) path = File.expand_path(path) root = path loop do return path if File.exist?(File.join(path, ".git")) parent = File.dirname(path) break if parent == path path = parent end root end
Runs the command-line interface with argv.
Returns whether the requested update or check succeeded.
# File lib/mkmf/depend.rb, line 259 def main(argv = ARGV, err: $stderr) options, inputs = parse_options(argv) rescue OptionParser::ParseError => error err.puts "#{File.basename($0)}: #{error.message}" err.puts "Try '#{File.basename($0)} --help' for more information." false else execute(inputs, **options) end
Creates a dependency updater for root.
# File lib/mkmf/depend.rb, line 360 def initialize(root: DEFAULT_ROOT) @root = File.expand_path(root) @make_variables = {} @dependency_declarations = {} @dependency_targets = {} @dependency_contents = {} @source_cache = {} @stat_cache = {} end
Public Instance Methods
Processes dependency inputs according to the selected update mode.
make_variables supplies values for Make variables in declarations. thread_model is a shortcut for its THREAD_MODEL entry.
Returns false only when check mode finds an outdated dependency file.
# File lib/mkmf/depend.rb, line 1069 def run(inputs = ARGV, out: $stdout, err: $stderr, mode: :stdout, output: nil, make_variables: {}, nmake: false, sources: false, scope: nil, thread_model: nil, verbose: false) @source_cache.clear @stat_cache.clear case mode when :output raise ArgumentError, "output directory is missing" unless output when :stdout, :inplace, :check raise ArgumentError, "output requires output mode" if output else raise ArgumentError, "unknown update mode: #{mode.inspect}" end unless thread_model.nil? if thread_model.empty? raise ArgumentError, "thread model must not be empty" end make_variables = make_variables.merge("THREAD_MODEL" => thread_model) end select_make_variables(make_variables) if scope inputs = dependency_files(scope).map {|file| File.join(@root, file)} end output = File.expand_path(output) if output cache_signature = dependency_cache_signature( nmake: nmake, sources: sources, ) changed = false inputs.each do |input| if input.end_with?(".c", ".y") out.puts makedepend(relative_source(input)) else 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) destination = File.join(output, relative_source(input)) if output if destination && dependency_output_fresh?(destination, cache_signature) next end current_rules = match[0] accessed = Set.new expected = update_deps( current_rules, input, group: !nmake, verbose: verbose, accessed: accessed, ) expected = minimize_deps(expected, input) if sources updated = match.pre_match + expected + match.post_match if mode == :output updated = normalize_dependency_rules(updated) unless nmake replace_file(destination, updated) accessed.add(File.expand_path(input)) accessed.add(File.join(@root, "depend")) accessed.add(File.expand_path(__FILE__)) accessed.add(File.join(@root, "tool/mkdepend.rb")) write_dependency_cache(destination, cache_signature, accessed) elsif same_dependency_rules?(current_rules, expected) next elsif mode == :inplace replace_file(input, updated) changed = true elsif mode == :check report_outdated_dependencies(input, current_rules, expected, err: err) changed = true else out.puts updated changed = true end end end if mode == :check && changed options = " --sources" if sources err.puts "\nupdate with:" err.puts " ruby tool/mkdepend.rb --scope=all#{options} --inplace" end mode != :check || !changed end
Updates the marked dependency section in extension file input.
source_map maps object targets to source paths. make_variables supplies values of Make variables used by manual dependency rules. Returns true when the file changed and false when its dependencies were already current.
# File lib/mkmf/depend.rb, line 934 def update_extension(input, source_map, make_variables: {}, nmake: false, verbose: false) select_make_variables(make_variables) input = File.expand_path(input) deps = File.read(input) if File.file?(input) match = MARK_SECTION.match(deps) if deps unless match raise "#{input}: no autogenerated dependency section" end raise "missing #{MARK_END} in #{input}" unless match.begin(1) dependency_declarations(input, content: deps) dependency_targets(input, deps) generated = [] source_map.each do |target, source| source = relative_source(source) warn "dependencies for #{source}:" if verbose makedepend( source, generated, target: target, input: input, project: true ) end expected = compact_dependencies(generated.join, group: !nmake) updated = match.pre_match + expected + match.post_match return false if same_dependency_rules?(match[0], expected) replace_file(input, updated) true end