Module PhusionPassenger::PlatformInfo
In: lib/phusion_passenger/platform_info.rb
lib/phusion_passenger/platform_info/documentation_tools.rb
lib/phusion_passenger/platform_info/ruby.rb
lib/phusion_passenger/platform_info/binary_compatibility.rb
lib/phusion_passenger/platform_info/linux.rb
lib/phusion_passenger/platform_info/zlib.rb
lib/phusion_passenger/platform_info/apache.rb
lib/phusion_passenger/platform_info/compiler.rb
lib/phusion_passenger/platform_info/curl.rb
lib/phusion_passenger/platform_info/operating_system.rb

Users can change the detection behavior by setting the environment variable APXS2 to the correct ‘apxs’ (or ‘apxs2’) binary, as provided by Apache.

Methods

Classes and Modules

Class PhusionPassenger::PlatformInfo::RuntimeError

Constants

GEM_HOME = gem_home
RUBY_ENGINE = ::RUBY_ENGINE
RUBY_ENGINE = "ruby"

Public Class methods

The absolute path to the Apache 2 ‘bin’ directory, or nil if unknown.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 140
140:         def self.apache2_bindir
141:                 if apxs2.nil?
142:                         return nil
143:                 else
144:                         return `#{apxs2} -q BINDIR 2>/dev/null`.strip
145:                 end
146:         end

The C compiler flags that are necessary to compile an Apache module. Also includes APR and APU compiler flags if with_apr_flags is true.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 164
164:         def self.apache2_module_cflags(with_apr_flags = true)
165:                 flags = ["-fPIC"]
166:                 if compiler_supports_visibility_flag?
167:                         flags << "-fvisibility=hidden -DVISIBILITY_ATTRIBUTE_SUPPORTED"
168:                         if compiler_visibility_flag_generates_warnings? && compiler_supports_wno_attributes_flag?
169:                                 flags << "-Wno-attributes"
170:                         end
171:                 end
172:                 if with_apr_flags
173:                         flags << apr_flags
174:                         flags << apu_flags
175:                 end
176:                 if !apxs2.nil?
177:                         apxs2_flags = `#{apxs2} -q CFLAGS`.strip << " -I" << `#{apxs2} -q INCLUDEDIR`.strip
178:                         apxs2_flags.gsub!(/-O\d? /, '')
179: 
180:                         # Remove flags not supported by GCC
181:                         if RUBY_PLATFORM =~ /solaris/ # TODO: Add support for people using SunStudio
182:                                 # The big problem is Coolstack apxs includes a bunch of solaris -x directives.
183:                                 options = apxs2_flags.split
184:                                 options.reject! { |f| f =~ /^\-x/ }
185:                                 options.reject! { |f| f =~ /^\-Xa/ }
186:                                 options.reject! { |f| f =~ /^\-fast/ }
187:                                 options.reject! { |f| f =~ /^\-mt/ }
188:                                 apxs2_flags = options.join(' ')
189:                         end
190:                         
191:                         apxs2_flags.strip!
192:                         flags << apxs2_flags
193:                 end
194:                 if !httpd.nil? && RUBY_PLATFORM =~ /darwin/
195:                         # The default Apache install on OS X is a universal binary.
196:                         # Figure out which architectures it's compiled for and do the same
197:                         # thing for mod_passenger. We use the 'file' utility to do this.
198:                         #
199:                         # Running 'file' on the Apache executable usually outputs something
200:                         # like this:
201:                         #
202:                         #   /usr/sbin/httpd: Mach-O universal binary with 4 architectures
203:                         #   /usr/sbin/httpd (for architecture ppc7400):     Mach-O executable ppc
204:                         #   /usr/sbin/httpd (for architecture ppc64):       Mach-O 64-bit executable ppc64
205:                         #   /usr/sbin/httpd (for architecture i386):        Mach-O executable i386
206:                         #   /usr/sbin/httpd (for architecture x86_64):      Mach-O 64-bit executable x86_64
207:                         #
208:                         # But on some machines, it may output just:
209:                         #
210:                         #   /usr/sbin/httpd: Mach-O fat file with 4 architectures
211:                         #
212:                         # (http://code.google.com/p/phusion-passenger/issues/detail?id=236)
213:                         output = `file "#{httpd}"`.strip
214:                         if output =~ /Mach-O fat file/ && output !~ /for architecture/
215:                                 architectures = ["i386", "ppc", "x86_64", "ppc64"]
216:                         else
217:                                 architectures = []
218:                                 output.split("\n").grep(/for architecture/).each do |line|
219:                                         line =~ /for architecture (.*?)\)/
220:                                         architectures << $1
221:                                 end
222:                         end
223:                         # The compiler may not support all architectures in the binary.
224:                         # XCode 4 seems to have removed support for the PPC architecture
225:                         # even though there are still plenty of Apache binaries around
226:                         # containing PPC components.
227:                         architectures.reject! do |arch|
228:                                 !compiler_supports_architecture?(arch)
229:                         end
230:                         architectures.map! do |arch|
231:                                 "-arch #{arch}"
232:                         end
233:                         flags << architectures.compact.join(' ')
234:                 end
235:                 return flags.compact.join(' ').strip
236:         end

Linker flags that are necessary for linking an Apache module. Already includes APR and APU linker flags.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 241
241:         def self.apache2_module_ldflags
242:                 flags = "-fPIC #{apr_libs} #{apu_libs}"
243:                 flags.strip!
244:                 return flags
245:         end

The absolute path to the Apache 2 ‘sbin’ directory, or nil if unknown.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 150
150:         def self.apache2_sbindir
151:                 if apxs2.nil?
152:                         return nil
153:                 else
154:                         return `#{apxs2} -q SBINDIR`.strip
155:                 end
156:         end

The absolute path to the ‘apachectl’ or ‘apache2ctl’ binary, or nil if not found.

[Source]

    # File lib/phusion_passenger/platform_info/apache.rb, line 60
60:         def self.apache2ctl
61:                 return find_apache2_executable('apache2ctl', 'apachectl2', 'apachectl')
62:         end

The absolute path to the ‘apr-config’ or ‘apr-1-config’ executable, or nil if not found.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 86
 86:         def self.apr_config
 87:                 if env_defined?('APR_CONFIG')
 88:                         return ENV['APR_CONFIG']
 89:                 elsif apxs2.nil?
 90:                         return nil
 91:                 else
 92:                         filename = `#{apxs2} -q APR_CONFIG 2>/dev/null`.strip
 93:                         if filename.empty?
 94:                                 apr_bindir = `#{apxs2} -q APR_BINDIR 2>/dev/null`.strip
 95:                                 if apr_bindir.empty?
 96:                                         return nil
 97:                                 else
 98:                                         return select_executable(apr_bindir,
 99:                                                 "apr-1-config", "apr-config")
100:                                 end
101:                         elsif File.exist?(filename)
102:                                 return filename
103:                         else
104:                                 return nil
105:                         end
106:                 end
107:         end

Returns whether it is necessary to use information outputted by ‘apr-config’ and ‘apu-config’ in order to compile an Apache module. When Apache is installed with —with-included-apr, the APR/APU headers are placed into the same directory as the Apache headers, and so ‘apr-config’ and ‘apu-config’ won‘t be necessary in that case.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 276
276:         def self.apr_config_needed_for_building_apache_modules?
277:                 filename = File.join("#{test_exe_outdir}/passenger-platform-check-#{Process.pid}.c")
278:                 File.open(filename, "w") do |f|
279:                         f.puts("#include <apr.h>")
280:                 end
281:                 begin
282:                         return !system("(gcc #{apache2_module_cflags(false)} -c '#{filename}' -o '#{filename}.o') >/dev/null 2>/dev/null")
283:                 ensure
284:                         File.unlink(filename) rescue nil
285:                         File.unlink("#{filename}.o") rescue nil
286:                 end
287:         end

The C compiler flags that are necessary for programs that use APR.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 249
249:         def self.apr_flags
250:                 return determine_apr_info[0]
251:         end

The linker flags that are necessary for linking programs that use APR.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 254
254:         def self.apr_libs
255:                 return determine_apr_info[1]
256:         end

The absolute path to the ‘apu-config’ or ‘apu-1-config’ executable, or nil if not found.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 112
112:         def self.apu_config
113:                 if env_defined?('APU_CONFIG')
114:                         return ENV['APU_CONFIG']
115:                 elsif apxs2.nil?
116:                         return nil
117:                 else
118:                         filename = `#{apxs2} -q APU_CONFIG 2>/dev/null`.strip
119:                         if filename.empty?
120:                                 apu_bindir = `#{apxs2} -q APU_BINDIR 2>/dev/null`.strip
121:                                 if apu_bindir.empty?
122:                                         return nil
123:                                 else
124:                                         return select_executable(apu_bindir,
125:                                                 "apu-1-config", "apu-config")
126:                                 end
127:                         elsif File.exist?(filename)
128:                                 return filename
129:                         else
130:                                 return nil
131:                         end
132:                 end
133:         end

The C compiler flags that are necessary for programs that use APR-Util.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 259
259:         def self.apu_flags
260:                 return determine_apu_info[0]
261:         end

The linker flags that are necessary for linking programs that use APR-Util.

[Source]

     # File lib/phusion_passenger/platform_info/apache.rb, line 264
264:         def self.apu_libs
265:                 return determine_apu_info[1]
266:         end

The absolute path to the ‘apxs’ or ‘apxs2’ executable, or nil if not found.

[Source]

    # File lib/phusion_passenger/platform_info/apache.rb, line 44
44:         def self.apxs2
45:                 if env_defined?("APXS2")
46:                         return ENV["APXS2"]
47:                 end
48:                 ['apxs2', 'apxs'].each do |name|
49:                         command = find_command(name)
50:                         if !command.nil?
51:                                 return command
52:                         end
53:                 end
54:                 return nil
55:         end

[Source]

    # File lib/phusion_passenger/platform_info/documentation_tools.rb, line 29
29:         def self.asciidoc
30:                 return find_command('asciidoc') || find_command('mizuho-asciidoc')
31:         end

[Source]

     # File lib/phusion_passenger/platform_info.rb, line 250
250:         def self.cc
251:                 return ENV['CC'] || "gcc"
252:         end

Checks whether the compiler supports "-arch #{arch}".

[Source]

    # File lib/phusion_passenger/platform_info/compiler.rb, line 50
50:         def self.compiler_supports_architecture?(arch)
51:                 return try_compile(:c, '', "-arch #{arch}")
52:         end

[Source]

    # File lib/phusion_passenger/platform_info/compiler.rb, line 54
54:         def self.compiler_supports_visibility_flag?
55:                 return try_compile(:c, '', '-fvisibility=hidden')
56:         end

[Source]

    # File lib/phusion_passenger/platform_info/compiler.rb, line 59
59:         def self.compiler_supports_wno_attributes_flag?
60:                 return try_compile(:c, '', '-Wno-attributes')
61:         end

Returns whether compiling C++ with -fvisibility=hidden might result in tons of useless warnings, like this: code.google.com/p/phusion-passenger/issues/detail?id=526 This appears to be a bug in older g++ versions: gcc.gnu.org/ml/gcc-patches/2006-07/msg00861.html Warnings should be suppressed with -Wno-attributes.

[Source]

    # File lib/phusion_passenger/platform_info/compiler.rb, line 70
70:         def self.compiler_visibility_flag_generates_warnings?
71:                 if RUBY_PLATFORM =~ /linux/ && `#{cxx} -v 2>&1` =~ /gcc version (.*?)/
72:                         return $1 <= "4.1.2"
73:                 else
74:                         return false
75:                 end
76:         end

Returns a list of all CPU architecture names that the current machine CPU supports. If there are multiple such architectures then the first item in the result denotes that OS runtime‘s main/preferred architecture.

This function normalizes some names. For example x86 is always reported as "x86" regardless of whether the OS reports it as "i386" or "i686". x86_64 is always reported as "x86_64" even if the OS reports it as "amd64".

Please note that even if the CPU supports multiple architectures, the operating system might not. For example most x86 CPUs nowadays also support x86_64, but x86_64 Linux systems require various x86 compatibility libraries to be installed before x86 executables can be run. This function does not detect whether these compatibility libraries are installed. The only guarantee that you have is that the OS can run executables in the architecture denoted by the first item in the result.

For example, on x86_64 Linux this function can return ["x86_64", "x86"]. This indicates that the CPU supports both of these architectures, and that the OS‘s main/preferred architecture is x86_64. Most executables on the system are thus be x86_64. It is guaranteed that the OS can run x86_64 executables, but not x86 executables per se.

Another example: on MacOS X this function can return either

"x86_64", "x86"
or ["x86", "x86_64"]. The former result indicates

OS X 10.6 (Snow Leopard) and beyond because starting from that version everything is 64-bit by default. The latter result indicates an OS X version older than 10.6.

[Source]

     # File lib/phusion_passenger/platform_info/operating_system.rb, line 77
 77:         def self.cpu_architectures
 78:                 if os_name == "macosx"
 79:                         arch = `uname -p`.strip
 80:                         if arch == "i386"
 81:                                 # Macs have been x86 since around 2007. I think all of them come with
 82:                                 # a recent enough Intel CPU that supports both x86 and x86_64, and I
 83:                                 # think every OS X version has both the x86 and x86_64 runtime installed.
 84:                                 major, minor, *rest = `sw_vers -productVersion`.strip.split(".")
 85:                                 major = major.to_i
 86:                                 minor = minor.to_i
 87:                                 if major >= 10 || (major == 10 && minor >= 6)
 88:                                         # Since Snow Leopard x86_64 is the default.
 89:                                         ["x86_64", "x86"]
 90:                                 else
 91:                                         # Before Snow Leopard x86 was the default.
 92:                                         ["x86", "x86_64"]
 93:                                 end
 94:                         else
 95:                                 arch
 96:                         end
 97:                 else
 98:                         arch = `uname -p`.strip
 99:                         # On some systems 'uname -p' returns something like
100:                         # 'Intel(R) Pentium(R) M processor 1400MHz'.
101:                         if arch == "unknown" || arch =~ / /
102:                                 arch = `uname -m`.strip
103:                         end
104:                         if arch =~ /^i.86$/
105:                                 arch = "x86"
106:                         elsif arch == "amd64"
107:                                 arch = "x86_64"
108:                         end
109:                         
110:                         if arch == "x86"
111:                                 # Most x86 operating systems nowadays are probably running on
112:                                 # a CPU that supports both x86 and x86_64, but we're not gonna
113:                                 # go through the trouble of checking that. The main architecture
114:                                 # is what we usually care about.
115:                                 ["x86"]
116:                         elsif arch == "x86_64"
117:                                 # I don't think there's a single x86_64 CPU out there
118:                                 # that doesn't support x86 as well.
119:                                 ["x86_64", "x86"]
120:                         else
121:                                 [arch]
122:                         end
123:                 end
124:         end

[Source]

    # File lib/phusion_passenger/platform_info/curl.rb, line 29
29:         def self.curl_flags
30:                 result = `(curl-config --cflags) 2>/dev/null`.strip
31:                 if result.empty?
32:                         return nil
33:                 else
34:                         version = `curl-config --vernum`.strip
35:                         if version >= '070c01'
36:                                 # Curl >= 7.12.1 supports curl_easy_reset()
37:                                 result << " -DHAS_CURL_EASY_RESET"
38:                         end
39:                         return result
40:                 end
41:         end

[Source]

    # File lib/phusion_passenger/platform_info/curl.rb, line 44
44:         def self.curl_libs
45:                 result = `(curl-config --libs) 2>/dev/null`.strip
46:                 if result.empty?
47:                         return nil
48:                 else
49:                         return result
50:                 end
51:         end

[Source]

    # File lib/phusion_passenger/platform_info/curl.rb, line 54
54:         def self.curl_supports_ssl?
55:                 features = `(curl-config --feature) 2>/dev/null`
56:                 return features =~ /SSL/
57:         end

[Source]

     # File lib/phusion_passenger/platform_info.rb, line 254
254:         def self.cxx
255:                 return ENV['CXX'] || "g++"
256:         end

C compiler flags that should be passed in order to enable debugging information.

[Source]

     # File lib/phusion_passenger/platform_info/compiler.rb, line 168
168:         def self.debugging_cflags
169:                 if RUBY_PLATFORM =~ /openbsd/
170:                         # According to OpenBSD's pthreads man page, pthreads do not work
171:                         # correctly when an app is compiled with -g. It recommends using
172:                         # -ggdb instead.
173:                         return '-ggdb'
174:                 else
175:                         return '-g'
176:                 end
177:         end

[Source]

     # File lib/phusion_passenger/platform_info.rb, line 159
159:         def self.env_defined?(name)
160:                 return !ENV[name].nil? && !ENV[name].empty?
161:         end

[Source]

     # File lib/phusion_passenger/platform_info/compiler.rb, line 179
179:         def self.export_dynamic_flags
180:                 if RUBY_PLATFORM =~ /linux/
181:                         return '-rdynamic'
182:                 else
183:                         return nil
184:                 end
185:         end

Check whether the specified command is in $PATH, and return its absolute filename. Returns nil if the command is not found.

This function exists because system(‘which’) doesn‘t always behave correctly, for some weird reason.

[Source]

     # File lib/phusion_passenger/platform_info.rb, line 148
148:         def self.find_command(name)
149:                 name = name.to_s
150:                 ENV['PATH'].to_s.split(File::PATH_SEPARATOR).detect do |directory|
151:                         path = File.join(directory, name)
152:                         if File.file?(path) && File.executable?(path)
153:                                 return path
154:                         end
155:                 end
156:                 return nil
157:         end

Returns the correct ‘gem’ command for this Ruby interpreter.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 110
110:         def self.gem_command
111:                 return locate_ruby_tool('gem')
112:         end

[Source]

    # File lib/phusion_passenger/platform_info/compiler.rb, line 30
30:         def self.gnu_make
31:                 gmake = find_command('gmake')
32:                 if !gmake
33:                         gmake = find_command('make')
34:                         if gmake
35:                                 if `#{gmake} --version 2>&1` =~ /GNU/
36:                                         return gmake
37:                                 else
38:                                         return nil
39:                                 end
40:                         else
41:                                 return nil
42:                         end
43:                 else
44:                         return gmake
45:                 end
46:         end

[Source]

    # File lib/phusion_passenger/platform_info/compiler.rb, line 79
79:         def self.has_math_library?
80:                 return try_link(:c, "int main() { return 0; }\n", '-lmath')
81:         end

The absolute path to the Apache binary (that is, ‘httpd’, ‘httpd2’, ‘apache’ or ‘apache2’), or nil if not found.

[Source]

    # File lib/phusion_passenger/platform_info/apache.rb, line 67
67:         def self.httpd
68:                 if env_defined?('HTTPD')
69:                         return ENV['HTTPD']
70:                 elsif apxs2.nil?
71:                         ["apache2", "httpd2", "apache", "httpd"].each do |name|
72:                                 command = find_command(name)
73:                                 if !command.nil?
74:                                         return command
75:                                 end
76:                         end
77:                         return nil
78:                 else
79:                         return find_apache2_executable(`#{apxs2} -q TARGET`.strip)
80:                 end
81:         end

Returns whether the current Ruby interpreter is managed by RVM.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 154
154:         def self.in_rvm?
155:                 bindir = Config::CONFIG['bindir']
156:                 return bindir.include?('/.rvm/') || bindir.include?('/rvm/')
157:         end

The current platform‘s shared library extension (‘so’ on most Unices).

[Source]

    # File lib/phusion_passenger/platform_info/operating_system.rb, line 42
42:         def self.library_extension
43:                 if RUBY_PLATFORM =~ /darwin/
44:                         return "bundle"
45:                 else
46:                         return "so"
47:                 end
48:         end

An identifier for the current Linux distribution. nil if the operating system is not Linux.

[Source]

    # File lib/phusion_passenger/platform_info/linux.rb, line 30
30:         def self.linux_distro
31:                 tags = linux_distro_tags
32:                 if tags
33:                         return tags.first
34:                 else
35:                         return nil
36:                 end
37:         end

Autodetects the current Linux distribution and return a number of identifier tags. The first tag identifies the distribution while the other tags indicate which distributions it is likely compatible with. Returns nil if the operating system is not Linux.

[Source]

    # File lib/phusion_passenger/platform_info/linux.rb, line 43
43:         def self.linux_distro_tags
44:                 if RUBY_PLATFORM !~ /linux/
45:                         return nil
46:                 end
47:                 lsb_release = read_file("/etc/lsb-release")
48:                 if lsb_release =~ /Ubuntu/
49:                         return [:ubuntu, :debian]
50:                 elsif File.exist?("/etc/debian_version")
51:                         return [:debian]
52:                 elsif File.exist?("/etc/redhat-release")
53:                         redhat_release = read_file("/etc/redhat-release")
54:                         if redhat_release =~ /CentOS/
55:                                 return [:centos, :redhat]
56:                         elsif redhat_release =~ /Fedora/
57:                                 return [:fedora, :redhat]
58:                         elsif redhat_release =~ /Mandriva/
59:                                 return [:mandriva, :redhat]
60:                         else
61:                                 # On official RHEL distros, the content is in the form of
62:                                 # "Red Hat Enterprise Linux Server release 5.1 (Tikanga)"
63:                                 return [:rhel, :redhat]
64:                         end
65:                 elsif File.exist?("/etc/suse-release")
66:                         return [:suse]
67:                 elsif File.exist?("/etc/gentoo-release")
68:                         return [:gentoo]
69:                 else
70:                         return [:unknown]
71:                 end
72:                 # TODO: Slackware
73:         end

Locates a Ruby tool command, e.g. ‘gem’, ‘rake’, ‘bundle’, etc. Instead of naively looking in $PATH, this function uses a variety of search heuristics to find the command that‘s really associated with the current Ruby interpreter. It should never locate a command that‘s actually associated with a different Ruby interpreter. Returns nil when nothing‘s found.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 246
246:         def self.locate_ruby_tool(name)
247:                 result = locate_ruby_tool_by_basename(name)
248:                 if !result
249:                         exeext = Config::CONFIG['EXEEXT']
250:                         exeext = nil if exeext.empty?
251:                         if exeext
252:                                 result = locate_ruby_tool_by_basename("#{name}#{exeext}")
253:                         end
254:                         if !result
255:                                 result = locate_ruby_tool_by_basename(transform_according_to_ruby_exec_format(name))
256:                         end
257:                         if !result && exeext
258:                                 result = locate_ruby_tool_by_basename(transform_according_to_ruby_exec_format(name) + exeext)
259:                         end
260:                 end
261:                 return result
262:         end

Returns the operating system‘s name. This name is in lowercase and contains no spaces, and thus is suitable to be used in some kind of ID. E.g. "linux", "macosx".

[Source]

    # File lib/phusion_passenger/platform_info/operating_system.rb, line 32
32:         def self.os_name
33:                 if Config::CONFIG['target_os'] =~ /darwin/ && (sw_vers = find_command('sw_vers'))
34:                         return "macosx"
35:                 else
36:                         return RUBY_PLATFORM.sub(/.*?-/, '')
37:                 end
38:         end

Returns an identifier string that describes the current platform‘s binary compatibility with regard to Phusion Passenger binaries, both the Ruby extension and the C++ binaries. Two systems with the same binary compatibility identifiers are able to run the same Phusion Passenger binaries.

The the string depends on the following factors:

  • The Ruby extension binary compatibility identifiers.
  • The operating system name.
  • Operating system runtime identifier. This may include the kernel version, libc version, C++ ABI version, etc. Everything that is of interest for binary compatibility with Phusion Passenger‘s C++ components.
  • Operating system default runtime architecture. This is not the same as the CPU architecture; some CPUs support multiple architectures, e.g. Intel Core 2 Duo supports x86 and x86_64. Some operating systems actually support multiple runtime architectures: a lot of x86_64 Linux distributions also include 32-bit runtimes, and OS X Snow Leopard is x86_64 by default but all system libraries also support x86. This component identifies the architecture that is used when compiling a binary with the system‘s C++ compiler with its default options.

[Source]

     # File lib/phusion_passenger/platform_info/binary_compatibility.rb, line 103
103:         def self.passenger_binary_compatibility_id
104:                 ruby_engine, ruby_ext_version, ruby_arch, os_name =
105:                         ruby_extension_binary_compatibility_ids
106:                 
107:                 if os_name == "macosx"
108:                         # RUBY_PLATFORM gives us the kernel version, but we want
109:                         # the OS X version.
110:                         os_version_string = `sw_vers -productVersion`.strip
111:                         # sw_vers returns something like "10.6.2". We're only
112:                         # interested in the first two digits (MAJOR.MINOR) since
113:                         # tiny releases tend to be binary compatible with each
114:                         # other.
115:                         components = os_version_string.split(".")
116:                         os_version = "#{components[0]}.#{components[1]}"
117:                         os_runtime = os_version
118:                         
119:                         os_arch = cpu_architectures[0]
120:                         if os_version >= "10.5" && os_arch =~ /^i.86$/
121:                                 # On Snow Leopard, 'uname -m' returns i386 but
122:                                 # we *know* that everything is x86_64 by default.
123:                                 os_arch = "x86_64"
124:                         end
125:                 else
126:                         os_arch = cpu_architectures[0]
127:                         
128:                         cpp = find_command('cpp')
129:                         if cpp
130:                                 macros = `#{cpp} -dM < /dev/null`
131:                                 
132:                                 # Can be something like "4.3.2"
133:                                 # or "4.2.1 20070719 (FreeBSD)"
134:                                 macros =~ /__VERSION__ "(.+)"/
135:                                 compiler_version = $1
136:                                 compiler_version.gsub!(/ .*/, '') if compiler_version
137:                                 
138:                                 macros =~ /__GXX_ABI_VERSION (.+)$/
139:                                 cxx_abi_version = $1
140:                         else
141:                                 compiler_version = nil
142:                                 cxx_abi_version = nil
143:                         end
144:                         
145:                         if compiler_version && cxx_abi_version
146:                                 os_runtime = "gcc#{compiler_version}-#{cxx_abi_version}"
147:                         else
148:                                 os_runtime = [compiler_version, cxx_abi_version].compact.join("-")
149:                                 if os_runtime.empty?
150:                                         os_runtime = `uname -r`.strip
151:                                 end
152:                         end
153:                 end
154:                 
155:                 if ruby_engine == "jruby"
156:                         # For JRuby it's kinda useless to prepend "java" as extension
157:                         # architecture because JRuby doesn't allow any other extension
158:                         # architecture.
159:                         identifier = ""
160:                 else
161:                         identifier = "#{ruby_arch}-"
162:                 end
163:                 identifier << "#{ruby_engine}#{ruby_ext_version}-"
164:                 # If the extension architecture is the same as the OS architecture
165:                 # then there's no need to specify it twice.
166:                 if ruby_arch != os_arch
167:                         identifier << "#{os_arch}-"
168:                 end
169:                 identifier << "#{os_name}-#{os_runtime}"
170:                 return identifier
171:         end

Compiler flags that should be used for compiling every C/C++ program, for portability reasons. These flags should be specified as last when invoking the compiler.

[Source]

     # File lib/phusion_passenger/platform_info/compiler.rb, line 87
 87:         def self.portability_cflags
 88:                 flags = ["-D_REENTRANT -I/usr/local/include"]
 89:                 
 90:                 # Google SparseHash flags.
 91:                 # Figure out header for hash function object and its namespace.
 92:                 # Based on stl_hash.m4 and stl_hash_fun.m4 in the Google SparseHash sources.
 93:                 hash_namespace = nil
 94:                 ok = false
 95:                 ['__gnu_cxx', '', 'std', 'stdext'].each do |namespace|
 96:                         ['ext/hash_map', 'hash_map'].each do |hash_map_header|
 97:                                 ok = try_compile(:cxx, %Q{
 98:                                         #include <#{hash_map_header}>
 99:                                         int
100:                                         main() {
101:                                                 #{namespace}::hash_map<int, int> m;
102:                                                 return 0;
103:                                         }
104:                                 })
105:                                 if ok
106:                                         hash_namespace = namespace
107:                                         flags << "-DHASH_NAMESPACE=\"#{namespace}\""
108:                                 end
109:                         end
110:                         break if ok
111:                 end
112:                 ['ext/hash_fun.h', 'functional', 'tr1/functional',
113:                  'ext/stl_hash_fun.h', 'hash_fun.h', 'stl_hash_fun.h',
114:                  'stl/_hash_fun.h'].each do |hash_function_header|
115:                         ok = try_compile(:cxx, %Q{
116:                                 #include <#{hash_function_header}>
117:                                 int
118:                                 main() {
119:                                         #{hash_namespace}::hash<int>()(5);
120:                                         return 0;
121:                                 }
122:                         })
123:                         if ok
124:                                 flags << "-DHASH_FUN_H=\"<#{hash_function_header}>\""
125:                                 break
126:                         end
127:                 end
128:                 
129:                 if RUBY_PLATFORM =~ /solaris/
130:                         flags << '-pthreads'
131:                         flags << '-D_XOPEN_SOURCE=500 -D_XPG4_2 -D__EXTENSIONS__ -D__SOLARIS__ -D_FILE_OFFSET_BITS=64'
132:                         flags << '-DBOOST_HAS_STDINT_H' unless RUBY_PLATFORM =~ /solaris2.9/
133:                         flags << '-D__SOLARIS9__ -DBOOST__STDC_CONSTANT_MACROS_DEFINED' if RUBY_PLATFORM =~ /solaris2.9/
134:                         flags << '-mcpu=ultrasparc' if RUBY_PLATFORM =~ /sparc/
135:                 elsif RUBY_PLATFORM =~ /openbsd/
136:                         flags << '-DBOOST_HAS_STDINT_H -D_GLIBCPP__PTHREADS'
137:                 elsif RUBY_PLATFORM =~ /aix/
138:                         flags << '-DOXT_DISABLE_BACKTRACES'
139:                 elsif RUBY_PLATFORM =~ /(sparc-linux|arm-linux|^arm.*-linux|sh4-linux)/
140:                         # http://code.google.com/p/phusion-passenger/issues/detail?id=200
141:                         # http://groups.google.com/group/phusion-passenger/t/6b904a962ee28e5c
142:                         # http://groups.google.com/group/phusion-passenger/browse_thread/thread/aad4bd9d8d200561
143:                         flags << '-DBOOST_SP_USE_PTHREADS'
144:                 end
145:                 
146:                 flags << '-DHAS_SFENCE' if supports_sfence_instruction?
147:                 flags << '-DHAS_LFENCE' if supports_lfence_instruction?
148:                 
149:                 return flags.compact.join(" ").strip
150:         end

Linker flags that should be used for linking every C/C++ program, for portability reasons. These flags should be specified as last when invoking the linker.

[Source]

     # File lib/phusion_passenger/platform_info/compiler.rb, line 156
156:         def self.portability_ldflags
157:                 if RUBY_PLATFORM =~ /solaris/
158:                         result = '-lxnet -lrt -lsocket -lnsl -lpthread'
159:                 else
160:                         result = '-lpthread'
161:                 end
162:                 flags << ' -lmath' if has_math_library?
163:                 return result
164:         end

Returns the absolute path to the Rake executable that belongs to the current Ruby interpreter. Returns nil if it doesn‘t exist.

The return value may not be the actual correct invocation for Rake. Use rake_command for that.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 121
121:         def self.rake
122:                 return locate_ruby_tool('rake')
123:         end

Returns the correct command string for invoking the Rake executable that belongs to the current Ruby interpreter. Returns nil if Rake is not found.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 129
129:         def self.rake_command
130:                 filename = rake
131:                 # If the Rake executable is a Ruby program then we need to run
132:                 # it in the correct Ruby interpreter just in case Rake doesn't
133:                 # have the correct shebang line; we don't want a totally different
134:                 # Ruby than the current one to be invoked.
135:                 if filename && is_ruby_program?(filename)
136:                         return "#{ruby_command} #{filename}"
137:                 else
138:                         # If it's not a Ruby program then it's probably a wrapper
139:                         # script as is the case with e.g. RVM (~/.rvm/wrappers).
140:                         return filename
141:                 end
142:         end

Returns the absolute path to the RSpec runner program that belongs to the current Ruby interpreter. Returns nil if it doesn‘t exist.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 148
148:         def self.rspec
149:                 return locate_ruby_tool('spec')
150:         end

Returns correct command for invoking the current Ruby interpreter. In case of RVM this function will return the path to the RVM wrapper script that executes the current Ruby interpreter in the currently active gem set.

[Source]

    # File lib/phusion_passenger/platform_info/ruby.rb, line 48
48:         def self.ruby_command
49:                 if in_rvm?
50:                         name = rvm_ruby_string
51:                         dir = rvm_path
52:                         if name && dir
53:                                 filename = "#{dir}/wrappers/#{name}/ruby"
54:                                 if File.exist?(filename)
55:                                         contents = File.open(filename, 'rb') do |f|
56:                                                 f.read
57:                                         end
58:                                         # Old wrapper scripts reference $HOME which causes
59:                                         # things to blow up when run by a different user.
60:                                         if contents.include?("$HOME")
61:                                                 filename = nil
62:                                         end
63:                                 else
64:                                         filename = nil
65:                                 end
66:                                 if filename
67:                                         return filename
68:                                 else
69:                                         STDERR.puts "Your RVM wrapper scripts are too old. Please " +
70:                                                 "update them first by running 'rvm update --head && " +
71:                                                 "rvm reload && rvm repair all'."
72:                                         exit 1
73:                                 end
74:                         else
75:                                 # Something's wrong with the user's RVM installation.
76:                                 # Raise an error so that the user knows this instead of
77:                                 # having things fail randomly later on.
78:                                 # 'name' is guaranteed to be non-nil because rvm_ruby_string
79:                                 # already raises an exception on error.
80:                                 STDERR.puts "Your RVM installation appears to be broken: the RVM " +
81:                                         "path cannot be found. Please fix your RVM installation " +
82:                                         "or contact the RVM developers for support."
83:                                 exit 1
84:                         end
85:                 else
86:                         return ruby_executable
87:                 end
88:         end

Returns the full path to the current Ruby interpreter‘s executable file. This might not be the actual correct command to use for invoking the Ruby interpreter; use ruby_command instead.

[Source]

    # File lib/phusion_passenger/platform_info/ruby.rb, line 94
94:         def self.ruby_executable
95:                 @@ruby_executable ||=
96:                         Config::CONFIG['bindir'] + '/' + Config::CONFIG['RUBY_INSTALL_NAME'] + Config::CONFIG['EXEEXT']
97:         end

Returns an array of identifiers that describe the current Ruby interpreter‘s extension binary compatibility. A Ruby extension compiled for a certain Ruby interpreter can also be loaded on a different Ruby interpreter with the same binary compatibility identifiers.

The identifiers depend on the following factors:

  • Ruby engine name.
  • Ruby extension version. This is not the same as the Ruby language version, which identifies language-level compatibility. This is rather about binary compatibility of extensions. MRI seems to break source compatibility between tiny releases, though patchlevel releases tend to be source and binary compatible.
  • Ruby extension architecture. This is not necessarily the same as the operating system runtime architecture or the CPU architecture. For example, in case of JRuby, the extension architecture is just "java" because all extensions target the Java platform; the architecture the JVM was compiled for has no effect on compatibility. On systems with universal binaries support there may be multiple architectures. In this case the architecture is "universal" because extensions must be able to support all of the Ruby executable‘s architectures.
  • The operating system for which the Ruby interpreter was compiled.

[Source]

    # File lib/phusion_passenger/platform_info/binary_compatibility.rb, line 59
59:         def self.ruby_extension_binary_compatibility_ids
60:                 ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
61:                 ruby_ext_version = RUBY_VERSION
62:                 if RUBY_PLATFORM =~ /darwin/
63:                         if RUBY_PLATFORM =~ /universal/
64:                                 ruby_arch = "universal"
65:                         else
66:                                 # Something like:
67:                                 # "/opt/ruby-enterprise/bin/ruby: Mach-O 64-bit executable x86_64"
68:                                 ruby_arch = `file -L "#{ruby_executable}"`.strip
69:                                 ruby_arch.sub!(/.* /, '')
70:                         end
71:                 elsif RUBY_PLATFORM == "java"
72:                         ruby_arch = "java"
73:                 else
74:                         ruby_arch = cpu_architectures[0]
75:                 end
76:                 return [ruby_engine, ruby_ext_version, ruby_arch, os_name]
77:         end

Returns either ‘sudo’ or ‘rvmsudo’ depending on whether the current Ruby interpreter is managed by RVM.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 232
232:         def self.ruby_sudo_command
233:                 if in_rvm?
234:                         return "rvmsudo"
235:                 else
236:                         return "sudo"
237:                 end
238:         end

Returns whether the Ruby interpreter supports process forking.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 100
100:         def self.ruby_supports_fork?
101:                 # MRI >= 1.9.2's respond_to? returns false for methods
102:                 # that are not implemented.
103:                 return Process.respond_to?(:fork) &&
104:                         RUBY_ENGINE != "jruby" &&
105:                         RUBY_ENGINE != "macruby" &&
106:                         Config::CONFIG['target_os'] !~ /mswin|windows|mingw/
107:         end

If the current Ruby interpreter is managed by RVM, returns the directory in which RVM places its working files. Otherwise returns nil.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 162
162:         def self.rvm_path
163:                 if in_rvm?
164:                         [ENV['rvm_path'], "~/.rvm", "/usr/local/rvm"].each do |path|
165:                                 next if path.nil?
166:                                 path = File.expand_path(path)
167:                                 return path if File.directory?(path)
168:                         end
169:                         # Failure to locate the RVM path is probably caused by the
170:                         # user customizing $rvm_path. Older RVM versions don't
171:                         # export $rvm_path, making us unable to detect its value.
172:                         STDERR.puts "Unable to locate the RVM path. Your RVM installation " +
173:                                 "is probably too old. Please update it with " +
174:                                 "'rvm update --head && rvm reload && rvm repair all'."
175:                         exit 1
176:                 else
177:                         return nil
178:                 end
179:         end

If the current Ruby interpreter is managed by RVM, returns the RVM name which identifies the current Ruby interpreter plus the currently active gemset, e.g. something like this: "ruby-1.9.2-p0@mygemset"

Returns nil otherwise.

[Source]

     # File lib/phusion_passenger/platform_info/ruby.rb, line 188
188:         def self.rvm_ruby_string
189:                 if in_rvm?
190:                         # RVM used to export the necessary information through
191:                         # environment variables, but doesn't always do that anymore
192:                         # in the latest versions in order to fight env var pollution.
193:                         # Scanning $LOAD_PATH seems to be the only way to obtain
194:                         # the information.
195:                         
196:                         # Getting the RVM name of the Ruby interpreter ("ruby-1.9.2")
197:                         # isn't so hard, we can extract it from the #ruby_executable
198:                         # string. Getting the gemset name is a bit harder, so let's
199:                         # try various strategies...
200:                         
201:                         # $GEM_HOME usually contains the gem set name.
202:                         if GEM_HOME && GEM_HOME.include?("rvm/gems/")
203:                                 return File.basename(GEM_HOME)
204:                         end
205:                         
206:                         # User somehow managed to nuke $GEM_HOME. Extract info
207:                         # from $LOAD_PATH.
208:                         matching_path = $LOAD_PATH.find_all do |item|
209:                                 item.include?("rvm/gems/")
210:                         end
211:                         if matching_path
212:                                 subpath = matching_path.to_s.gsub(/^.*rvm\/gems\//, '')
213:                                 result = subpath.split('/').first
214:                                 return result if result
215:                         end
216:                         
217:                         # On Ruby 1.9, $LOAD_PATH does not contain any gem paths until
218:                         # at least one gem has been required so the above can fail.
219:                         # We're out of options now, we can't detect the gem set.
220:                         # Raise an exception so that the user knows what's going on
221:                         # instead of having things fail in obscure ways later.
222:                         STDERR.puts "Unable to autodetect the currently active RVM gem " +
223:                                 "set name. Please contact this program's author for support."
224:                         exit 1
225:                 end
226:                 return nil
227:         end

Returns whether the OS‘s main CPU architecture supports the x86/x86_64 lfence instruction.

[Source]

     # File lib/phusion_passenger/platform_info/operating_system.rb, line 144
144:         def self.supports_lfence_instruction?
145:                 arch = cpu_architectures[0]
146:                 return arch == "x86_64" || (arch == "x86" &&
147:                         try_compile_and_run(:c, %Q{
148:                                 int
149:                                 main() {
150:                                         __asm__ __volatile__ ("lfence" ::: "memory");
151:                                         return 0;
152:                                 }
153:                         }))
154:         end

Returns whether the OS‘s main CPU architecture supports the x86/x86_64 sfence instruction.

[Source]

     # File lib/phusion_passenger/platform_info/operating_system.rb, line 129
129:         def self.supports_sfence_instruction?
130:                 arch = cpu_architectures[0]
131:                 return arch == "x86_64" || (arch == "x86" &&
132:                         try_compile_and_run(:c, %Q{
133:                                 int
134:                                 main() {
135:                                         __asm__ __volatile__ ("sfence" ::: "memory");
136:                                         return 0;
137:                                 }
138:                         }))
139:         end

[Source]

     # File lib/phusion_passenger/platform_info.rb, line 163
163:         def self.tmpdir
164:                 result = ENV['TMPDIR']
165:                 if result && !result.empty?
166:                         return result.sub(/\/+\Z/, '')
167:                 else
168:                         return '/tmp'
169:                 end
170:         end

Returns the directory in which test executables should be placed. The returned directory is guaranteed to be writable and guaranteed to not be mounted with the ‘noexec’ option. If no such directory can be found then it will raise a PlatformInfo::RuntimeError with an appropriate error message.

[Source]

     # File lib/phusion_passenger/platform_info.rb, line 178
178:         def self.tmpexedir
179:                 basename = "test-exe.#{Process.pid}.#{Thread.current.object_id}"
180:                 attempts = []
181:                 
182:                 dir = tmpdir
183:                 filename = "#{dir}/#{basename}"
184:                 begin
185:                         File.open(filename, 'w').close
186:                         File.chmod(0700, filename)
187:                         if File.executable?(filename)
188:                                 return dir
189:                         else
190:                                 attempts << { :dir => dir,
191:                                         :error => "This directory's filesystem is mounted with the 'noexec' option." }
192:                         end
193:                 rescue Errno::ENOENT
194:                         attempts << { :dir => dir, :error => "This directory doesn't exist." }
195:                 rescue Errno::EACCES
196:                         attempts << { :dir => dir, :error => "This program doesn't have permission to write to this directory." }
197:                 rescue SystemCallError => e
198:                         attempts << { :dir => dir, :error => e.message }
199:                 ensure
200:                         File.unlink(filename) rescue nil
201:                 end
202:                 
203:                 dir = Dir.pwd
204:                 filename = "#{dir}/#{basename}"
205:                 begin
206:                         File.open(filename, 'w').close
207:                         File.chmod(0700, filename)
208:                         if File.executable?(filename)
209:                                 return dir
210:                         else
211:                                 attempts << { :dir => dir,
212:                                         :error => "This directory's filesystem is mounted with the 'noexec' option." }
213:                         end
214:                 rescue Errno::ENOENT
215:                         attempts << { :dir => dir, :error => "This directory doesn't exist." }
216:                 rescue Errno::EACCES
217:                         attempts << { :dir => dir, :error => "This program doesn't have permission to write to this directory." }
218:                 rescue SystemCallError => e
219:                         attempts << { :dir => dir, :error => e.message }
220:                 ensure
221:                         File.unlink(filename) rescue nil
222:                 end
223:                 
224:                 message = "In order to run certain tests, this program " +
225:                         "must be able to write temporary\n" +
226:                         "executable files to some directory. However no such " +
227:                         "directory can be found. \n" +
228:                         "The following directories have been tried:\n\n"
229:                 attempts.each do |attempt|
230:                         message << " * #{attempt[:dir]}\n"
231:                         message << "   #{attempt[:error]}\n"
232:                 end
233:                 message << "\nYou can solve this problem by telling this program what directory to write\n" <<
234:                         "temporary executable files to.\n" <<
235:                         "\n" <<
236:                         "  Set the $TMPDIR environment variable to the desired directory's filename and\n" <<
237:                         "  re-run this program.\n" <<
238:                         "\n" <<
239:                         "Notes:\n" <<
240:                         "\n" <<
241:                         " * If you're using 'sudo'/'rvmsudo', remember that 'sudo'/'rvmsudo' unsets all\n" <<
242:                         "   environment variables, so you must set the environment variable *after*\n" <<
243:                         "   having gained root privileges.\n" <<
244:                         " * The directory you choose must writeable and must not be mounted with the\n" <<
245:                         "   'noexec' option."
246:                 raise RuntimeError, message
247:         end

[Source]

    # File lib/phusion_passenger/platform_info/zlib.rb, line 29
29:         def self.zlib_flags
30:                 return nil
31:         end

[Source]

    # File lib/phusion_passenger/platform_info/zlib.rb, line 33
33:         def self.zlib_libs
34:                 return '-lz'
35:         end

[Validate]