670 lines
22 KiB
Ruby
670 lines
22 KiB
Ruby
# Phusion Passenger - https://www.phusionpassenger.com/
|
|
# Copyright (c) 2010-2025 Asynchronous B.V.
|
|
#
|
|
# "Passenger", "Phusion Passenger" and "Union Station" are registered
|
|
# trademarks of Asynchronous B.V.
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
|
|
PhusionPassenger.require_passenger_lib 'platform_info'
|
|
PhusionPassenger.require_passenger_lib 'platform_info/operating_system'
|
|
|
|
module PhusionPassenger
|
|
|
|
module PlatformInfo
|
|
private
|
|
def self.detect_language_extension(language)
|
|
case language
|
|
when :c
|
|
return "c"
|
|
when :cxx
|
|
return "cpp"
|
|
else
|
|
raise ArgumentError, "Unsupported language #{language.inspect}"
|
|
end
|
|
end
|
|
private_class_method :detect_language_extension
|
|
|
|
def self.detect_compiler_type_name(language)
|
|
case language
|
|
when :c
|
|
return "C"
|
|
when :cxx
|
|
return "C++"
|
|
else
|
|
raise ArgumentError, "Unsupported language #{language.inspect}"
|
|
end
|
|
end
|
|
private_class_method :detect_compiler_type_name
|
|
|
|
def self.create_compiler_command(language, flags1, flags2, link = false)
|
|
case language
|
|
when :c
|
|
result = [cc, link ? ENV['EXTRA_PRE_LDFLAGS'] : nil,
|
|
ENV['EXTRA_PRE_CFLAGS'], flags1, flags2, ENV['EXTRA_CFLAGS'],
|
|
ENV['EXTRA_LDFLAGS']]
|
|
when :cxx
|
|
result = [cxx, link ? ENV['EXTRA_PRE_LDFLAGS'] : nil,
|
|
ENV['EXTRA_PRE_CXXFLAGS'], flags1, flags2, ENV['EXTRA_CXXFLAGS'],
|
|
ENV['EXTRA_LDFLAGS']]
|
|
else
|
|
raise ArgumentError, "Unsupported language #{language.inspect}"
|
|
end
|
|
return result.compact.join(" ").strip
|
|
end
|
|
private_class_method :create_compiler_command
|
|
|
|
def self.run_compiler(description, command, source_file, source, capture_output = false)
|
|
if verbose?
|
|
message = "#{description}\n" <<
|
|
"Running: #{command}\n"
|
|
if source.strip.empty?
|
|
message << "Source file is empty."
|
|
else
|
|
message << "Source file contains:\n" <<
|
|
"-------------------------\n" <<
|
|
unindent(source) <<
|
|
"\n-------------------------"
|
|
end
|
|
log(message)
|
|
end
|
|
if capture_output
|
|
begin
|
|
output = `#{command} 2>&1`
|
|
result = $?.exitstatus == 0
|
|
rescue SystemCallError => e
|
|
result = nil
|
|
exec_error_reason = e.message
|
|
end
|
|
log("Output:\n" <<
|
|
"-------------------------\n" <<
|
|
output.to_s <<
|
|
"\n-------------------------")
|
|
elsif verbose?
|
|
result = system(command)
|
|
else
|
|
result = system("(#{command}) >/dev/null 2>/dev/null")
|
|
end
|
|
if result.nil?
|
|
log("Command could not be executed! #{exec_error_reason}".strip)
|
|
return false
|
|
elsif result
|
|
log("Check succeeded")
|
|
if capture_output
|
|
return { :result => true, :output => output }
|
|
else
|
|
return true
|
|
end
|
|
else
|
|
log("Check failed with exit status #{$?.exitstatus}")
|
|
if capture_output == :always
|
|
return { :result => false, :output => output }
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
private_class_method :run_compiler
|
|
|
|
def self.cc_or_cxx_supports_feliminate_unused_debug?(language)
|
|
ext = detect_language_extension(language)
|
|
compiler_type_name = detect_compiler_type_name(language)
|
|
create_temp_file("passenger-compile-check.#{ext}") do |filename, f|
|
|
f.close
|
|
begin
|
|
command = create_compiler_command(language,
|
|
"-c '#{filename}' -o '#{filename}.o'",
|
|
'-feliminate-unused-debug-symbols -feliminate-unused-debug-types')
|
|
result = run_compiler("Checking for #{compiler_type_name} compiler '-feliminate-unused-debug-{symbols,types}' support",
|
|
command, filename, '', true)
|
|
return result && result[:output].empty?
|
|
ensure
|
|
File.unlink("#{filename}.o") rescue nil
|
|
end
|
|
end
|
|
end
|
|
private_class_method :cc_or_cxx_supports_feliminate_unused_debug?
|
|
|
|
def self.cc_or_cxx_supports_blocks?(language)
|
|
command = create_compiler_command(language,"-E -dM",'- </dev/null')
|
|
result = `#{command}`
|
|
return result.include? "__BLOCKS__"
|
|
end
|
|
private_class_method :cc_or_cxx_supports_blocks?
|
|
|
|
public
|
|
def self.cc
|
|
return string_env('CC', default_cc)
|
|
end
|
|
memoize :cc
|
|
|
|
def self.cxx
|
|
return string_env('CXX', default_cxx)
|
|
end
|
|
memoize :cxx
|
|
|
|
def self.default_cc
|
|
# On most platforms, we'll want to use the same compiler as what the rest
|
|
# of the system uses, so that we generate compatible binaries. That's
|
|
# most likely the 'cc' command. We used to use 'gcc' by default.
|
|
#
|
|
# See for example this issue with OS X Mavericks (10.9). They switched from
|
|
# GCC to Clang as the default compiler. Since the Nginx by default uses 'cc'
|
|
# as the compiler, we'll have to do that too. Otherwise we'll get C++ linker
|
|
# errors because Nginx is compiled with Clang while Phusion Passenger is
|
|
# compiled with GCC.
|
|
# https://code.google.com/p/phusion-passenger/issues/detail?id=950
|
|
if PlatformInfo.find_command('cc')
|
|
return 'cc'
|
|
else
|
|
return 'gcc'
|
|
end
|
|
end
|
|
|
|
def self.default_cxx
|
|
if PlatformInfo.find_command('c++')
|
|
return 'c++'
|
|
else
|
|
return 'g++'
|
|
end
|
|
end
|
|
|
|
def self.cc_is_gcc?
|
|
`#{cc} -v 2>&1` =~ /gcc version/
|
|
end
|
|
memoize :cc_is_gcc?
|
|
|
|
def self.cxx_is_gcc?
|
|
`#{cxx} -v 2>&1` =~ /gcc version/
|
|
end
|
|
memoize :cxx_is_gcc?
|
|
|
|
def self.cc_is_clang?
|
|
`#{cc} --version 2>&1` =~ /clang( version|-)/
|
|
end
|
|
memoize :cc_is_clang?
|
|
|
|
def self.cxx_is_clang?
|
|
`#{cxx} --version 2>&1` =~ /clang( version|-)/
|
|
end
|
|
memoize :cxx_is_clang?
|
|
|
|
def self.cc_is_sun_studio?
|
|
`#{cc} -V 2>&1` =~ /Sun C/ || `#{cc} -flags 2>&1` =~ /Sun C/
|
|
end
|
|
memoize :cc_is_sun_studio?
|
|
|
|
def self.cxx_is_sun_studio?
|
|
`#{cxx} -V 2>&1` =~ /Sun C/ || `#{cxx} -flags 2>&1` =~ /Sun C/
|
|
end
|
|
memoize :cxx_is_sun_studio?
|
|
|
|
|
|
# Looks for the given C or C++ header. This works by invoking the compiler and
|
|
# searching in the compiler's header search path. Returns its full filename,
|
|
# or true if this function knows that the header exists but can't find it (e.g.
|
|
# because the compiler cannot tell us what its header search path is).
|
|
# Returns nil if the header cannot be found.
|
|
def self.find_header(header_name, language, flags = nil)
|
|
extension = detect_language_extension(language)
|
|
create_temp_file("passenger-compile-check.#{extension}") do |filename, f|
|
|
source = %Q{
|
|
#include <#{header_name}>
|
|
}
|
|
f.puts(source)
|
|
f.close
|
|
begin
|
|
command = create_compiler_command(language,
|
|
"-v -c '#{filename}' -o '#{filename}.o'",
|
|
flags)
|
|
if result = run_compiler("Checking for #{header_name}", command, filename, source, true)
|
|
result[:output] =~ /^#include <...> search starts here:$(.+?)^End of search list\.$/m
|
|
search_paths = $1.to_s.strip.split("\n").map{ |line| line.strip }
|
|
search_paths.each do |dir|
|
|
if File.file?("#{dir}/#{header_name}")
|
|
return "#{dir}/#{header_name}"
|
|
end
|
|
end
|
|
return true
|
|
else
|
|
return nil
|
|
end
|
|
ensure
|
|
File.unlink("#{filename}.o") rescue nil
|
|
end
|
|
end
|
|
end
|
|
|
|
def self.try_compile(description, language, source, flags = nil)
|
|
extension = detect_language_extension(language)
|
|
create_temp_file("passenger-compile-check.#{extension}") do |filename, f|
|
|
f.puts(source)
|
|
f.close
|
|
command = create_compiler_command(language,
|
|
"-c '#{filename}' -o '#{filename}.o'",
|
|
flags)
|
|
return run_compiler(description, command, filename, source)
|
|
end
|
|
end
|
|
|
|
# Like try_compile, but designed for checking whether a warning flag is
|
|
# supported. Compilers sometimes do not error out upon encountering an
|
|
# unsupported warning flag, but merely print a warning. This method checks
|
|
# for that too.
|
|
def self.try_compile_with_warning_flag(description, language, source, flags = nil)
|
|
extension = detect_language_extension(language)
|
|
result = nil
|
|
create_temp_file("passenger-compile-check.#{extension}") do |filename, f|
|
|
f.puts(source)
|
|
f.close
|
|
command = create_compiler_command(language,
|
|
"-c '#{filename}' -o '#{filename}.o'",
|
|
flags)
|
|
result = run_compiler(description, command, filename, source, true)
|
|
result = result && result[:result] && result[:output] !~ /unknown warning option|unrecognized command line option/i
|
|
end
|
|
return false if !result
|
|
|
|
# For some reason, GCC does not complain about a warning flag
|
|
# not being supported unless the source contains another error. So we
|
|
# check for this.
|
|
create_temp_file("passenger-compile-check.#{extension}") do |filename, f|
|
|
source = %Q{
|
|
void foo() {
|
|
return error;
|
|
}
|
|
}
|
|
f.puts(source)
|
|
f.close
|
|
command = create_compiler_command(language,
|
|
"-c '#{filename}' -o '#{filename}.o'",
|
|
flags)
|
|
result = run_compiler("#{description} (really)", command, filename, source, :always)
|
|
end
|
|
result && !result[:output].include?(flags)
|
|
end
|
|
|
|
def self.try_link(description, language, source, flags = nil)
|
|
extension = detect_language_extension(language)
|
|
create_temp_file("passenger-link-check.#{extension}") do |filename, f|
|
|
f.puts(source)
|
|
f.close
|
|
command = create_compiler_command(language,
|
|
"'#{filename}' -o '#{filename}.out'",
|
|
flags, true)
|
|
return run_compiler(description, command, filename, source)
|
|
end
|
|
end
|
|
|
|
def self.try_compile_and_run(description, language, source, flags = nil)
|
|
extension = detect_language_extension(language)
|
|
create_temp_file("passenger-run-check.#{extension}", tmpexedir) do |filename, f|
|
|
f.puts(source)
|
|
f.close
|
|
command = create_compiler_command(language,
|
|
"'#{filename}' -o '#{filename}.out'",
|
|
flags, true)
|
|
if run_compiler(description, command, filename, source)
|
|
log("Running #{filename}.out")
|
|
begin
|
|
output = `'#{filename}.out' 2>&1`
|
|
rescue SystemCallError => e
|
|
log("Command failed: #{e}")
|
|
return false
|
|
end
|
|
status = $?.exitstatus
|
|
log("Command exited with status #{status}. Output:\n--------------\n#{output}\n--------------")
|
|
return status == 0
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
# Checks whether the compiler supports "-arch #{arch}".
|
|
def self.compiler_supports_architecture?(arch)
|
|
return try_compile("Checking for C compiler '-arch' support",
|
|
:c, '', "-arch #{arch}")
|
|
end
|
|
|
|
def self.cc_supports_visibility_flag?
|
|
return false if os_name_simple == "aix"
|
|
return try_compile("Checking for C compiler '-fvisibility' support",
|
|
:c, '', '-fvisibility=hidden')
|
|
end
|
|
memoize :cc_supports_visibility_flag?, true
|
|
|
|
def self.cc_supports_fno_limit_debug_info_flag?
|
|
try_compile_with_warning_flag(
|
|
"Checking for C compiler '-fno-limit-debug-info' support",
|
|
:c, '', '-fno-limit-debug-info')
|
|
end
|
|
memoize :cc_supports_fno_limit_debug_info_flag?
|
|
|
|
def self.cc_supports_fno_optimize_sibling_calls_flag?
|
|
try_compile_with_warning_flag(
|
|
"Checking for C compiler '-fno-optimize-sibling-calls' support",
|
|
:c, '', '-fno-optimize-sibling-calls')
|
|
end
|
|
memoize :cc_supports_fno_optimize_sibling_calls_flag?
|
|
|
|
def self.cxx_supports_visibility_flag?
|
|
return false if os_name_simple == "aix"
|
|
return try_compile("Checking for C++ compiler '-fvisibility' support",
|
|
:cxx, '', '-fvisibility=hidden')
|
|
end
|
|
memoize :cxx_supports_visibility_flag?, true
|
|
|
|
def self.cc_supports_wno_attributes_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C compiler '-Wno-attributes' support",
|
|
:c, '', '-Wno-attributes')
|
|
end
|
|
memoize :cc_supports_wno_attributes_flag?, true
|
|
|
|
def self.cxx_supports_wno_attributes_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-Wno-attributes' support",
|
|
:cxx, '', '-Wno-attributes')
|
|
end
|
|
memoize :cxx_supports_wno_attributes_flag?, true
|
|
|
|
def self.cc_supports_wno_missing_field_initializers_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C compiler '-Wno-missing-field-initializers' support",
|
|
:c, '', '-Wno-missing-field-initializers')
|
|
end
|
|
memoize :cc_supports_wno_missing_field_initializers_flag?, true
|
|
|
|
def self.cxx_supports_wno_missing_field_initializers_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-Wno-missing-field-initializers' support",
|
|
:cxx, '', '-Wno-missing-field-initializers')
|
|
end
|
|
memoize :cxx_supports_wno_missing_field_initializers_flag?, true
|
|
|
|
def self.cc_supports_wno_unknown_pragmas_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C compiler '-Wno-unknown-pragmas' support",
|
|
:c, '', '-Wno-unknown-pragmas')
|
|
end
|
|
memoize :cc_supports_wno_unknown_pragmas_flag?, true
|
|
|
|
def self.cxx_supports_wno_unknown_pragmas_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-Wno-unknown-pragmas' support",
|
|
:cxx, '', '-Wno-unknown-pragmas')
|
|
end
|
|
memoize :cxx_supports_wno_unknown_pragmas_flag?, true
|
|
|
|
def self.cxx_supports_wno_unused_local_typedefs_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-Wno-unused-local-typedefs' support",
|
|
:cxx, '', '-Wno-unused-local-typedefs')
|
|
end
|
|
memoize :cxx_supports_wno_unused_local_typedefs_flag?, true
|
|
|
|
def self.cxx_supports_wno_format_nonliteral_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-Wno-format-nonliteral' support",
|
|
:cxx, '', '-Wno-format-nonliteral')
|
|
end
|
|
memoize :cxx_supports_wno_format_nonliteral_flag?, true
|
|
|
|
def self.cxx_supports_fno_limit_debug_info_flag?
|
|
try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-fno-limit-debug-info' support",
|
|
:cxx, '', '-fno-limit-debug-info')
|
|
end
|
|
memoize :cxx_supports_fno_limit_debug_info_flag?
|
|
|
|
def self.cxx_supports_fno_optimize_sibling_calls_flag?
|
|
try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-fno-optimize-sibling-calls' support",
|
|
:cxx, '', '-fno-optimize-sibling-calls')
|
|
end
|
|
memoize :cxx_supports_fno_optimize_sibling_calls_flag?
|
|
|
|
def self.cc_supports_no_tls_direct_seg_refs_option?
|
|
return try_compile("Checking for C compiler '-mno-tls-direct-seg-refs' support",
|
|
:c, '', '-mno-tls-direct-seg-refs')
|
|
end
|
|
memoize :cc_supports_no_tls_direct_seg_refs_option?, true
|
|
|
|
def self.cxx_supports_no_tls_direct_seg_refs_option?
|
|
return try_compile("Checking for C++ compiler '-mno-tls-direct-seg-refs' support",
|
|
:cxx, '', '-mno-tls-direct-seg-refs')
|
|
end
|
|
memoize :cxx_supports_no_tls_direct_seg_refs_option?, true
|
|
|
|
def self.compiler_supports_wno_ambiguous_member_template?
|
|
try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-Wno-ambiguous-member-template' support",
|
|
:cxx, '', '-Wno-ambiguous-member-template')
|
|
end
|
|
memoize :compiler_supports_wno_ambiguous_member_template?, true
|
|
|
|
def self.cc_supports_feliminate_unused_debug?
|
|
return cc_or_cxx_supports_feliminate_unused_debug?(:c)
|
|
end
|
|
memoize :cc_supports_feliminate_unused_debug?, true
|
|
|
|
def self.cxx_supports_feliminate_unused_debug?
|
|
return cc_or_cxx_supports_feliminate_unused_debug?(:cxx)
|
|
end
|
|
memoize :cxx_supports_feliminate_unused_debug?, true
|
|
|
|
def self.cc_block_support_ok?
|
|
return (os_name_simple != 'macosx' || cc_or_cxx_supports_blocks?(:c) || os_version >= "10.13" )
|
|
end
|
|
memoize :cc_block_support_ok?, true
|
|
|
|
def self.cxx_block_support_ok?
|
|
return (os_name_simple != 'macosx' || cc_or_cxx_supports_blocks?(:cxx) || os_version >= "10.13" )
|
|
end
|
|
memoize :cxx_block_support_ok?, true
|
|
|
|
def self.cxx_supports_wno_vla_cxx_extension_flag?
|
|
return try_compile_with_warning_flag(
|
|
"Checking for C++ compiler '-Wno-vla-cxx-extension' support",
|
|
:cxx, '', '-Wno-vla-cxx-extension')
|
|
end
|
|
memoize :cxx_supports_wno_vla_cxx_extension_flag?, true
|
|
|
|
# Returns whether compiling C++ with -fvisibility=hidden might result
|
|
# in tons of useless warnings, like this:
|
|
# http://code.google.com/p/phusion-passenger/issues/detail?id=526
|
|
# This appears to be a bug in older g++ versions:
|
|
# http://gcc.gnu.org/ml/gcc-patches/2006-07/msg00861.html
|
|
# Warnings should be suppressed with -Wno-attributes.
|
|
def self.cc_visibility_flag_generates_warnings?
|
|
if os_name_simple == "linux" && `#{cc} -v 2>&1` =~ /gcc version (.*?)/
|
|
return $1 <= "4.1.2"
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
memoize :cc_visibility_flag_generates_warnings?, true
|
|
|
|
def self.cxx_visibility_flag_generates_warnings?
|
|
if os_name_simple == "linux" && `#{cxx} -v 2>&1` =~ /gcc version (.*?)/
|
|
return $1 <= "4.1.2"
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
memoize :cxx_visibility_flag_generates_warnings?, true
|
|
|
|
def self.address_sanitizer_flags
|
|
if cc_is_clang?
|
|
if `#{cc} --help` =~ /-fsanitize=/
|
|
"-fsanitize=address -fsanitize-address-use-after-return=always"
|
|
else
|
|
"-faddress-sanitizer"
|
|
end
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
def self.undefined_behavior_sanitizer_flags
|
|
if cc_is_clang?
|
|
"-fsanitize=undefined"
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
def self.cxx_14_flag
|
|
source = %{
|
|
struct Foo {
|
|
Foo(Foo &&f) { }
|
|
};
|
|
}
|
|
if try_compile("Checking for C++ -std=gnu++14 compiler flag", :cxx, source, '-std=gnu++14')
|
|
return "-std=gnu++14"
|
|
elsif try_compile("Checking for C++ -std=c++14 compiler flag", :cxx, source, '-std=c++14')
|
|
return "-std=c++14"
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
memoize :cxx_14_flag, true
|
|
|
|
def self.has_rt_library?
|
|
return try_link("Checking for -lrt support",
|
|
:c, "int main() { return 0; }\n", '-lrt')
|
|
end
|
|
memoize :has_rt_library?, true
|
|
|
|
def self.has_math_library?
|
|
return try_link("Checking for -lmath support",
|
|
:c, "int main() { return 0; }\n", '-lmath')
|
|
end
|
|
memoize :has_math_library?, true
|
|
|
|
def self.has_dl_library?
|
|
return try_link("Checking for -ldl support",
|
|
:c, "int main() { return 0; }\n", '-ldl')
|
|
end
|
|
memoize :has_dl_library?, true
|
|
|
|
def self.has_accept4?
|
|
return try_compile("Checking for accept4()", :c, %Q{
|
|
#define _GNU_SOURCE
|
|
#include <sys/socket.h>
|
|
static void *foo = accept4;
|
|
})
|
|
end
|
|
memoize :has_accept4?, true
|
|
|
|
# C compiler flags that should be passed in order to enable debugging information.
|
|
def self.debugging_cflags
|
|
# According to OpenBSD's pthreads man page, pthreads do not work
|
|
# correctly when an app is compiled with -g. It recommends using
|
|
# -ggdb instead.
|
|
#
|
|
# In any case we'll always want to use -ggdb for better GDB debugging.
|
|
if cc_is_gcc?
|
|
result = '-ggdb'
|
|
else
|
|
result = '-g'
|
|
end
|
|
if cc_supports_fno_limit_debug_info_flag?
|
|
result << ' -fno-limit-debug-info'
|
|
end
|
|
result
|
|
end
|
|
|
|
# C++ compiler flags that should be passed in order to enable debugging information.
|
|
def self.debugging_cxxflags
|
|
# According to OpenBSD's pthreads man page, pthreads do not work
|
|
# correctly when an app is compiled with -g. It recommends using
|
|
# -ggdb instead.
|
|
#
|
|
# In any case we'll always want to use -ggdb for better GDB debugging.
|
|
if cxx_is_gcc?
|
|
result = '-ggdb'
|
|
else
|
|
result = '-g'
|
|
end
|
|
if cxx_supports_fno_limit_debug_info_flag?
|
|
result << ' -fno-limit-debug-info'
|
|
end
|
|
result
|
|
end
|
|
|
|
def self.export_dynamic_flags
|
|
if os_name_simple == "linux"
|
|
return '-rdynamic'
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
def self.precompiled_header_extension
|
|
if cxx_is_gcc?
|
|
'gch'
|
|
else
|
|
'pch'
|
|
end
|
|
end
|
|
|
|
|
|
def self.make
|
|
return string_env('MAKE', find_command('make'))
|
|
end
|
|
memoize :make, true
|
|
|
|
def self.gnu_make
|
|
if result = string_env('GMAKE')
|
|
return result
|
|
else
|
|
result = find_command('gmake')
|
|
if !result
|
|
result = find_command('make')
|
|
if result
|
|
if `#{result} --version 2>&1` =~ /GNU/
|
|
return result
|
|
else
|
|
return nil
|
|
end
|
|
else
|
|
return nil
|
|
end
|
|
else
|
|
return result
|
|
end
|
|
end
|
|
end
|
|
memoize :gnu_make, true
|
|
|
|
def self.xcode_select_version
|
|
if find_command('xcode-select')
|
|
`xcode-select --version` =~ /version (.+)\./
|
|
return $1
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
end
|
|
|
|
end # module PhusionPassenger
|