diff --git a/.gitignore b/.gitignore index 0ac7805e..92449eb4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ lib/libv8/VERSION /ext/libv8/.location.yml /release/**/libv8 /release/**/.vagrant +/vendor/.gclient +/vendor/.gclient_entries +/vendor/v8/ diff --git a/.gitmodules b/.gitmodules index 61469545..37ac743d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "vendor/v8"] - path = vendor/v8 - url = https://github.com/v8/v8.git -[submodule "vendor/gyp"] - path = vendor/gyp - url = https://chromium.googlesource.com/external/gyp.git +[submodule "vendor/depot_tools"] + path = vendor/depot_tools + url = https://chromium.googlesource.com/chromium/tools/depot_tools.git diff --git a/.rspec b/.rspec new file mode 100644 index 00000000..1e6da830 --- /dev/null +++ b/.rspec @@ -0,0 +1,3 @@ +--format documentation +--color +--warnings \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 9d025246..ff16881b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,42 @@ +language: ruby rvm: + - 2.2.2 + - 2.1.2 - 2.0.0 - - 2.1.5 - 1.9.3 - - rbx -bundler_args: --jobs=1 --retry=3 + - rbx-2 +matrix: + include: + - rvm: ruby-2.2.2-clang + env: CXX=clang++ + - rvm: ruby-head + - rvm: ruby-head-clang + env: CXX=clang++ + - rvm: ree + - rvm: ruby-1.8.7 + allow_failures: + - rvm: ree + - rvm: ruby-1.8.7 + - rvm: ruby-head + - rvm: ruby-head-clang + fast_finish: true +bundler_args: -j4 --retry=3 +script: + - MAKEFLAGS+=-j8 bundle exec rake spec build binary --trace + - MAKEFLAGS+=-j8 travis_wait gem install pkg/*.gem notifications: recipients: - cowboyd@thefrontside.net - bordjukov@gmail.com -before_install: - - sudo apt-get update - - sudo apt-get install git-svn +cache: bundler +sudo: false +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.8 + - g++-4.8 + - clang +env: + - CXX=g++-4.8 diff --git a/README.md b/README.md index efa5c608..1fb493b3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # libv8 [![Gem Version](https://badge.fury.io/rb/libv8.svg)](http://badge.fury.io/rb/libv8) [![Build Status](https://travis-ci.org/cowboyd/libv8.svg?branch=master)](https://travis-ci.org/cowboyd/libv8) -[![Build status](https://ci.appveyor.com/api/projects/status/ugeqff972kxlba5j?svg=true)](https://ci.appveyor.com/project/cowboyd/libv8) + [![Join the chat at https://gitter.im/cowboyd/therubyracer](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/cowboyd/therubyracer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) A gem for distributing the v8 runtime libraries and headers in both @@ -22,16 +22,11 @@ opens the door for supporting Windows. That depends on your platform. Right now, we support the following platforms. -* x86_64-darwin10.7.0 -* x86_64-darwin-10 -* x86_64-darwin-11 -* x86_64-darwin-12 -* x86_64-darwin-13 +* x86_64-darwin-14 * x86_64-linux * x86-linux -* x86_64-freebsd-9 * x86_64-freebsd-10 -* x86_64-solaris-2.11 +* i386-freebsd-10 If you don't see your platform on this list, first, make sure that it installs from source, and second talk to us about setting up a binary @@ -64,6 +59,16 @@ distribution > This step release system is a workaround to carlhuda/bundler#1537 +### Requirements + +Building the v8 library from source imposes the following requirements: + +* A compiler that supports C++11 (such as GCC 4.8 and above or clang, +preferably 3.5 and above) +* GNU Make +* Python 2 +* git-svn + ### Using a git version If you want to use the latest unstable version of the gem you can do @@ -79,15 +84,14 @@ You can find more info on using a git repo as a gem source in ### What if I can't install from source? -If you can fix the "Makefile" so that it correctly compiles for your +If you can fix v8's build system so that it correctly compiles for your platform, we'll pull it right in! To get the source, these commands will get you started: - git clone git://github.com/cowboyd/libv8.git + git clone --recursive git://github.com/cowboyd/libv8.git cd libv8 bundle install - bundle exec rake checkout bundle exec rake compile ### Bring your own V8 @@ -106,9 +110,15 @@ Using Bundler (in your Gemfile): bundle config build.libv8 --with-system-v8 +#### Gotchas + Please note that if you intend to run your own V8, you must install both V8 *and its headers* (found in libv8-dev for Debian distros). +Also keep in mind that v8's API does not tend to be stable and you need to make +sure that the version of therubyracer you intend to use is compatible with the +version of v8 present on your system. Otherwise therubyracer's build will fail. + ### Bring your own compiler You can specify a compiler of your choice by either setting the `CXX` diff --git a/Rakefile b/Rakefile index 3696a27f..e049211a 100644 --- a/Rakefile +++ b/Rakefile @@ -1,112 +1,83 @@ require 'bundler/setup' -Bundler::GemHelper.install_tasks -class Bundler::GemHelper - def clean? - sh_with_code('git diff --exit-code --ignore-submodules')[1] == 0 - end -end - require 'rspec/core/rake_task' -RSpec::Core::RakeTask.new(:spec) - -require File.expand_path '../ext/libv8/make.rb', __FILE__ -require File.expand_path '../ext/libv8/checkout.rb', __FILE__ -include Libv8::Make -include Libv8::Checkout -desc "setup the vendored v8 source to correspond to the libv8 gem version" -task :checkout do - sh "git submodule update --init" - checkout! -end - -desc "compile v8 via the ruby extension mechanism" -task :compile => :devkit do - sh "ruby ext/libv8/extconf.rb" -end +Bundler::GemHelper.install_tasks +RSpec::Core::RakeTask.new :spec -desc "manually invoke the GYP compile. Useful for seeing debug output" -task :manual_compile do - require File.expand_path '../ext/libv8/arch.rb', __FILE__ - include Libv8::Arch - Dir.chdir(V8_Source) do - sh %Q{#{make} -j2 #{libv8_arch}.release ARFLAGS.target=crs} +module Helpers + module_function + def binary_gemspec(platform = Gem::Platform.local) + gemspec = eval(File.read 'libv8.gemspec') + gemspec.platform = platform + gemspec end -end -def get_binary_gemspec(platform = RUBY_PLATFORM) - gemspec = eval(File.read('libv8.gemspec')) - gemspec.platform = Gem::Platform.new(platform) - gemspec + def binary_gem_name(platform = Gem::Platform.local) + File.basename binary_gemspec(platform).cache_file + end end -begin - binary_gem_name = File.basename get_binary_gemspec.cache_file -rescue - binary_gem_name = '' +desc "compile v8 via the ruby extension mechanism" +task :compile do + sh "ruby ext/libv8/extconf.rb" end -desc "build a binary gem #{binary_gem_name}" +desc "build a binary gem #{Helpers.binary_gem_name}" task :binary => :compile do - gemspec = get_binary_gemspec + gemspec = Helpers.binary_gemspec gemspec.extensions.clear + # We don't need most things for the binary gemspec.files = [] gemspec.files += ['lib/libv8.rb', 'lib/libv8/version.rb'] gemspec.files += ['ext/libv8/arch.rb', 'ext/libv8/location.rb', 'ext/libv8/paths.rb'] gemspec.files += ['ext/libv8/.location.yml'] + # V8 - gemspec.files += Dir['vendor/v8/include/*'] + gemspec.files += Dir['vendor/v8/include/**/*.h'] gemspec.files += Dir['vendor/v8/out/**/*.a'] - FileUtils.chmod 'a+r', gemspec.files + + FileUtils.chmod 0644, gemspec.files FileUtils.mkdir_p 'pkg' + package = if Gem::VERSION < '2.0.0' Gem::Builder.new(gemspec).build else require 'rubygems/package' - Gem::Package.build(gemspec) + Gem::Package.build gemspec end - FileUtils.mv(package, 'pkg') -end -desc "clean up artifacts of the build" -task :clean do - sh "rm -rf pkg" - sh "git clean -df" - sh "cd #{V8_Source} && git checkout -f && git clean -dxf" - if Dir.chdir GYP_Source - sh "git checkout -f" - puts "git clean -dxf" - `git clean -dxf` - end -end - -task :devkit do - begin - if RUBY_PLATFORM =~ /mingw/ - require "devkit" - end - rescue LoadError => e - abort "Failed to activate RubyInstaller's DevKit required for compilation." - end + FileUtils.mv package, 'pkg' end namespace :build do - ['x86_64-linux', 'x86-linux'].each do |arch| + ['x86_64-linux', 'x86-linux', 'x86_64-freebsd10'].each do |arch| desc "build binary gem for #{arch}" task arch do arch_dir = Pathname(__FILE__).dirname.join("release/#{arch}") Dir.chdir(arch_dir) do sh "vagrant up" - sh "vagrant ssh -c 'cd /vagrant && rm -rf libv8 && git clone /libv8/.git libv8'" - sh "vagrant ssh -c 'cd /vagrant/libv8 && bundle install --path vendor/bundle'" - sh "vagrant ssh -c 'cd /vagrant/libv8 && bundle exec rake checkout binary'" - sh "vagrant ssh -c 'cp /vagrant/libv8/pkg/*.gem /vagrant'" + sh "vagrant ssh -c 'rm -rf libv8 && git clone --recursive /libv8/.git libv8'" + sh "vagrant ssh -c 'cd libv8 && bundle install --path vendor/bundle'" + sh "vagrant ssh -c 'cd libv8 && bundle exec rake binary'" + sh "vagrant ssh -c 'cp libv8/pkg/*.gem /vagrant'" end end end +end + +task :clean_submodules do + sh "git submodule --quiet foreach git reset --hard" + sh "git submodule --quiet foreach git clean -dxf" + sh "git submodule update --init" +end +desc "clean up artifacts of the build" +task :clean => [:clean_submodules] do + sh "rm -rf pkg" + sh "rm -rf vendor/v8" + sh "git clean -dxf -e .bundle -e vendor/bundle" end -task :default => [:checkout, :compile, :spec] -task :build => [:clean, :checkout] +task :default => [:compile, :spec] +task :build => [:clean] diff --git a/appveyor.yml b/appveyor.yml.disabled similarity index 100% rename from appveyor.yml rename to appveyor.yml.disabled diff --git a/ext/libv8/arch.rb b/ext/libv8/arch.rb index 17ac37ca..cc6862cd 100644 --- a/ext/libv8/arch.rb +++ b/ext/libv8/arch.rb @@ -1,42 +1,18 @@ -require 'rbconfig' +require 'rubygems' module Libv8 module Arch module_function - def x86_64_from_build_cpu - RbConfig::MAKEFILE_CONFIG['build_cpu'] == 'x86_64' - end - - def x86_64_from_byte_length - ['foo'].pack('p').size == 8 - end - - def x86_64_from_arch_flag - RbConfig::MAKEFILE_CONFIG['ARCH_FLAG'] =~ /x86_64/ - end - - def rubinius? - Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE == "rbx" - end - - # TODO fix false positive on 64-bit ARM - def x64? - if rubinius? - x86_64_from_build_cpu || x86_64_from_arch_flag - else - x86_64_from_byte_length - end - end - - def arm? - RbConfig::MAKEFILE_CONFIG['build_cpu'] =~ /^arm/ - end - def libv8_arch - if arm? then "arm" - elsif x64? then "x64" - else "ia32" + case Gem::Platform.local.cpu + when /^arm$/ then 'arm' + when /^a(rm|arch)64$/ then 'arm64' + when /^x86$/ then 'ia32' + when /^(x86_64|amd64)$/ then 'x64' + else + warn "Unsupported target: #{Gem::Platform.local.cpu}" + Gem::Platform.local.cpu end end end diff --git a/ext/libv8/builder.rb b/ext/libv8/builder.rb old mode 100755 new mode 100644 index b672ac5d..1fd622b8 --- a/ext/libv8/builder.rb +++ b/ext/libv8/builder.rb @@ -1,15 +1,17 @@ +unless $:.include? File.expand_path("../../../lib", __FILE__) + $:.unshift File.expand_path("../../../lib", __FILE__) +end require 'mkmf' +require 'libv8/version' require File.expand_path '../compiler', __FILE__ require File.expand_path '../arch', __FILE__ require File.expand_path '../make', __FILE__ -require File.expand_path '../checkout', __FILE__ require File.expand_path '../patcher', __FILE__ module Libv8 class Builder include Libv8::Arch include Libv8::Make - include Libv8::Checkout include Libv8::Patcher def initialize @@ -20,23 +22,20 @@ def make_target profile = enable_config('debug') ? 'debug' : 'release' "#{libv8_arch}.#{profile}" end - - def make_flags(*flags) - # FreeBSD uses gcc 4.2 by default which leads to - # compilation failures due to warnings about aliasing. - # http://svnweb.freebsd.org/ports/head/lang/v8/Makefile?view=markup - flags << "strictaliasing=off" if @compiler.is_a?(Compiler::GCC) and @compiler.version < '4.4' - # Avoid compilation failures on the Raspberry Pi. - flags << "vfp2=off vfp3=on" if @compiler.target.include? "arm" + def gyp_defines(*defines) + # Do not use an external snapshot as we don't really care for binary size + defines << 'v8_use_external_startup_data=0' + + # Pass clang flag to GYP in order to work around GCC compilation failures + defines << "clang=#{@compiler.is_a?(Compiler::Clang) ? '1' : '0'}" - # FIXME: Determine when to activate this instead of leaving it on by - # default. - flags << "hardfp=on" if @compiler.target.include? "arm" + "GYP_DEFINES=\"#{defines.join ' '}\"" + end - # Fix Malformed archive issue caused by GYP creating thin archives by - # default. - flags << "ARFLAGS.target=crs" + def make_flags(*flags) + # Disable i18n + flags << 'i18nsupport=off' # Solaris / Smart OS requires additional -G flag to use with -fPIC flags << "CFLAGS=-G" if @compiler.target =~ /solaris/ @@ -45,28 +44,24 @@ def make_flags(*flags) # with it on flags << 'werror=no' + # Append GYP variable definitions + flags << gyp_defines + "#{make_target} #{flags.join ' '}" end def build_libv8! - Dir.chdir(V8_Source) do + setup_python! + setup_build_deps! + Dir.chdir(File.expand_path('../../../vendor/v8', __FILE__)) do fail 'No compilers available' if @compiler.nil? - checkout! - setup_python! - setup_build_deps! - patch! *patch_directories_for(@compiler) + patch! print_build_info + puts 'Beginning compilation. This will take some time.' - case RUBY_PLATFORM - when /mingw/ - # use a script that will fix the paths in the generated Makefiles - # don't use make_flags otherwise it will trigger a rebuild of the Makefiles - system "env CXX=#{@compiler} LINK=#{@compiler} bash #{PATCH_DIRECTORY}/mingw-generate-makefiles.sh" - system "env CXX=#{@compiler} LINK=#{@compiler} make #{make_target}" - - else - puts `env CXX=#{@compiler} LINK=#{@compiler} #{make} #{make_flags}` - end + command = "env CXX=#{@compiler} LINK=#{@compiler} #{make} #{make_flags}" + puts "Building v8 with #{command}" + system command end return $?.exitstatus end @@ -85,11 +80,33 @@ def setup_python! end end + ## + # The release tag to checkout. If this is version 4.5.95.0 of the libv8 gem, + # then this will be 4.5.95 + # + def source_version + Libv8::VERSION.gsub(/\.\d+$/, '') + end + + ## + # Checkout all of the V8 source and its dependencies using the + # chromium depot tools. + # + # https://chromium.googlesource.com/v8/v8.git#Getting-the-Code + # def setup_build_deps! - # This uses the Git mirror of the svn repository used by - # "make dependencies", instead of calling that make target - `rm -rf build/gyp` - `ln -fs #{GYP_Source} build/gyp` + ENV['PATH'] = "#{File.expand_path('../../../vendor/depot_tools', __FILE__)}:#{ENV['PATH']}" + Dir.chdir(File.expand_path('../../../vendor', __FILE__)) do + system "fetch v8" or fail "unable to fetch v8 source" + Dir.chdir('v8') do + system "git checkout Makefile" # Work around a weird bug on FreeBSD + unless system "git checkout #{source_version}" + fail "unable to checkout source for v8 #{source_version}" + end + system "gclient sync" or fail "could not sync v8 build dependencies" + system "git checkout Makefile" # Work around a weird bug on FreeBSD + end + end end private @@ -97,7 +114,7 @@ def setup_build_deps! def choose_compiler compiler_names = if with_config('cxx') then [with_config('cxx')] elsif ENV['CXX'] then [ENV['CXX']] - else Compiler::KNOWN_COMPILERS + else Compiler::well_known_compilers end available_compilers = Compiler.available_compilers(*compiler_names) @@ -109,8 +126,8 @@ def choose_compiler end def python_version - if `which python` =~ /python/ - `python -c "import platform; print(platform.python_version())"`.chomp + if system 'which python 2>&1 > /dev/null' + `python -c 'import platform; print(platform.python_version())'`.chomp else "not available" end @@ -124,7 +141,7 @@ def print_build_info puts "Using compiler: #{@compiler} (#{@compiler.name} version #{@compiler.version})" unless @compiler.compatible? warn "Unable to find a compiler officially supported by v8." - warn "It is recommended to use GCC v4.4 or higher" + warn "It is recommended to use clang v3.5 or GCC v4.8 or higher" end end end diff --git a/ext/libv8/checkout.rb b/ext/libv8/checkout.rb deleted file mode 100644 index b7102a39..00000000 --- a/ext/libv8/checkout.rb +++ /dev/null @@ -1,52 +0,0 @@ -require File.expand_path '../../../lib/libv8/version.rb', __FILE__ - -module Libv8 - module Checkout - module_function - - GYP_SVN = 'http://gyp.googlecode.com/svn' - V8_Source = File.expand_path '../../../vendor/v8', __FILE__ - GYP_Source = File.expand_path '../../../vendor/gyp', __FILE__ - - def checkout! - # When compiling from a source gem, it's not a git repository anymore and - # we assume the right code is already checked out. - return unless git?(V8_Source) - - Dir.chdir(V8_Source) do - `git fetch` - `git checkout #{Libv8::VERSION.gsub(/\.\d+(\.rc\d+)?$/,'')} -f` - `rm -f .applied_patches` - end - - return unless git?(GYP_Source) - - check_git_svn! - - Dir.chdir(GYP_Source) do - mkf = File.readlines(File.join(V8_Source, 'Makefile')) - idx = mkf.index {|l| l =~ /#{GYP_SVN}/} + 1 - rev = /--revision (\d+)/.match(mkf[idx])[1] - `git fetch` - # --git-dir is needed for older versions of git and git-svn - `git --git-dir=../../.git/modules/vendor/gyp/ svn init #{GYP_SVN} -Ttrunk` - `git config --replace-all svn-remote.svn.fetch trunk:refs/remotes/origin/master` - svn_rev = `git --git-dir=../../.git/modules/vendor/gyp/ svn find-rev r#{rev} | tail -n 1`.chomp - `git checkout #{svn_rev} -f` - end - end - - def git?(dir) - File.exist?(File.join(dir, '.git')) - end - - def check_git_svn! - # msysgit provides git svn - return if RUBY_PLATFORM =~ /mingw/ - - unless system 'git help svn 2>&1 > /dev/null' - fail "git-svn not installed!\nPlease install git-svn." - end - end - end -end diff --git a/ext/libv8/compiler.rb b/ext/libv8/compiler.rb old mode 100755 new mode 100644 index ee18bcb9..8159911f --- a/ext/libv8/compiler.rb +++ b/ext/libv8/compiler.rb @@ -1,42 +1,66 @@ -require 'mkmf' -require 'open3' +require 'rbconfig' require File.expand_path '../compiler/generic_compiler', __FILE__ require File.expand_path '../compiler/gcc', __FILE__ require File.expand_path '../compiler/clang', __FILE__ +require File.expand_path '../compiler/apple_llvm', __FILE__ module Libv8 module Compiler - KNOWN_COMPILERS = [ - 'c++', - 'g++48', 'g++46', 'g++44', 'g++', - 'clang++', - ] - module_function - def system_compilers - available_compilers *Compiler::KNOWN_COMPILERS + def well_known_compilers + compilers = [] + + # The command Ruby was compiled with + compilers << RbConfig::CONFIG['CXX'] + + # The default system compiler + compilers << 'c++' + + # FreeBSD GCC command names + compilers += ['g++48', 'g++49', 'g++5'] + + # Default compiler names + compilers += ['clang++', 'g++'] + + compilers.uniq end def available_compilers(*compiler_names) - compiler_paths = compiler_names.map { |name| find name }.reject &:nil? + available = compiler_names.select { |compiler_name| available? compiler_name } + available.map { |compiler_name| type_of(compiler_name).new compiler_name } end - def find(name) - return nil if name.empty? - path, _, status = Open3.capture3 "which #{name}" - path.chomp! - determine_type(path).new(path) if status.success? + def type_of(compiler_name) + case version_string_of(compiler_name) + when /^Apple LLVM\b/ then AppleLLVM + when /\bclang\b/i then Clang + when /^gcc/i then GCC + else GenericCompiler + end end - def determine_type(compiler_path) - compiler_version = Open3.capture3("#{compiler_path} -v")[0..1].join + def version_string_of(compiler_name) + command_result = execute_command "#{compiler_name} -v 2>&1" - case compiler_version - when /\bclang\b/i then Clang - when /^gcc/i then GCC - else GenericCompiler + unless command_result.status.success? + raise "Could not get version string of compiler #{compiler_name}" end + + command_result.output + end + + def available?(command) + execute_command("which #{command} 2>&1").status.success? + end + + def execute_command(command) + output = `env LC_ALL=C LANG=C #{command}` + status = $? + ExecutionResult.new output, status + end + + class ExecutionResult < Struct.new(:output, :status) end end end diff --git a/ext/libv8/compiler/apple_llvm.rb b/ext/libv8/compiler/apple_llvm.rb new file mode 100644 index 00000000..0dcb2998 --- /dev/null +++ b/ext/libv8/compiler/apple_llvm.rb @@ -0,0 +1,21 @@ +module Libv8 + module Compiler + class AppleLLVM < Clang + LLVM_VERSION_REGEXP = /Apple LLVM version (\d+\.\d+(\.\d+)*) \(/i + + def name + 'Apple LLVM' + end + + def compatible? + version >= '4.3' unless version.nil? + end + + private + + def version_regexp + LLVM_VERSION_REGEXP + end + end + end +end diff --git a/ext/libv8/compiler/clang.rb b/ext/libv8/compiler/clang.rb index da84878f..8e988157 100644 --- a/ext/libv8/compiler/clang.rb +++ b/ext/libv8/compiler/clang.rb @@ -1,14 +1,20 @@ module Libv8 module Compiler class Clang < GenericCompiler - VERSION_REGEXP = /clang version (\d+\.\d+(\.\d+)*) \(/i + CLANG_VERSION_REGEXP = /clang version (\d+\.\d+(\.\d+)*) \(/i def name 'clang' end def compatible? - version >= '3.1' + version >= '3.1' unless version.nil? + end + + private + + def version_regexp + CLANG_VERSION_REGEXP end end end diff --git a/ext/libv8/compiler/gcc.rb b/ext/libv8/compiler/gcc.rb index 937321bc..f781483f 100644 --- a/ext/libv8/compiler/gcc.rb +++ b/ext/libv8/compiler/gcc.rb @@ -1,14 +1,20 @@ module Libv8 module Compiler class GCC < GenericCompiler - VERSION_REGEXP = /gcc version (\d+\.\d+(\.\d+)*)/i + GCC_VERSION_REGEXP = /gcc version (\d+\.\d+(\.\d+)*)/i def name 'GCC' end def compatible? - version > '4.3' and version < '5' + version > '4.7' unless version.nil? + end + + private + + def version_regexp + GCC_VERSION_REGEXP end end end diff --git a/ext/libv8/compiler/generic_compiler.rb b/ext/libv8/compiler/generic_compiler.rb index e4e66754..7588ff93 100644 --- a/ext/libv8/compiler/generic_compiler.rb +++ b/ext/libv8/compiler/generic_compiler.rb @@ -1,28 +1,28 @@ module Libv8 module Compiler class GenericCompiler - VERSION_REGEXP = /(\d+\.\d+(\.\d+)*)/ - TARGET_REGEXP = /Target: ([a-z0-9\-_.]*)/ + GENERIC_VERSION_REGEXP = /(\d+\.\d+(\.\d+)*)/ + GENERIC_TARGET_REGEXP = /Target: ([a-z0-9\-_.]*)/ - def initialize(path) - @path = path + def initialize(command) + @command = command end def name - File.basename @path + File.basename @command end def to_s - @path + @command end def version - call('-v')[0..1].join =~ VERSION_REGEXP + version_string =~ version_regexp $1 end def target - call('-v')[0..1].join =~ TARGET_REGEXP + version_string =~ target_regexp $1 end @@ -31,7 +31,25 @@ def compatible? end def call(*arguments) - Open3.capture3 arguments.unshift('env LC_ALL=en', @path).join(' ') + Compiler::execute_command arguments.unshift(@command).join(' ') + end + + private + + def version_string + begin + Compiler::version_string_of @command + rescue StandardError + nil + end + end + + def version_regexp + GENERIC_VERSION_REGEXP + end + + def target_regexp + GENERIC_TARGET_REGEXP end end end diff --git a/ext/libv8/location.rb b/ext/libv8/location.rb index f8972dab..ddb63b27 100644 --- a/ext/libv8/location.rb +++ b/ext/libv8/location.rb @@ -32,11 +32,15 @@ def configure(context = MkmfContext.new) end def verify_installation! + include_paths = Libv8::Paths.include_paths + unless include_paths.detect { |p| Pathname(p).join('include/v8.h').exist? } + fail HeaderNotFound, "Unable to locate 'include/v8.h' in the libv8 header paths: #{include_paths.inspect}" + end Libv8::Paths.object_paths.each do |p| fail ArchiveNotFound, p unless File.exist? p end end - + class HeaderNotFound < StandardError; end class ArchiveNotFound < StandardError def initialize(filename) super "libv8 did not install properly, expected binary v8 archive '#{filename}'to exist, but it was not found" @@ -48,6 +52,7 @@ class System < Location def configure(context = MkmfContext.new) context.send(:dir_config, 'v8') context.send(:find_header, 'v8.h') or fail NotFoundError + context.send(:find_header, 'libplatform/libplatform.h') or fail NotFoundError context.send(:have_library, 'v8') or fail NotFoundError end diff --git a/ext/libv8/patcher.rb b/ext/libv8/patcher.rb index 6f555d82..a811b4b5 100644 --- a/ext/libv8/patcher.rb +++ b/ext/libv8/patcher.rb @@ -4,50 +4,15 @@ module Patcher module_function - def patch_directories_for(compiler) - patch_directories = [] - - case - when compiler.target =~ /arm/ - patch_directories << 'arm' - end - - case compiler - when Compiler::GCC - patch_directories << 'gcc48' if compiler.version >= '4.8' - when Compiler::Clang - patch_directories << 'clang' - patch_directories << 'clang33' if compiler.version >= '3.3' - patch_directories << 'clang51' if compiler.version >= '5.1' - end - - patch_directories - end - - def patch_directories(*additional_directories) - absolute_paths = [PATCH_DIRECTORY] - - additional_directories.each do |directory| - absolute_paths << File.join(PATCH_DIRECTORY, directory) - end - - absolute_paths.uniq - end - - def patches(*additional_directories) - patch_directories(*additional_directories).map do |directory| - Dir.glob(File.join directory, '*.patch') - end.flatten.sort - end - - def patch!(*additional_directories) + def patch! File.open(".applied_patches", File::RDWR|File::CREAT) do |f| - available_patches = patches *additional_directories + available_patches = Dir.glob(File.join(PATCH_DIRECTORY, '*.patch')) applied_patches = f.readlines.map(&:chomp) (available_patches - applied_patches).each do |patch| + puts "Applying #{patch}" `patch -p1 -N < #{patch}` - fail 'failed to apply patch' unless $?.success? + fail "failed to apply patch #{patch}" unless $?.success? f.puts patch end end diff --git a/ext/libv8/paths.rb b/ext/libv8/paths.rb index 12eccddd..ec403f59 100644 --- a/ext/libv8/paths.rb +++ b/ext/libv8/paths.rb @@ -7,12 +7,12 @@ module Paths module_function def include_paths - [Shellwords.escape("#{vendored_source_path}/include")] + [Shellwords.escape(vendored_source_path)] end def object_paths - [libv8_object(:base), libv8_object(:snapshot)].map do |path| - Shellwords.escape path + [:base, :libplatform, :libbase, :snapshot].map do |name| + Shellwords.escape libv8_object(name) end end diff --git a/lib/libv8/version.rb b/lib/libv8/version.rb index afb9674d..075efb88 100644 --- a/lib/libv8/version.rb +++ b/lib/libv8/version.rb @@ -1,3 +1,3 @@ module Libv8 - VERSION = "3.16.14.11" + VERSION = "4.5.95.5" end diff --git a/libv8.gemspec b/libv8.gemspec index d5aa7ab2..278a54be 100644 --- a/libv8.gemspec +++ b/libv8.gemspec @@ -1,4 +1,3 @@ -# -*- encoding: utf-8 -*- $:.unshift File.expand_path("../lib", __FILE__) require "libv8/version" @@ -15,14 +14,13 @@ Gem::Specification.new do |s| s.rubyforge_project = "libv8" - s.files = `git ls-files`.split("\n") - s.files += Dir.chdir("vendor/v8") do - `git ls-files`.split("\n").reject {|f| f =~ /^out/}.map {|f| "vendor/v8/#{f}"} - end - s.files += Dir['vendor/v8/build/**/*'] - s.files += Dir.chdir("vendor/gyp") do - `git ls-files`.split("\n").map {|f| "vendor/gyp/#{f}"} + + submodules = `git submodule --quiet foreach 'echo $path'`.split("\n").map(&:chomp) + submodules.each do |submodule| + s.files += Dir.chdir(submodule) do + `git ls-files`.split("\n").reject {|f| f =~ /^test/}.map {|f| "#{submodule}/#{f}"} + end end s.extensions = ["ext/libv8/extconf.rb"] @@ -30,6 +28,5 @@ Gem::Specification.new do |s| s.add_development_dependency 'rake', '~> 10' s.add_development_dependency 'rake-compiler', '~> 0' - s.add_development_dependency 'rspec', '~> 2' - s.add_development_dependency 'rspec-spies', '~> 2' + s.add_development_dependency 'rspec', '~> 3' end diff --git a/patches/arm/do-not-imply-vfp3-and-armv7.patch b/patches/arm/do-not-imply-vfp3-and-armv7.patch deleted file mode 100644 index 891ab35c..00000000 --- a/patches/arm/do-not-imply-vfp3-and-armv7.patch +++ /dev/null @@ -1,16 +0,0 @@ -diff --git a/build/standalone.gypi b/build/standalone.gypi -index 125c5bf..9900c5b 100644 ---- a/build/standalone.gypi -+++ b/build/standalone.gypi -@@ -77,9 +77,9 @@ - }], - ], - # Default ARM variable settings. -- 'armv7%': 1, -+ 'armv7%': 0, - 'arm_neon%': 0, -- 'arm_fpu%': 'vfpv3', -+ 'arm_fpu%': 'vfp', - }, - 'target_defaults': { - 'default_configuration': 'Debug', diff --git a/patches/arm/do-not-use-vfp2.patch b/patches/arm/do-not-use-vfp2.patch deleted file mode 100644 index 7b413a46..00000000 --- a/patches/arm/do-not-use-vfp2.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/build/common.gypi b/build/common.gypi -index 3a59639..594abe4 100644 ---- a/build/common.gypi -+++ b/build/common.gypi -@@ -173,7 +173,6 @@ - [ 'v8_use_arm_eabi_hardfloat=="true"', { - 'defines': [ - 'USE_EABI_HARDFLOAT=1', -- 'CAN_USE_VFP2_INSTRUCTIONS', - ], - 'target_conditions': [ - ['_toolset=="target"', { - diff --git a/patches/build-standalone-static-library.patch b/patches/build-standalone-static-library.patch new file mode 100644 index 00000000..994c3224 --- /dev/null +++ b/patches/build-standalone-static-library.patch @@ -0,0 +1,14 @@ +diff --git a/build/standalone.gypi b/build/standalone.gypi +index b6519c4..ef9e7c5 100644 +--- a/build/standalone.gypi ++++ b/build/standalone.gypi +@@ -373,6 +373,9 @@ + }], + ], + 'target_conditions': [ ++ ['_type=="static_library"', { ++ 'standalone_static_library': 1, ++ }], + ['v8_code == 0', { + 'defines!': [ + 'DEBUG', diff --git a/patches/clang/no-unused-private-field.patch b/patches/clang/no-unused-private-field.patch deleted file mode 100644 index cf844323..00000000 --- a/patches/clang/no-unused-private-field.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/build/common.gypi b/build/common.gypi -index 3a59639..14bf0f9 100644 ---- a/build/common.gypi -+++ b/build/common.gypi -@@ -376,7 +376,8 @@ - }], - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { - 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', -- '-Wnon-virtual-dtor', '-Woverloaded-virtual' ], -+ '-Wnon-virtual-dtor', '-Woverloaded-virtual', -+ '-Wno-unused-private-field' ], - }], - ['OS=="linux" and v8_enable_backtrace==1', { - # Support for backtrace_symbols. -diff --git a/build/standalone.gypi b/build/standalone.gypi -index 125c5bf..c8d9b4f 100644 ---- a/build/standalone.gypi -+++ b/build/standalone.gypi -@@ -98,7 +98,8 @@ - 'target_defaults': { - 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', - '-Wnon-virtual-dtor', '-pthread', '-fno-rtti', -- '-fno-exceptions', '-pedantic' ], -+ '-fno-exceptions', '-pedantic', -+ '-Wno-unused-private-field' ], - 'ldflags': [ '-pthread', ], - 'conditions': [ - [ 'OS=="linux"', { diff --git a/patches/clang33/silence-nested-anon-types-and-unused-function-warnings.patch b/patches/clang33/silence-nested-anon-types-and-unused-function-warnings.patch deleted file mode 100644 index b3957515..00000000 --- a/patches/clang33/silence-nested-anon-types-and-unused-function-warnings.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/build/common.gypi b/build/common.gypi -index 14bf0f9..301109a 100644 ---- a/build/common.gypi -+++ b/build/common.gypi -@@ -377,7 +377,8 @@ - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { - 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', - '-Wnon-virtual-dtor', '-Woverloaded-virtual', -- '-Wno-unused-private-field' ], -+ '-Wno-unused-private-field', '-Wno-nested-anon-types', -+ '-Wno-unused-function' ], - }], - ['OS=="linux" and v8_enable_backtrace==1', { - # Support for backtrace_symbols. -diff --git a/build/standalone.gypi b/build/standalone.gypi -index c8d9b4f..ddd1693 100644 ---- a/build/standalone.gypi -+++ b/build/standalone.gypi -@@ -99,7 +99,8 @@ - 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', - '-Wnon-virtual-dtor', '-pthread', '-fno-rtti', - '-fno-exceptions', '-pedantic', -- '-Wno-unused-private-field' ], -+ '-Wno-unused-private-field', '-Wno-nested-anon-types', -+ '-Wno-unused-function' ], - 'ldflags': [ '-pthread', ], - 'conditions': [ - [ 'OS=="linux"', { diff --git a/patches/clang51/no-unused-variable.patch b/patches/clang51/no-unused-variable.patch deleted file mode 100644 index 3b39349c..00000000 --- a/patches/clang51/no-unused-variable.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/build/standalone.gypi b/build/standalone.gypi -index 125c5bf..a283a28 100644 ---- a/build/standalone.gypi -+++ b/build/standalone.gypi -@@ -210,6 +212,7 @@ - '-Wendif-labels', - '-W', - '-Wno-unused-parameter', -+ '-Wno-unused-variable', - '-Wnon-virtual-dtor', - ], - }, diff --git a/patches/disable-building-tests.patch b/patches/disable-building-tests.patch index a9f25552..1854a9b7 100644 --- a/patches/disable-building-tests.patch +++ b/patches/disable-building-tests.patch @@ -1,25 +1,27 @@ diff --git a/Makefile b/Makefile -index 0cdae4b..2bf8aa5 100644 +index 9761265..80169b2 100644 --- a/Makefile +++ b/Makefile -@@ -153,7 +153,7 @@ ANDROID_ARCHES = android_ia32 android_arm - # List of files that trigger Makefile regeneration: - GYPFILES = build/all.gyp build/common.gypi build/standalone.gypi \ - preparser/preparser.gyp samples/samples.gyp src/d8.gyp \ -- test/cctest/cctest.gyp tools/gyp/v8.gyp -+ tools/gyp/v8.gyp - - # Generates all combinations of ARCHES and MODES, e.g. "ia32.release". - BUILDS = $(foreach mode,$(MODES),$(addsuffix .$(mode),$(ARCHES))) +@@ -248,8 +248,6 @@ NACL_ARCHES = nacl_ia32 nacl_x64 + GYPFILES = third_party/icu/icu.gypi third_party/icu/icu.gyp \ + build/shim_headers.gypi build/features.gypi build/standalone.gypi \ + build/toolchain.gypi build/all.gyp build/mac/asan.gyp \ +- test/cctest/cctest.gyp \ +- test/unittests/unittests.gyp tools/gyp/v8.gyp \ + tools/parser-shell.gyp testing/gmock.gyp testing/gtest.gyp \ + buildtools/third_party/libc++abi/libc++abi.gyp \ + buildtools/third_party/libc++/libc++.gyp samples/samples.gyp \ diff --git a/build/all.gyp b/build/all.gyp -index 4b2fe52..9885678 100644 +index 4aeb507..1ff2c7a 100644 --- a/build/all.gyp +++ b/build/all.gyp -@@ -11,7 +11,6 @@ - '../preparser/preparser.gyp:*', +@@ -10,8 +10,6 @@ + 'dependencies': [ '../samples/samples.gyp:*', '../src/d8.gyp:d8', - '../test/cctest/cctest.gyp:*', +- '../test/unittests/unittests.gyp:*', ], - } - ] + 'conditions': [ + ['component!="shared_library"', { + diff --git a/patches/fPIC-for-static.patch b/patches/fPIC-for-static.patch index 3e588f0a..39564772 100644 --- a/patches/fPIC-for-static.patch +++ b/patches/fPIC-for-static.patch @@ -1,13 +1,13 @@ diff --git a/build/standalone.gypi b/build/standalone.gypi -index 125c5bf..71641a3 100644 +index 7670e5b..230518c 100644 --- a/build/standalone.gypi +++ b/build/standalone.gypi -@@ -107,7 +107,7 @@ +@@ -205,7 +205,7 @@ [ 'visibility=="hidden" and v8_enable_backtrace==0', { 'cflags': [ '-fvisibility=hidden' ], }], - [ 'component=="shared_library"', { -+ [ 'component=="shared_library" or component=="static_library" and v8_target_arch=="x64" or v8_target_arch=="arm"', { ++ [ 'component=="shared_library" or component=="static_library" and (v8_target_arch=="x64" or v8_target_arch=="arm64")', { 'cflags': [ '-fPIC', ], }], ], diff --git a/patches/gcc48/gcc48-wno-unused-local-typedefs.patch b/patches/gcc48/gcc48-wno-unused-local-typedefs.patch deleted file mode 100644 index d45276da..00000000 --- a/patches/gcc48/gcc48-wno-unused-local-typedefs.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/build/common.gypi b/build/common.gypi -index 3a59639..365178a 100644 ---- a/build/common.gypi -+++ b/build/common.gypi -@@ -376,7 +376,8 @@ - }], - ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { - 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', -- '-Wnon-virtual-dtor', '-Woverloaded-virtual' ], -+ '-Wnon-virtual-dtor', '-Woverloaded-virtual', -+ '-Wno-unused-local-typedefs' ], - }], - ['OS=="linux" and v8_enable_backtrace==1', { - # Support for backtrace_symbols. -diff --git a/build/standalone.gypi b/build/standalone.gypi -index 125c5bf..32eaf85 100644 ---- a/build/standalone.gypi -+++ b/build/standalone.gypi -@@ -98,7 +98,8 @@ - 'target_defaults': { - 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', - '-Wnon-virtual-dtor', '-pthread', '-fno-rtti', -- '-fno-exceptions', '-pedantic' ], -+ '-fno-exceptions', '-pedantic', -+ '-Wno-unused-local-typedefs' ], - 'ldflags': [ '-pthread', ], - 'conditions': [ - [ 'OS=="linux"', { diff --git a/release/x86-linux/Vagrantfile b/release/x86-linux/Vagrantfile index be2221b4..1848475e 100644 --- a/release/x86-linux/Vagrantfile +++ b/release/x86-linux/Vagrantfile @@ -66,10 +66,14 @@ Vagrant.configure(2) do |config| # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the # documentation for more information about their specific syntax and use. config.vm.provision "shell", inline: <<-SHELL - sudo apt-get update - sudo apt-get install -y gcc-4.8 g++-4.8 build-essential git git-svn python ruby ruby-dev - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8 - sudo update-alternatives --config gcc - gem install bundler + apt-get update + apt-get install -y gcc-4.8 g++-4.8 build-essential git git-svn python ruby ruby-dev emacs + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8 + update-alternatives --config gcc + su -c 'gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3' - vagrant + su -c '\\curl -sSL https://get.rvm.io | bash -s stable' - vagrant + su -c 'rvm install 2.2.2 --disable-binary' - vagrant + su -c 'rvm --default use 2.2.2' - vagrant + su -c 'gem install bundler' - vagrant SHELL end diff --git a/release/x86_64-freebsd10/Vagrantfile b/release/x86_64-freebsd10/Vagrantfile new file mode 100644 index 00000000..e0a4fe3f --- /dev/null +++ b/release/x86_64-freebsd10/Vagrantfile @@ -0,0 +1,79 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# All Vagrant configuration is done below. The "2" in Vagrant.configure +# configures the configuration version (we support older styles for +# backwards compatibility). Please don't change it unless you know what +# you're doing. +Vagrant.configure(2) do |config| + # The most common configuration options are documented and commented below. + # For a complete reference, please see the online documentation at + # https://docs.vagrantup.com. + + # Every Vagrant development environment requires a box. You can search for + # boxes at https://atlas.hashicorp.com/search. + config.vm.box = "ignisf/freebsd10.1" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + # config.vm.network "forwarded_port", guest: 80, host: 8080 + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + config.vm.network "private_network", ip: "10.0.1.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + #config.vm.synced_folder ".", "/vagrant", type: :rsync + #config.vm.synced_folder "../..", "/libv8", type: :rsync + + config.vm.synced_folder ".", "/vagrant", nfs: true + config.vm.synced_folder "../..", "/libv8", nfs: true + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + # config.vm.provider "virtualbox" do |vb| + # # Display the VirtualBox GUI when booting the machine + # vb.gui = true + # + # # Customize the amount of memory on the VM: + # vb.memory = "1024" + # end + # + # View the documentation for the provider you are using for more + # information on available options. + + # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies + # such as FTP and Heroku are also available. See the documentation at + # https://docs.vagrantup.com/v2/push/atlas.html for more information. + # config.push.define "atlas" do |push| + # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" + # end + + # Enable provisioning with a shell script. Additional provisioners such as + # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the + # documentation for more information about their specific syntax and use. + # config.vm.provision "shell", inline: <<-SHELL + # sudo apt-get update + # sudo apt-get install -y apache2 + # SHELL + + config.vm.provision "shell", inline: <<-SHELL + sudo pkg install -y gmake ruby rubygem-bundler git-subversion python2 + SHELL +end diff --git a/release/x86_64-linux/Vagrantfile b/release/x86_64-linux/Vagrantfile index f06a1ed0..7deda6f7 100644 --- a/release/x86_64-linux/Vagrantfile +++ b/release/x86_64-linux/Vagrantfile @@ -66,10 +66,14 @@ Vagrant.configure(2) do |config| # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the # documentation for more information about their specific syntax and use. config.vm.provision "shell", inline: <<-SHELL - sudo apt-get update - sudo apt-get install -y gcc-4.8 g++-4.8 build-essential git git-svn python ruby ruby-dev - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8 - sudo update-alternatives --config gcc - gem install bundler + apt-get update + apt-get install -y gcc-4.8 g++-4.8 build-essential git git-svn python ruby ruby-dev emacs + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 60 --slave /usr/bin/g++ g++ /usr/bin/g++-4.8 + update-alternatives --config gcc + su -c 'gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3' - vagrant + su -c '\\curl -sSL https://get.rvm.io | bash -s stable' - vagrant + su -c 'rvm install 2.2.2 --disable-binary' - vagrant + su -c 'rvm --default use 2.2.2' - vagrant + su -c 'gem install bundler' - vagrant SHELL end diff --git a/spec/compiler/apple_llvm_spec.rb b/spec/compiler/apple_llvm_spec.rb new file mode 100644 index 00000000..f5b9c587 --- /dev/null +++ b/spec/compiler/apple_llvm_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' +require 'compiler' + +module Libv8::Compiler + describe AppleLLVM do + subject { AppleLLVM.new 'c++' } + + describe '#name' do + it 'returns Apple LLVM' do + expect(subject.name).to eq 'Apple LLVM' + end + end + + describe '#version' do + it 'returns the version of the compiler' do + stub_as_available 'c++', :apple_llvm, '5.1' + expect(subject.version).to eq '5.1' + end + end + + describe '#compatible?' do + context 'when Apple LLVM\'s version is >= 4.3' do + it 'returns true' do + stub_as_available 'c++', :apple_llvm, '5.1' + expect(subject).to be_compatible + end + end + end + end +end diff --git a/spec/compiler/clang_spec.rb b/spec/compiler/clang_spec.rb new file mode 100644 index 00000000..ef9e7994 --- /dev/null +++ b/spec/compiler/clang_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' +require 'compiler' + +module Libv8::Compiler + describe Clang do + subject { Clang.new 'c++' } + + describe '#name' do + it 'returns clang' do + expect(subject.name).to eq 'clang' + end + end + + describe '#version' do + it 'returns the version of the compiler' do + stub_as_available 'c++', :clang, '3.4.1' + expect(subject.version).to eq '3.4.1' + end + end + + describe '#compatible?' do + context 'when clang\'s version is >= 3.1' do + it 'returns true' do + stub_as_available 'c++', :clang, '3.4.1' + expect(subject).to be_compatible + end + end + end + end +end diff --git a/spec/compiler/gcc_spec.rb b/spec/compiler/gcc_spec.rb new file mode 100644 index 00000000..8196564c --- /dev/null +++ b/spec/compiler/gcc_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' +require 'compiler' + +module Libv8::Compiler + describe GCC do + subject { GCC.new 'c++' } + + describe '#name' do + it 'returns GCC' do + expect(subject.name).to eq 'GCC' + end + end + + describe '#version' do + it 'returns the version of the compiler' do + stub_as_available 'c++', :gcc, '4.9.0' + expect(subject.version).to eq '4.9.0' + end + end + + describe '#compatible?' do + context 'when GCC\'s version is >= 4.8' do + it 'returns true' do + stub_as_available 'c++', :gcc, '4.9.0' + expect(subject).to be_compatible + end + end + + context 'when GCC\'s version is < 4.3' do + it 'returns false' do + stub_as_available 'c++', :gcc, '4.2.1-freebsd' + expect(subject).to_not be_compatible + end + end + end + end +end diff --git a/spec/compiler/generic_compiler_spec.rb b/spec/compiler/generic_compiler_spec.rb new file mode 100644 index 00000000..8a3e0fdc --- /dev/null +++ b/spec/compiler/generic_compiler_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' +require 'compiler' + +module Libv8::Compiler + describe GenericCompiler do + subject { GenericCompiler.new 'c++' } + + describe '#name' do + it 'returns just the base name of the command' do + expect(GenericCompiler.new('/usr/sbin/c++').name).to eq 'c++' + end + end + + describe '#to_s' do + it 'should be the command used to call the compiler' do + expect(subject.to_s).to eq 'c++' + end + end + + describe '#version' do + it 'returns the version of the compiler' do + stub_as_available 'c++', :clang, '3.4.1' + expect(subject.version).to eq '3.4.1' + end + + it 'returns nil when determining the version fails' do + stub_as_unavailable 'c++' + expect(subject.version).to be_nil + end + end + + describe '#target' do + it 'returns the target of the compiler' do + stub_as_available 'c++', :clang, '3.4.1' + expect(subject.target).to eq 'x86_64-unknown-linux-gnu' + end + + it 'returns nil when determining the target fails' do + stub_as_unavailable 'c++' + expect(subject.target).to be_nil + end + end + + describe '#compatible?' do + it 'returns false' do + expect(GenericCompiler.new('c++')).to_not be_compatible + end + end + end +end diff --git a/spec/compiler_spec.rb b/spec/compiler_spec.rb new file mode 100644 index 00000000..334b12fd --- /dev/null +++ b/spec/compiler_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' +require 'compiler' + +module Libv8 + describe Compiler do + describe '::type_of' do + it 'recognises correctly GCC' do + stub_as_available 'c++', :gcc, '4.9.0' + expect(Compiler.available_compilers('c++').first).to be_a Compiler::GCC + + stub_as_available 'g++', :gcc, '4.2.1-freebsd' + expect(Compiler.available_compilers('g++').first).to be_a Compiler::GCC + end + + it 'recognises correctly Clang' do + stub_as_available 'c++', :clang, '3.4.1' + expect(Compiler.available_compilers('c++').first).to be_a Compiler::Clang + + stub_as_available 'freebsd-clang++', :clang, '3.3-freebsd' + expect(Compiler.available_compilers('freebsd-clang++').first).to be_a Compiler::Clang + end + + it 'recognises correctly Apple\'s LLVM' do + stub_as_available 'c++', :apple_llvm, '5.1' + expect(Compiler.available_compilers('c++').first).to be_a Compiler::AppleLLVM + end + end + + describe '::available_compilers' do + it 'returns instances of the available compilers' do + stub_as_available 'c++', :clang, '3.4.1' + stub_as_unavailable 'g++' + stub_as_available 'clang++', :clang, '3.4.1' + + available_compilers = Compiler.available_compilers 'c++', 'g++', 'clang++' + expect(available_compilers.map(&:class).count).to eq 2 + available_compilers.all? { |compiler| expect(compiler).to be_a Compiler::Clang } + end + end + + describe '::version_string_of' do + context 'when calling the compiler command succedes' do + it 'returns the version string of the compiler' do + stub_as_available 'c++', :clang, '3.4.1' + expect(Compiler.version_string_of('c++')).to eq version_output_of(:clang, '3.4.1') + end + end + + context 'when calling the compiler command fails' do + it 'raises an exception' do + stub_as_unavailable 'c++' + expect { Compiler.version_string_of('c++') }.to raise_exception(RuntimeError, /Could not get version string of compiler/) + end + end + end + + describe '::available?' do + it 'returns true when the command is available' do + stub_as_available 'c++', :clang, '3.4.1' + expect(Compiler::available?('c++')).to be true + end + + it 'returns false when the command cannot be found ' do + stub_as_unavailable 'c++' + expect(Compiler::available?('c++')).to be false + end + end + end +end diff --git a/spec/location_spec.rb b/spec/location_spec.rb index c48e2c16..367782f0 100644 --- a/spec/location_spec.rb +++ b/spec/location_spec.rb @@ -8,27 +8,27 @@ describe "the system location" do before do @location = Libv8::Location::System.new - @context.stub(:dir_config) + allow(@context).to receive :dir_config end describe "configuring a compliation context with it" do before do - @context.stub(:find_header) {true} - @context.stub(:have_library) {true} + allow(@context).to receive(:find_header) {true} + allow(@context).to receive(:have_library) {true} @location.configure @context end it "adds the include path to the front of the include flags" do - @context.should have_received(:dir_config).with('v8').at_least(:once) - @context.should have_received(:find_header).with('v8.h').at_least(:once) - @context.should have_received(:have_library).with('v8').at_least(:once) + expect(@context).to have_received(:dir_config).with('v8').at_least(:once) + expect(@context).to have_received(:find_header).with('v8.h').at_least(:once) + expect(@context).to have_received(:have_library).with('v8').at_least(:once) end end describe "when the v8 library cannot be found" do before do - @context.stub(:find_header) {true} - @context.stub(:have_library) {false} + allow(@context).to receive(:find_header) {true} + allow(@context).to receive(:have_library) {false} end it "raises a NotFoundError" do @@ -38,8 +38,8 @@ describe "when the v8.h header cannot be found" do before do - @context.stub(:find_header) {false} - @context.stub(:have_library) {true} + allow(@context).to receive(:find_header) {false} + allow(@context).to receive(:have_library) {true} end it "raises a NotFoundError" do @@ -51,20 +51,20 @@ describe "the vendor location" do before do @location = Libv8::Location::Vendor.new - @context.stub(:incflags) {@incflags ||= "-I/usr/include -I/usr/local/include"} - @context.stub(:ldflags) {@ldflags ||= "-lobjc -lpthread"} + allow(@context).to receive(:incflags) {@incflags ||= "-I/usr/include -I/usr/local/include"} + allow(@context).to receive(:ldflags) {@ldflags ||= "-lobjc -lpthread"} - Libv8::Paths.stub(:vendored_source_path) {"/foo bar/v8"} - Libv8::Arch.stub(:libv8_arch) {'x64'} + allow(Libv8::Paths).to receive(:vendored_source_path) {"/foo bar/v8"} + allow(Libv8::Arch).to receive(:libv8_arch) {'x64'} @location.configure @context end it "prepends its own incflags before any pre-existing ones" do - @context.incflags.should eql "-I/foo\\ bar/v8/include -I/usr/include -I/usr/local/include" + expect(@context.incflags).to eql "-I/foo\\ bar/v8 -I/usr/include -I/usr/local/include" end it "prepends the locations of any libv8 objects on the the ldflags" do - @context.ldflags.should eql "/foo\\ bar/v8/out/x64.release/obj.target/tools/gyp/libv8_base.a /foo\\ bar/v8/out/x64.release/obj.target/tools/gyp/libv8_snapshot.a -lobjc -lpthread" + expect(@context.ldflags).to eql "/foo\\ bar/v8/out/x64.release/obj.target/tools/gyp/libv8_base.a /foo\\ bar/v8/out/x64.release/obj.target/tools/gyp/libv8_libplatform.a /foo\\ bar/v8/out/x64.release/obj.target/tools/gyp/libv8_libbase.a /foo\\ bar/v8/out/x64.release/obj.target/tools/gyp/libv8_snapshot.a -lobjc -lpthread" end end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9e6d775c..9dec079f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,4 +1,5 @@ +$:.unshift File.expand_path '../../ext/libv8', __FILE__ $:.unshift File.expand_path '../../lib', __FILE__ require 'rspec' -require 'rspec-spies' require 'libv8' +require File.expand_path '../support/compiler_helpers', __FILE__ diff --git a/spec/support/compiler_helpers.rb b/spec/support/compiler_helpers.rb new file mode 100644 index 00000000..93af6cc5 --- /dev/null +++ b/spec/support/compiler_helpers.rb @@ -0,0 +1,47 @@ +module CompilerHelpers + VERSION_OUTPUTS = { + :gcc => { + "4.2.1-freebsd" => %Q{Using built-in specs.\nTarget: i386-undermydesk-freebsd\nConfigured with: FreeBSD/i386 system compiler\nThread model: posix\ngcc version 4.2.1 20070831 patched [FreeBSD]\n}, + "4.9.0" => %Q{Using built-in specs.\nCOLLECT_GCC=c++\nCOLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-unknown-linux-gnu/4.9.0/lto-wrapper\nTarget: x86_64-unknown-linux-gnu\nConfigured with: /build/gcc-multilib/src/gcc-4.9-20140604/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-cloog-backend=isl --disable-cloog-version-check --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-multilib --disable-werror --enable-checking=release\nThread model: posix\ngcc version 4.9.0 20140604 (prerelease) (GCC)\n} + }, + :clang => { + "3.3-freebsd" => %Q{FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610\nTarget: i386-unknown-freebsd9.2\nThread model: posix}, + "3.4.1" => %Q{clang version 3.4.1 (tags/RELEASE_34/dot1-final)\nTarget: x86_64-unknown-linux-gnu\nThread model: posix\nFound candidate GCC installation: /usr/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.0\nFound candidate GCC installation: /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0\nFound candidate GCC installation: /usr/lib/gcc/x86_64-unknown-linux-gnu/4.9.0\nFound candidate GCC installation: /usr/lib64/gcc/x86_64-unknown-linux-gnu/4.9.0\nSelected GCC installation: /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.9.0\n}, + }, + :apple_llvm => { + '5.1' => %Q{Configured with: --prefix=/Applications/Xcode.app/Contents/Developer//usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1\nApple LLVM version 5.1 (clang-503.0.38) (based on LLVM 3.4svn)\nTarget: x86_64-apple-darwin14.0.0\nThread model: posix\n} + } + } + + def version_output_of(name, version) + VERSION_OUTPUTS[name][version] + end + + def success_status + double :success? => true + end + + def failure_status + double :success? => false + end + + def stub_shell_command(command, output, status) + allow(Libv8::Compiler).to receive(:execute_command).with(command) do + double :output => output, :status => status + end + end + + def stub_as_available(command, name, version) + stub_shell_command "which #{command} 2>&1", '', success_status + stub_shell_command "#{command} -v 2>&1", version_output_of(name, version), success_status + end + + def stub_as_unavailable(command) + stub_shell_command "which #{command} 2>&1", '', failure_status + stub_shell_command(/^#{Regexp.escape(command)}/, '', failure_status) + end +end + +RSpec.configure do |c| + c.include CompilerHelpers +end diff --git a/vendor/depot_tools b/vendor/depot_tools new file mode 160000 index 00000000..faa4b4eb --- /dev/null +++ b/vendor/depot_tools @@ -0,0 +1 @@ +Subproject commit faa4b4eb51757e38879a34c4005c4e56c2d360ad diff --git a/vendor/gyp b/vendor/gyp deleted file mode 160000 index f7bc250c..00000000 --- a/vendor/gyp +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f7bc250ccc4d619a1cf238db87e5979f89ff36d7 diff --git a/vendor/v8 b/vendor/v8 deleted file mode 160000 index 7ce3fe10..00000000 --- a/vendor/v8 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7ce3fe106a37826dc23189a78dcb9000a1b3fa06