Class: Fortran::Dependencies

Inherits:
Object
  • Object
show all
Defined in:
lib/fortran.rb

Overview

Find Fortran dependencies

Constant Summary collapse

OPTIONS =
{ :search_paths => [ '.', '../lib' ],
:ignore_files => %r{ },
:ignore_modules => %r{ },
:ignore_symlinks => true }
USE_MODULE_REGEX =
/^\s*use\s+(\w+)/i
MODULE_DEF_REGEX =
/^\s*module\s+(\w+)/i
MODULE_INCLUDE_REGEX =
/\s*include\s+('|")(\w+\.(f|F)90)('|")/i
FILE_EXTENSION =
/\.f90$/i

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config = OPTIONS) ⇒ Dependencies

Returns a new instance of Dependencies.


26
27
28
29
30
31
32
33
34
# File 'lib/fortran.rb', line 26

def initialize( config=OPTIONS )
  @config = config
  OPTIONS.each{ |opt,default| @config[opt] = default unless @config.has_key? opt }
  @parsed, @file_dependencies, @source_files = [], {}, []
  @inlined_dependencies = {}
  @hash = build_hash_of_modules_in_files
  @included_files = build_hash_of_non_module_files
  self
end

Instance Attribute Details

#file_dependenciesObject (readonly)

Returns the value of attribute file_dependencies


24
25
26
# File 'lib/fortran.rb', line 24

def file_dependencies
  @file_dependencies
end

#inlined_dependenciesObject (readonly)

Returns the value of attribute inlined_dependencies


24
25
26
# File 'lib/fortran.rb', line 24

def inlined_dependencies
  @inlined_dependencies
end

#source_filesObject (readonly)

Returns the value of attribute source_files


24
25
26
# File 'lib/fortran.rb', line 24

def source_files
  @source_files
end

Instance Method Details

#build_dictionary_of_modules(array_of_file_names) ⇒ Object


54
55
56
57
58
59
60
# File 'lib/fortran.rb', line 54

def build_dictionary_of_modules( array_of_file_names )
  file_containing_module = {}
  array_of_file_names.each do |file|
    modules_defined_in( file ).each{ |mod| file_containing_module[mod]=file }
  end
  file_containing_module
end

#build_hash_of_modules_in_filesObject


88
89
90
# File 'lib/fortran.rb', line 88

def build_hash_of_modules_in_files
  build_dictionary_of_modules find_fortran_files
end

#build_hash_of_non_module_filesObject


70
71
72
73
74
75
76
77
78
79
# File 'lib/fortran.rb', line 70

def build_hash_of_non_module_files
  files = find_fortran_files
  included_files = {}
  files.each do |file|
    unless file_is_module?(file)
      included_files[File.basename(file)] = file
    end
  end
  included_files
end

#dependencies(start) ⇒ Object


129
130
131
132
133
134
135
136
137
138
139
# File 'lib/fortran.rb', line 129

def dependencies( start )
  modules = modules_used_in( start )
  @parsed = @parsed || [start]
  new_source_files = modules.collect{ |mod| @hash[mod] }.compact
  makefile_dependency_line(start) +
  new_source_files.collect do |file|
    next if @parsed.include?(file)
    @parsed.push file
    dependencies file
  end.join
end

#file_is_module?(file) ⇒ Boolean

Returns:

  • (Boolean)

81
82
83
84
85
86
# File 'lib/fortran.rb', line 81

def file_is_module?(file)
  IO.readlines( file ).map do |line|
    return true if line.match MODULE_DEF_REGEX
  end
  return false
end

#files_included_in(file) ⇒ Object


48
49
50
51
52
# File 'lib/fortran.rb', line 48

def files_included_in( file )
  IO.readlines( file ).map do |line|
    $2 if line.match MODULE_INCLUDE_REGEX
  end.uniq.compact
end

#find_fortran_filesObject


62
63
64
65
66
67
68
# File 'lib/fortran.rb', line 62

def find_fortran_files
  source = @config[:search_paths].map{ |path| Dir[path+"/*.[fF]90"] }
  source.flatten!.uniq!
  source.delete_if{ |file| File.lstat(file).symlink? } if @config[:ignore_symlinks]
  source.delete_if{ |file| file.match @config[:ignore_files] }
  source.map!{ |file| file.sub(/^\.\//,'') }# strip leading ./
end

#included_files_in_module(file) ⇒ Object


98
99
100
101
102
# File 'lib/fortran.rb', line 98

def included_files_in_module( file )
  files_included_in( file ).map do |included_file|
    @included_files[included_file]
  end.flatten.uniq.compact
end

#makefile_dependency_line(source) ⇒ Object


104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/fortran.rb', line 104

def makefile_dependency_line( source )
  real_source = source.sub(/PHYSICS_DUMMY/,'PHYSICS_MODULES')# FIXME: What's this?!
  source_no_path = File.basename source
  @source_files.push source_no_path.gsub(%r|^.*/|,'')
  output = ''
  if (File.expand_path(source) != File.expand_path(source_no_path))
    output += source_no_path+ ": " + real_source + "\n"
    output += "\tln -sf "+real_source+" .\n"
  end
  output += source.gsub(FILE_EXTENSION, ".o").gsub(%r|^.*/|,'' ) +
            ": " + source.gsub(%r|^.*/|,"" ) 
  modules_used_in( source ).each do |use|
    unless @hash[use]
      unless use.match @config[:ignore_modules]
        $stderr.puts 'Warning: unable to locate module #{use} used in #{source}.'
        $stderr.puts '         set :search_paths or :ignore_module_regex options.'
      end
      next
    end
    output = output + " \\\n " +
             @hash[use].gsub(FILE_EXTENSION, ".o").gsub(%r|^.*/|,'' )
  end
  output+"\n"
end

#modules_defined_in(file) ⇒ Object


42
43
44
45
46
# File 'lib/fortran.rb', line 42

def modules_defined_in( file )
  IO.readlines( file ).map do |line| 
    $1.downcase if line.match MODULE_DEF_REGEX
  end.uniq.compact
end

#modules_in_included_files(file) ⇒ Object


92
93
94
95
96
# File 'lib/fortran.rb', line 92

def modules_in_included_files( file )
  files_included_in( file ).map do |included_file|
    modules_used_in(@included_files[included_file])
  end.flatten.uniq.compact
end

#modules_used_in(file) ⇒ Object


36
37
38
39
40
# File 'lib/fortran.rb', line 36

def modules_used_in( file )
  IO.readlines( file ).map do |line|
    $1.downcase if line.match USE_MODULE_REGEX
  end.uniq.compact
end

#required_source_files(head_f90) ⇒ Object


157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/fortran.rb', line 157

def required_source_files( head_f90 )
  @parsed.clear
  source_file_dependencies( head_f90 )
  sources = []
  until @file_dependencies.empty? do
    no_dependents_pair = @file_dependencies.detect{ |h,d| d == [] }
    no_dependents = no_dependents_pair.first
    sources.push no_dependents
    @file_dependencies.delete(no_dependents){ |el| "#{el} not found" }
    @file_dependencies.each_value{ |deps| deps.delete(no_dependents) }
  end
  sources
end

#source_file_dependencies(head_f90) ⇒ Object


141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/fortran.rb', line 141

def source_file_dependencies( head_f90 )
  modules_head_uses = modules_used_in( head_f90 )
  modules_head_uses += modules_in_included_files( head_f90 )
  required_f90s = modules_head_uses.map{ |mod| @hash[mod] }.compact
  required_f90s.delete_if{ |f| f == head_f90 }
  required_inlined = included_files_in_module( head_f90 )
  required_inlined.delete_if{ |f| f == head_f90 }
  @file_dependencies[head_f90] = required_f90s
  @inlined_dependencies[head_f90] = required_inlined
  required_f90s.each do |required_f90|
    next if @parsed.include?(required_f90)
    source_file_dependencies( required_f90 )
  end
  @parsed.push head_f90
end