Class: Compiler

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

Overview

Processes source code files to produce intermediate object files.

Direct Known Subclasses

CCompiler

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(language, extension) ⇒ Compiler

Returns a new instance of Compiler.



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/makeconf/compiler.rb', line 10

def initialize(language, extension)
  @language = language
  @extension = extension
  @ld = Linker.new()
  windows_init if Platform.is_windows?
  @flags = []
  @sources = []     # List of input files
  @output = nil
  @sysroot = nil
  @quiet = false          # If true, output will be suppressed

  # TODO:
  # If true, all source files will be passed to the compiler at one time.
  # This will also combine the link and compilation phases.
  # See: the -combine option in GCC
  #@combine = false

end

Instance Attribute Details

#ldObject (readonly)

Returns the value of attribute ld.



8
9
10
# File 'lib/makeconf/compiler.rb', line 8

def ld
  @ld
end

#outputObject

Returns the value of attribute output.



7
8
9
# File 'lib/makeconf/compiler.rb', line 7

def output
  @output
end

#sysrootObject

Returns the value of attribute sysroot.



7
8
9
# File 'lib/makeconf/compiler.rb', line 7

def sysroot
  @sysroot
end

Instance Method Details

#cflagsObject



36
37
38
# File 'lib/makeconf/compiler.rb', line 36

def cflags
  @flags
end

#check_header(path) ⇒ Object

Check if a header is available



183
184
185
# File 'lib/makeconf/compiler.rb', line 183

def check_header(path)
  test_compile("#include <" + path + ">")
end

#cloneObject



40
41
42
# File 'lib/makeconf/compiler.rb', line 40

def clone
  Marshal.load(Marshal.dump(self))
end

#commandObject

Return the complete command line to compile an object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/makeconf/compiler.rb', line 71

def command
  log.debug self.pretty_inspect

  throw 'Invalid linker' unless @ld.is_a?(Linker)
  throw 'One or more source files are required' unless @sources.length > 0
#      cflags = default_flags
#      cflags.concat @flags
#    end
#    throw cflags

#    topdir = h[:topdir] || ''
#    ld = @ld.clone
#    ldadd = h[:ldadd]
#    ld.flags = h[:ldflags]
#    ld.output = Platform.pathspec(h[:output])
#    ld.rpath = h[:rpath] if h[:rpath].length > 0

#    inputs = h[:sources]
#    inputs = [ inputs ] if inputs.is_a? String
#    inputs = inputs.map { |x| Platform.pathspec(topdir + x) }
#    throw 'One or more sources are required' unless inputs.count

#TODO:if @combine
# return [ @path, cflags, '-combine', ldflags, inputs, ldadd ].flatten.join(' ')
#
  
  cmd = [ @path, '-DHAVE_CONFIG_H', flags, '-c', @sources ].flatten.join(' ')

  cmd += Platform.dev_null if @quiet

  log.debug "Compiler command: #{cmd}"

  cmd
end

#compileObject

Run the compilation command



193
194
195
196
197
198
199
200
# File 'lib/makeconf/compiler.rb', line 193

def compile
  cmd = self.command
#puts ' + ' + cmd
  log.debug "Invoking the compiler"
  rc = Platform.execute cmd
  log.debug "Compilation complete; rc=#{rc.to_s}"
  rc
end

#default_flagsObject

Try to determine a usable default set of compiler flags



244
245
246
247
248
249
250
251
252
253
254
# File 'lib/makeconf/compiler.rb', line 244

def default_flags
  cflags = []

  # GCC on Solaris 10 produces 32-bit code by default, so add -m64
  # when running in 64-bit mode.
  if Platform.is_solaris? and Platform.word_size == 64
     cflags.push '-m64'
  end

  cflags
end

#flagsObject



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/makeconf/compiler.rb', line 106

def flags
  tok = @flags

 # KLUDGE: remove things that CL.EXE doesn't understand
#    if @path.match(/cl.exe$/i)
#      cflags += ' '
#      cflags.gsub!(/ -Wall /, ' ') #  /Wall generates too much noise
#      cflags.gsub!(/ -Werror /, ' ')  # Could use /WX here
#      cflags.gsub!(/ -W /, ' ')
#      cflags.gsub!(/ -Wno-.*? /, ' ')
#      cflags.gsub!(/ -Wextra /, ' ')
#      cflags.gsub!(/ -fpic /, ' ')
#      cflags.gsub!(/ -std=.*? /, ' ')
#      cflags.gsub!(/ -pedantic /, ' ')
#    end

  # Set the output path
  unless @output.nil?
    outfile = Platform.pathspec(@output)
    if vendor == 'Microsoft'
      tok.push '"-IC:\Program Files\Microsoft Visual Studio 10.0\VC\include"' # XXX-HARDCODED
      tok.push '/Fo' + outfile
      tok.push '/MD'
    else
      tok.push '-o', outfile
    end
  end

  if @ld.shared_library 
    if Platform.is_windows?
      throw 'FIXME'
    else
      tok.push '-fpic' unless is_mingw?
    end
  end

  tok.push '--sysroot=' + @sysroot unless @sysroot.nil?

  tok.join(' ')
end

#flags=(s) ⇒ Object



147
148
149
150
# File 'lib/makeconf/compiler.rb', line 147

def flags=(s)
  @flags = s
  @flags = @flags.split(' ') if @flags.kind_of?(String)
end

#has_option(opt) ⇒ Object

Test if the compiler supports a command line option



170
171
172
173
174
175
176
177
178
179
180
# File 'lib/makeconf/compiler.rb', line 170

def has_option(opt)

  # Create a simple test file
  f = Tempfile.new(['test_has_option', @extension]);
  f.puts 'int main() { }'
  f.flush

#FIXME: /dev/null not portable
  cmd = [ @path, opt, '-o /dev/null', '-c', f.path ].join(' ') + Platform.dev_null
  Platform.execute cmd
end

Run the link command



203
204
205
206
207
208
209
210
211
# File 'lib/makeconf/compiler.rb', line 203

def link
  throw 'Invalid linker' unless @ld.is_a?(Linker)
  throw 'One or more source files are required' unless @sources.length > 0
  cmd = @ld.command
  log.debug "Invoking the linker: " + cmd
  rc = Platform.execute cmd
  log.debug "Linking complete; rc=#{rc.to_s}"
  rc
end

#makefileObject



58
59
60
61
62
63
# File 'lib/makeconf/compiler.rb', line 58

def makefile
  m = Makefile.new
  m.define_variable('CC', ':=', @path)
  m.define_variable('LD', ':=', @ld.path)
  return m
end

#object_files(sources) ⇒ Object

Return the intermediate object files for each source file



45
46
47
48
49
50
51
# File 'lib/makeconf/compiler.rb', line 45

def object_files(sources)
  res = []
  sources.sort.each do |s|
    res.push s.sub(/.c$/, Platform.object_extension)
  end
  res
end

#quiet=(b) ⇒ Object



53
54
55
56
# File 'lib/makeconf/compiler.rb', line 53

def quiet=(b)
  ld.quiet = b
  @quiet = b
end

#ruleObject

Return the command formatted as a Makefile rule



66
67
68
# File 'lib/makeconf/compiler.rb', line 66

def rule
  [ '$(CC)', '-DHAVE_CONFIG_H', flags, '$(CFLAGS)', '-c', @sources ].flatten.join(' ')
end

#shared_library=(b) ⇒ Object

Enable compiler and linker options to create a shared library



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/makeconf/compiler.rb', line 153

def shared_library=(b)
  case b
  when true
    if Platform.is_windows?
      # noop
    else
      @flags.push '-fpic'
      @ld.shared_library = true
    end
  when false
    # noop
  else
    throw 'Invalid value'
  end
end

#sources=(a) ⇒ Object



29
30
31
32
33
34
# File 'lib/makeconf/compiler.rb', line 29

def sources=(a)
  a = [ a ] if a.kind_of?(String)
  throw 'Array input required' unless a.kind_of?(Array)
  @sources = a
  @ld.objects = a.map { |x| x.sub(/\.c$/, '.o') } #FIXME: hardcoded to C
end

#test_compile(code, stage = :compile) ⇒ Object

Compile a test program



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/makeconf/compiler.rb', line 214

def test_compile(code, stage = :compile)
  log.debug "Testing compilation of:\n" + code

  # Write the code to a temporary source file
  f = Tempfile.new(['test_compile', @extension]);
  f.print code
  f.flush

  # Run the compiler
  cc = self.clone
  cc.sources = f.path
  cc.output = f.path.sub(/\.c$/, '.o')
  cc.quiet = true
  rc = cc.compile

  # (Optional) Run the linker
  if (rc == true and stage == :combined)
    cc.ld.quiet = true
    rc = cc.link
    File.unlink(cc.ld.output) if File.exist? cc.ld.output
  end

  # Delete the output file(s)
  File.unlink(cc.output) if File.exist? cc.output

  return rc
end

Compile and link a test program



188
189
190
# File 'lib/makeconf/compiler.rb', line 188

def test_link(code)
  test_compile(code, :combined)
end