Class: RMagick::Extconf

Inherits:
Object
  • Object
show all
Defined in:
ext/RMagick/extconf.rb

Constant Summary collapse

RMAGICK_VERS =
::Magick::VERSION
MIN_RUBY_VERS =
::Magick::MIN_RUBY_VERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeExtconf

Returns a new instance of Extconf.



15
16
17
18
19
20
21
22
# File 'ext/RMagick/extconf.rb', line 15

def initialize
  @stdout = $stdout.dup

  setup_pkg_config_path
  configure_compile_options
  assert_can_compile!
  configure_headers
end

Instance Attribute Details

#headersObject (readonly)

Returns the value of attribute headers.



13
14
15
# File 'ext/RMagick/extconf.rb', line 13

def headers
  @headers
end

Instance Method Details

#assert_can_compile!Object



284
285
286
287
# File 'ext/RMagick/extconf.rb', line 284

def assert_can_compile!
  assert_minimum_ruby_version!
  assert_has_dev_libs!
end

#assert_has_dev_libs!Object



297
298
299
300
301
302
303
304
305
# File 'ext/RMagick/extconf.rb', line 297

def assert_has_dev_libs!
  return unless RUBY_PLATFORM !~ /mswin|mingw/

  unless `pkg-config --libs MagickCore`[/\bl\s*(MagickCore|Magick)6?\b/]
    exit_failure "Can't install RMagick #{RMAGICK_VERS}. " \
               "Can't find the ImageMagick library or one of the dependent libraries. " \
               "Check the mkmf.log file for more detailed information.\n"
  end
end

#assert_minimum_ruby_version!Object



289
290
291
292
293
294
295
# File 'ext/RMagick/extconf.rb', line 289

def assert_minimum_ruby_version!
  unless checking_for("Ruby version >= #{MIN_RUBY_VERS}") do
    Gem::Version.new(RUBY_VERSION) >= Gem::Version.new(MIN_RUBY_VERS)
  end
    exit_failure "Can't install RMagick #{RMAGICK_VERS}. Ruby #{MIN_RUBY_VERS} or later required.\n"
  end
end

#check_multiple_imagemagick_versionsObject

Seems like lots of people have multiple versions of ImageMagick installed.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'ext/RMagick/extconf.rb', line 190

def check_multiple_imagemagick_versions
  versions = []
  path = ENV['PATH'].split(File::PATH_SEPARATOR)
  path.each do |dir|
    file = File.join(dir, 'Magick-config')
    next unless File.executable? file

    vers = `#{file} --version`.chomp.strip
    prefix = `#{file} --prefix`.chomp.strip
    versions << [vers, prefix, dir]
  end
  versions.uniq!
  return unless versions.size > 1

  msg = "\nWarning: Found more than one ImageMagick installation. This could cause problems at runtime.\n"
  versions.each do |vers, prefix, dir|
    msg << "         #{dir}/Magick-config reports version #{vers} is installed in #{prefix}\n"
  end
  msg << "Using #{versions[0][0]} from #{versions[0][1]}.\n\n"
  Logging.message msg
  message msg
end

#check_partial_imagemagick_versionsObject

Ubuntu (maybe other systems) comes with a partial installation of ImageMagick in the prefix /usr (some libraries, no includes, and no binaries). This causes problems when /usr/lib is in the path (e.g., using the default Ruby installation).



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'ext/RMagick/extconf.rb', line 217

def check_partial_imagemagick_versions
  prefix = config_string('prefix') || ''
  matches = [
    prefix + '/lib/lib?agick*',
    prefix + '/include/ImageMagick',
    prefix + '/bin/Magick-config'
  ].map do |file_glob|
    Dir.glob(file_glob)
  end
  matches.delete_if(&:empty?)
  return unless !matches.empty? && matches.length < 3

  msg = "\nWarning: Found a partial ImageMagick installation. Your operating system likely has some built-in ImageMagick libraries but not all of ImageMagick. This will most likely cause problems at both compile and runtime.\nFound partial installation at: " + prefix + "\n"
  Logging.message msg
  message msg
end

#configure_compile_optionsObject



61
62
63
64
65
66
67
68
69
70
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'ext/RMagick/extconf.rb', line 61

def configure_compile_options
  # Magick-config is not available on Windows
  if RUBY_PLATFORM !~ /mswin|mingw/

    # Check for compiler. Extract first word so ENV['CC'] can be a program name with arguments.
    config = defined?(RbConfig) ? ::RbConfig : ::Config
    cc = (ENV['CC'] || config::CONFIG['CC'] || 'gcc').split(' ').first
    exit_failure "No C compiler found in ${ENV['PATH']}. See mkmf.log for details." unless find_executable(cc)

    magick_package = determine_imagemagick_package

    $magick_version = `pkg-config #{magick_package} --modversion`[/^(\d+\.\d+\.\d+)/]

    check_multiple_imagemagick_versions
    check_partial_imagemagick_versions

    # Ensure minimum ImageMagick version
    # Check minimum ImageMagick version if possible
    checking_for("outdated ImageMagick version (<= #{Magick::MIN_IM_VERSION})") do
      Logging.message("Detected ImageMagick version: #{$magick_version}\n")

      exit_failure "Can't install RMagick #{RMAGICK_VERS}. You must have ImageMagick #{Magick::MIN_IM_VERSION} or later.\n" if Gem::Version.new($magick_version) < Gem::Version.new(Magick::MIN_IM_VERSION)
    end

    # Save flags
    $CFLAGS = ENV['CFLAGS'].to_s + ' ' + `pkg-config --cflags #{magick_package}`.chomp
    $CPPFLAGS = ENV['CPPFLAGS'].to_s + ' ' + `pkg-config --cflags #{magick_package}`.chomp
    $LDFLAGS = ENV['LDFLAGS'].to_s + ' ' + `pkg-config --libs #{magick_package}`.chomp
    $LOCAL_LIBS = ENV['LIBS'].to_s + ' ' + `pkg-config --libs #{magick_package}`.chomp

    set_archflags_for_osx if RUBY_PLATFORM =~ /darwin/ # osx

  elsif RUBY_PLATFORM =~ /mingw/ # mingw

    `identify -version` =~ /Version: ImageMagick (\d+\.\d+\.\d+)-+\d+ /
    abort 'Unable to get ImageMagick version' unless Regexp.last_match(1)
    $magick_version = Regexp.last_match(1)

    dir_paths = search_paths_for_library_for_windows
    $CPPFLAGS = %(-I"#{dir_paths[:include]}")
    $LDFLAGS = %(-L"#{dir_paths[:lib]}")

    have_library('CORE_RL_magick_')

  else # mswin

    `identify -version` =~ /Version: ImageMagick (\d+\.\d+\.\d+)-+\d+ /
    abort 'Unable to get ImageMagick version' unless Regexp.last_match(1)
    $magick_version = Regexp.last_match(1)

    dir_paths = search_paths_for_library_for_windows
    $CPPFLAGS << %( -I"#{dir_paths[:include]}")
    $LDFLAGS << %( -libpath:"#{dir_paths[:lib]}")

    $LOCAL_LIBS = 'CORE_RL_magick_.lib'

  end

  $CFLAGS << (have_macro('__GNUC__') ? ' -std=gnu99' : ' -std=c99')
end

#configure_headersObject



51
52
53
54
55
56
57
58
59
# File 'ext/RMagick/extconf.rb', line 51

def configure_headers
  @headers = %w[assert.h ctype.h stdio.h stdlib.h math.h time.h sys/types.h]

  if have_header('magick/MagickCore.h')
    headers << 'magick/MagickCore.h'
  else
    exit_failure "Can't install RMagick #{RMAGICK_VERS}. Can't find magick/MagickCore.h."
  end
end

#configured_compile_optionsObject



39
40
41
42
43
44
45
46
47
48
49
# File 'ext/RMagick/extconf.rb', line 39

def configured_compile_options
  {
    magick_version: $magick_version,
    local_libs: $LOCAL_LIBS,
    cflags: $CFLAGS,
    cppflags: $CPPFLAGS,
    ldflags: $LDFLAGS,
    defs: $defs,
    config_h: $config_h
  }
end

#create_header_fileObject



307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'ext/RMagick/extconf.rb', line 307

def create_header_file
  [
    'GetImageChannelEntropy', # 6.9.0-0
    'SetImageGray' # 6.9.1-10
  ].each do |func|
    have_func(func, headers)
  end

  # Miscellaneous constants
  $defs.push("-DRUBY_VERSION_STRING=\"ruby #{RUBY_VERSION}\"")
  $defs.push("-DRMAGICK_VERSION_STRING=\"RMagick #{RMAGICK_VERS}\"")

  if Gem::Version.new($magick_version) >= Gem::Version.new('6.8.9')
    $defs.push('-DIMAGEMAGICK_GREATER_THAN_EQUAL_6_8_9=1')
  end
  if Gem::Version.new($magick_version) >= Gem::Version.new('6.9.0')
    $defs.push('-DIMAGEMAGICK_GREATER_THAN_EQUAL_6_9_0=1')
  end

  create_header
end

#create_makefile_fileObject



329
330
331
332
333
334
335
336
337
338
339
340
# File 'ext/RMagick/extconf.rb', line 329

def create_makefile_file
  create_header_file
  # Prior to 1.8.5 mkmf duplicated the symbols on the command line and in the
  # extconf.h header. Suppress that behavior by removing the symbol array.
  $defs = []

  # Force re-compilation if the generated Makefile changed.
  $config_h = 'Makefile rmagick.h'

  create_makefile('RMagick2')
  print_summary
end

#determine_imagemagick_packageObject



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'ext/RMagick/extconf.rb', line 163

def determine_imagemagick_package
  unless find_executable('pkg-config')
    exit_failure "Can't install RMagick #{RMAGICK_VERS}. Can't find pkg-config in #{ENV['PATH']}\n"
  end

  packages = `pkg-config --list-all`.scan(/(ImageMagick\-6[\.A-Z0-9]+) .*/).flatten

  # For ancient version of ImageMagick 6 we need a different regex
  if packages.empty?
    packages = `pkg-config --list-all`.scan(/(ImageMagick) .*/).flatten
  end

  if packages.empty?
    exit_failure "Can't install RMagick #{RMAGICK_VERS}. Can't find ImageMagick with pkg-config\n"
  end

  if packages.length > 1
    package_lines = packages.map { |package| " - #{package}" }.join("\n")
    msg = "\nWarning: Found more than one ImageMagick installation. This could cause problems at runtime.\n#{package_lines}\n\n"
    Logging.message msg
    message msg
  end

  packages.first
end

#exit_failure(msg) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'ext/RMagick/extconf.rb', line 146

def exit_failure(msg)
  msg = "ERROR: #{msg}"

  Logging.message msg

  @stdout.puts "\n\n"
  if ENV['NO_COLOR']
    @stdout.puts msg
  else
    @stdout.print "\e[31m\e[1m#{msg}\e[0m"
  end
  @stdout.puts "\n\n"
  @stdout.flush

  exit(1)
end

#have_enum_value(enum, value, headers = nil, &b) ⇒ Object

Test for a specific value in an enum type



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'ext/RMagick/extconf.rb', line 123

def have_enum_value(enum, value, headers = nil, &b)
  checking_for "#{enum}.#{value}" do
    if try_compile(<<"SRC", &b)
#{COMMON_HEADERS}
    #{cpp_include(headers)}
/*top*/
int main() { #{enum} t = #{value}; t = t; return 0; }
SRC
      $defs.push(format('-DHAVE_ENUM_%s', value.upcase))
      true
    else
      false
    end
  end
end

#have_enum_values(enum, values, headers = nil, &b) ⇒ Object

Test for multiple values of the same enum type



140
141
142
143
144
# File 'ext/RMagick/extconf.rb', line 140

def have_enum_values(enum, values, headers = nil, &b)
  values.each do |value|
    have_enum_value(enum, value, headers, &b)
  end
end


342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
# File 'ext/RMagick/extconf.rb', line 342

def print_summary
  summary = <<"END_SUMMARY"


#{'=' * 70}
#{DateTime.now.strftime('%a %d %b %y %T')}
This installation of RMagick #{RMAGICK_VERS} is configured for
Ruby #{RUBY_VERSION} (#{RUBY_PLATFORM}) and ImageMagick #{$magick_version}
#{'=' * 70}


END_SUMMARY

  Logging.message summary
  message summary
end

#search_paths_for_library_for_windowsObject



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'ext/RMagick/extconf.rb', line 251

def search_paths_for_library_for_windows
  msg = 'searching PATH for the ImageMagick library...'
  Logging.message msg
  message msg + "\n"

  found_lib = false
  dir_paths = {}

  paths = ENV['PATH'].split(File::PATH_SEPARATOR)
  paths.each do |dir|
    lib = File.join(dir, 'lib')
    lib_file = File.join(lib, 'CORE_RL_magick_.lib')
    next unless File.exist?(lib_file)

    dir_paths[:include] = File.join(dir, 'include')
    dir_paths[:lib] = lib

    found_lib = true
    break
  end

  return dir_paths if found_lib

  exit_failure <<END_MINGW
Can't install RMagick #{RMAGICK_VERS}.
Can't find the ImageMagick library.
Retry with '--with-opt-dir' option.
Usage: gem install rmagick -- '--with-opt-dir=\"[path to ImageMagick]\"'
e.g.
  gem install rmagick -- '--with-opt-dir=\"C:\Program Files\ImageMagick-6.9.1-Q16\"'
END_MINGW
end

#set_archflags_for_osxObject

issue #169 set ARCHFLAGS appropriately for OSX



236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'ext/RMagick/extconf.rb', line 236

def set_archflags_for_osx
  archflags = []
  fullpath = `which convert`
  fileinfo = `file #{fullpath}`

  # default ARCHFLAGS
  archs = $ARCH_FLAG.scan(/-arch\s+(\S+)/).flatten

  archs.each do |arch|
    archflags << "-arch #{arch}" if fileinfo.include?(arch)
  end

  $ARCH_FLAG = archflags.join(' ') unless archflags.empty?
end

#setup_pkg_config_pathObject



24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'ext/RMagick/extconf.rb', line 24

def setup_pkg_config_path
  if find_executable('brew')
    pkg_config_path = "#{`brew --prefix imagemagick@6`.strip}/lib/pkgconfig"
  elsif find_executable('pacman')
    pkg_config_path = '/usr/lib/imagemagick6/pkgconfig'
  else
    return
  end

  pkg_config_paths = ENV['PKG_CONFIG_PATH'].to_s.split(':')
  if File.exist?(pkg_config_path) && !pkg_config_paths.include?(pkg_config_path)
    ENV['PKG_CONFIG_PATH'] = [ENV['PKG_CONFIG_PATH'], pkg_config_path].compact.join(':')
  end
end