├── lib ├── libv8 │ └── version.rb └── libv8.rb ├── thefrontside.png ├── Gemfile ├── spec ├── spec_helper.rb └── location_spec.rb ├── .gitignore ├── .gitmodules ├── ext └── libv8 │ ├── extconf.rb │ ├── make.rb │ ├── compiler │ ├── clang.rb │ ├── gcc.rb │ └── generic_compiler.rb │ ├── arch.rb │ ├── paths.rb │ ├── compiler.rb │ ├── patcher.rb │ ├── checkout.rb │ ├── location.rb │ └── builder.rb ├── .travis.yml ├── patches ├── clang51 │ └── no-unused-variable.patch ├── arm │ ├── do-not-use-vfp2.patch │ └── do-not-imply-vfp3-and-armv7.patch ├── fPIC-for-static.patch ├── disable-building-tests.patch ├── clang │ └── no-unused-private-field.patch ├── gcc48 │ └── gcc48-wno-unused-local-typedefs.patch └── clang33 │ └── silence-nested-anon-types-and-unused-function-warnings.patch ├── libv8.gemspec ├── Rakefile └── README.md /lib/libv8/version.rb: -------------------------------------------------------------------------------- 1 | module Libv8 2 | VERSION = "3.16.14.7" 3 | end 4 | -------------------------------------------------------------------------------- /thefrontside.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/genius/libv8/master/thefrontside.png -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Specify your gem's dependencies in libv8.gemspec 4 | gemspec 5 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path '../../lib', __FILE__ 2 | require 'rspec' 3 | require 'rspec-spies' 4 | require 'libv8' 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.bundle 3 | *.so 4 | *.a 5 | .rbx/ 6 | Gemfile.lock 7 | Makefile 8 | pkg/* 9 | tmp/* 10 | lib/libv8/build/* 11 | lib/libv8/VERSION 12 | /ext/libv8/.location.yml 13 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/v8"] 2 | path = vendor/v8 3 | url = https://github.com/v8/v8.git 4 | [submodule "vendor/gyp"] 5 | path = vendor/gyp 6 | url = https://chromium.googlesource.com/external/gyp.git 7 | -------------------------------------------------------------------------------- /lib/libv8.rb: -------------------------------------------------------------------------------- 1 | require 'libv8/version' 2 | require 'libv8/location' 3 | 4 | module Libv8 5 | def self.configure_makefile 6 | location = Location.load! 7 | location.configure 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /ext/libv8/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | create_makefile('libv8') 3 | 4 | require File.expand_path '../location', __FILE__ 5 | location = with_config('system-v8') ? Libv8::Location::System.new : Libv8::Location::Vendor.new 6 | 7 | exit location.install! 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | rvm: 2 | - 2.0.0 3 | - 2.1.5 4 | - 1.9.3 5 | - rbx 6 | bundler_args: --jobs=1 --retry=3 7 | notifications: 8 | recipients: 9 | - cowboyd@thefrontside.net 10 | - bordjukov@gmail.com 11 | before_install: 12 | - sudo apt-get update 13 | - sudo apt-get install git-svn 14 | -------------------------------------------------------------------------------- /ext/libv8/make.rb: -------------------------------------------------------------------------------- 1 | module Libv8 2 | module Make 3 | module_function 4 | 5 | def make 6 | unless defined?(@make) 7 | @make = `which gmake 2> /dev/null`.chomp 8 | @make = `which make`.chomp unless $?.success? 9 | end 10 | @make 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /ext/libv8/compiler/clang.rb: -------------------------------------------------------------------------------- 1 | module Libv8 2 | module Compiler 3 | class Clang < GenericCompiler 4 | VERSION_REGEXP = /clang version (\d+\.\d+(\.\d+)*) \(/i 5 | 6 | def name 7 | 'clang' 8 | end 9 | 10 | def compatible? 11 | version >= '3.1' 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ext/libv8/compiler/gcc.rb: -------------------------------------------------------------------------------- 1 | module Libv8 2 | module Compiler 3 | class GCC < GenericCompiler 4 | VERSION_REGEXP = /gcc version (\d+\.\d+(\.\d+)*)/i 5 | 6 | def name 7 | 'GCC' 8 | end 9 | 10 | def compatible? 11 | version > '4.3' and version < '5' 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /patches/clang51/no-unused-variable.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/standalone.gypi b/build/standalone.gypi 2 | index 125c5bf..a283a28 100644 3 | --- a/build/standalone.gypi 4 | +++ b/build/standalone.gypi 5 | @@ -210,6 +212,7 @@ 6 | '-Wendif-labels', 7 | '-W', 8 | '-Wno-unused-parameter', 9 | + '-Wno-unused-variable', 10 | '-Wnon-virtual-dtor', 11 | ], 12 | }, 13 | -------------------------------------------------------------------------------- /patches/arm/do-not-use-vfp2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/common.gypi b/build/common.gypi 2 | index 3a59639..594abe4 100644 3 | --- a/build/common.gypi 4 | +++ b/build/common.gypi 5 | @@ -173,7 +173,6 @@ 6 | [ 'v8_use_arm_eabi_hardfloat=="true"', { 7 | 'defines': [ 8 | 'USE_EABI_HARDFLOAT=1', 9 | - 'CAN_USE_VFP2_INSTRUCTIONS', 10 | ], 11 | 'target_conditions': [ 12 | ['_toolset=="target"', { 13 | 14 | -------------------------------------------------------------------------------- /patches/fPIC-for-static.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/standalone.gypi b/build/standalone.gypi 2 | index 125c5bf..71641a3 100644 3 | --- a/build/standalone.gypi 4 | +++ b/build/standalone.gypi 5 | @@ -107,7 +107,7 @@ 6 | [ 'visibility=="hidden" and v8_enable_backtrace==0', { 7 | 'cflags': [ '-fvisibility=hidden' ], 8 | }], 9 | - [ 'component=="shared_library"', { 10 | + [ 'component=="shared_library" or component=="static_library" and v8_target_arch=="x64" or v8_target_arch=="arm"', { 11 | 'cflags': [ '-fPIC', ], 12 | }], 13 | ], 14 | -------------------------------------------------------------------------------- /ext/libv8/compiler/generic_compiler.rb: -------------------------------------------------------------------------------- 1 | module Libv8 2 | module Compiler 3 | class GenericCompiler 4 | VERSION_REGEXP = /(\d+\.\d+(\.\d+)*)/ 5 | TARGET_REGEXP = /Target: ([a-z0-9\-_.]*)/ 6 | 7 | def initialize(path) 8 | @path = path 9 | end 10 | 11 | def name 12 | File.basename @path 13 | end 14 | 15 | def to_s 16 | @path 17 | end 18 | 19 | def version 20 | call('-v')[0..1].join =~ VERSION_REGEXP 21 | $1 22 | end 23 | 24 | def target 25 | call('-v')[0..1].join =~ TARGET_REGEXP 26 | $1 27 | end 28 | 29 | def compatible? 30 | false 31 | end 32 | 33 | def call(*arguments) 34 | Open3.capture3 arguments.unshift('LC_ALL=en', @path).join(' ') 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /patches/arm/do-not-imply-vfp3-and-armv7.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/common.gypi b/build/common.gypi 2 | index 3a59639..594abe4 100644 3 | --- a/build/common.gypi 4 | +++ b/build/common.gypi 5 | @@ -173,7 +173,6 @@ 6 | [ 'v8_use_arm_eabi_hardfloat=="true"', { 7 | 'defines': [ 8 | 'USE_EABI_HARDFLOAT=1', 9 | - 'CAN_USE_VFP2_INSTRUCTIONS', 10 | ], 11 | 'target_conditions': [ 12 | ['_toolset=="target"', { 13 | diff --git a/build/standalone.gypi b/build/standalone.gypi 14 | index 125c5bf..9900c5b 100644 15 | --- a/build/standalone.gypi 16 | +++ b/build/standalone.gypi 17 | @@ -77,9 +77,9 @@ 18 | }], 19 | ], 20 | # Default ARM variable settings. 21 | - 'armv7%': 1, 22 | + 'armv7%': 0, 23 | 'arm_neon%': 0, 24 | - 'arm_fpu%': 'vfpv3', 25 | + 'arm_fpu%': 'vfp', 26 | }, 27 | 'target_defaults': { 28 | 'default_configuration': 'Debug', 29 | -------------------------------------------------------------------------------- /patches/disable-building-tests.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index 0cdae4b..2bf8aa5 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -153,7 +153,7 @@ ANDROID_ARCHES = android_ia32 android_arm 6 | # List of files that trigger Makefile regeneration: 7 | GYPFILES = build/all.gyp build/common.gypi build/standalone.gypi \ 8 | preparser/preparser.gyp samples/samples.gyp src/d8.gyp \ 9 | - test/cctest/cctest.gyp tools/gyp/v8.gyp 10 | + tools/gyp/v8.gyp 11 | 12 | # Generates all combinations of ARCHES and MODES, e.g. "ia32.release". 13 | BUILDS = $(foreach mode,$(MODES),$(addsuffix .$(mode),$(ARCHES))) 14 | diff --git a/build/all.gyp b/build/all.gyp 15 | index 4b2fe52..9885678 100644 16 | --- a/build/all.gyp 17 | +++ b/build/all.gyp 18 | @@ -11,7 +11,6 @@ 19 | '../preparser/preparser.gyp:*', 20 | '../samples/samples.gyp:*', 21 | '../src/d8.gyp:d8', 22 | - '../test/cctest/cctest.gyp:*', 23 | ], 24 | } 25 | ] 26 | -------------------------------------------------------------------------------- /ext/libv8/arch.rb: -------------------------------------------------------------------------------- 1 | require 'rbconfig' 2 | 3 | module Libv8 4 | module Arch 5 | module_function 6 | 7 | def x86_64_from_build_cpu 8 | RbConfig::MAKEFILE_CONFIG['build_cpu'] == 'x86_64' 9 | end 10 | 11 | def x86_64_from_byte_length 12 | ['foo'].pack('p').size == 8 13 | end 14 | 15 | def x86_64_from_arch_flag 16 | RbConfig::MAKEFILE_CONFIG['ARCH_FLAG'] =~ /x86_64/ 17 | end 18 | 19 | def rubinius? 20 | Object.const_defined?(:RUBY_ENGINE) && RUBY_ENGINE == "rbx" 21 | end 22 | 23 | # TODO fix false positive on 64-bit ARM 24 | def x64? 25 | if rubinius? 26 | x86_64_from_build_cpu || x86_64_from_arch_flag 27 | else 28 | x86_64_from_byte_length 29 | end 30 | end 31 | 32 | def arm? 33 | RbConfig::MAKEFILE_CONFIG['build_cpu'] =~ /^arm/ 34 | end 35 | 36 | def libv8_arch 37 | if arm? then "arm" 38 | elsif x64? then "x64" 39 | else "ia32" 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /ext/libv8/paths.rb: -------------------------------------------------------------------------------- 1 | require 'rbconfig' 2 | require File.expand_path '../arch', __FILE__ 3 | 4 | module Libv8 5 | module Paths 6 | module_function 7 | 8 | def include_paths 9 | ["#{vendored_source_path}/include"] 10 | end 11 | 12 | def object_paths 13 | [libv8_object(:base), libv8_object(:snapshot)] 14 | end 15 | 16 | def config 17 | RbConfig::MAKEFILE_CONFIG 18 | end 19 | 20 | def libv8_object(name) 21 | filename = "#{libv8_profile}/libv8_#{name}.#{config['LIBEXT']}" 22 | unless File.exist? filename 23 | filename = "#{libv8_profile}/obj.target/tools/gyp/libv8_#{name}.#{config['LIBEXT']}" 24 | end 25 | return filename 26 | end 27 | 28 | def libv8_profile 29 | base = "#{vendored_source_path}/out/#{Libv8::Arch.libv8_arch}" 30 | debug = "#{base}.debug" 31 | File.exist?(debug) ? debug : "#{base}.release" 32 | end 33 | 34 | def vendored_source_path 35 | File.expand_path "../../../vendor/v8", __FILE__ 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /ext/libv8/compiler.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | require 'open3' 3 | require File.expand_path '../compiler/generic_compiler', __FILE__ 4 | require File.expand_path '../compiler/gcc', __FILE__ 5 | require File.expand_path '../compiler/clang', __FILE__ 6 | 7 | module Libv8 8 | module Compiler 9 | KNOWN_COMPILERS = [ 10 | 'c++', 11 | 'g++48', 'g++46', 'g++44', 'g++', 12 | 'clang++', 13 | ] 14 | 15 | module_function 16 | 17 | def system_compilers 18 | available_compilers *Compiler::KNOWN_COMPILERS 19 | end 20 | 21 | def available_compilers(*compiler_names) 22 | compiler_paths = compiler_names.map { |name| find name }.reject &:nil? 23 | end 24 | 25 | def find(name) 26 | return nil if name.empty? 27 | path, _, status = Open3.capture3 "which #{name}" 28 | path.chomp! 29 | determine_type(path).new(path) if status.success? 30 | end 31 | 32 | def determine_type(compiler_path) 33 | compiler_version = Open3.capture3("#{compiler_path} -v")[0..1].join 34 | 35 | case compiler_version 36 | when /\bclang\b/i then Clang 37 | when /^gcc/i then GCC 38 | else GenericCompiler 39 | end 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /patches/clang/no-unused-private-field.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/common.gypi b/build/common.gypi 2 | index 3a59639..14bf0f9 100644 3 | --- a/build/common.gypi 4 | +++ b/build/common.gypi 5 | @@ -376,7 +376,8 @@ 6 | }], 7 | ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { 8 | 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', 9 | - '-Wnon-virtual-dtor', '-Woverloaded-virtual' ], 10 | + '-Wnon-virtual-dtor', '-Woverloaded-virtual', 11 | + '-Wno-unused-private-field' ], 12 | }], 13 | ['OS=="linux" and v8_enable_backtrace==1', { 14 | # Support for backtrace_symbols. 15 | diff --git a/build/standalone.gypi b/build/standalone.gypi 16 | index 125c5bf..c8d9b4f 100644 17 | --- a/build/standalone.gypi 18 | +++ b/build/standalone.gypi 19 | @@ -98,7 +98,8 @@ 20 | 'target_defaults': { 21 | 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', 22 | '-Wnon-virtual-dtor', '-pthread', '-fno-rtti', 23 | - '-fno-exceptions', '-pedantic' ], 24 | + '-fno-exceptions', '-pedantic', 25 | + '-Wno-unused-private-field' ], 26 | 'ldflags': [ '-pthread', ], 27 | 'conditions': [ 28 | [ 'OS=="linux"', { 29 | -------------------------------------------------------------------------------- /patches/gcc48/gcc48-wno-unused-local-typedefs.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/common.gypi b/build/common.gypi 2 | index 3a59639..365178a 100644 3 | --- a/build/common.gypi 4 | +++ b/build/common.gypi 5 | @@ -376,7 +376,8 @@ 6 | }], 7 | ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { 8 | 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', 9 | - '-Wnon-virtual-dtor', '-Woverloaded-virtual' ], 10 | + '-Wnon-virtual-dtor', '-Woverloaded-virtual', 11 | + '-Wno-unused-local-typedefs' ], 12 | }], 13 | ['OS=="linux" and v8_enable_backtrace==1', { 14 | # Support for backtrace_symbols. 15 | diff --git a/build/standalone.gypi b/build/standalone.gypi 16 | index 125c5bf..32eaf85 100644 17 | --- a/build/standalone.gypi 18 | +++ b/build/standalone.gypi 19 | @@ -98,7 +98,8 @@ 20 | 'target_defaults': { 21 | 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', 22 | '-Wnon-virtual-dtor', '-pthread', '-fno-rtti', 23 | - '-fno-exceptions', '-pedantic' ], 24 | + '-fno-exceptions', '-pedantic', 25 | + '-Wno-unused-local-typedefs' ], 26 | 'ldflags': [ '-pthread', ], 27 | 'conditions': [ 28 | [ 'OS=="linux"', { 29 | -------------------------------------------------------------------------------- /libv8.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.unshift File.expand_path("../lib", __FILE__) 3 | require "libv8/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "libv8" 7 | s.version = Libv8::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["Charles Lowell"] 10 | s.email = ["cowboyd@thefrontside.net"] 11 | s.homepage = "http://github.com/cowboyd/libv8" 12 | s.summary = %q{Distribution of the V8 JavaScript engine} 13 | s.description = %q{Distributes the V8 JavaScript engine in binary and source forms in order to support fast builds of The Ruby Racer} 14 | s.license = "MIT" 15 | 16 | s.rubyforge_project = "libv8" 17 | 18 | 19 | s.files = `git ls-files`.split("\n") 20 | s.files += Dir.chdir("vendor/v8") do 21 | `git ls-files`.split("\n").reject {|f| f =~ /^out/}.map {|f| "vendor/v8/#{f}"} 22 | end 23 | s.files += Dir['vendor/v8/build/**/*'] 24 | s.files += Dir.chdir("vendor/gyp") do 25 | `git ls-files`.split("\n").map {|f| "vendor/gyp/#{f}"} 26 | end 27 | 28 | s.extensions = ["ext/libv8/extconf.rb"] 29 | s.require_paths = ["lib", "ext"] 30 | 31 | s.add_development_dependency "rake" 32 | s.add_development_dependency "rake-compiler" 33 | s.add_development_dependency "rspec" 34 | s.add_development_dependency "rspec-spies" 35 | s.add_development_dependency "rubysl", "~> 2.0" if RUBY_ENGINE == "rbx" 36 | s.add_development_dependency "vulcan" 37 | end 38 | -------------------------------------------------------------------------------- /patches/clang33/silence-nested-anon-types-and-unused-function-warnings.patch: -------------------------------------------------------------------------------- 1 | diff --git a/build/common.gypi b/build/common.gypi 2 | index 14bf0f9..301109a 100644 3 | --- a/build/common.gypi 4 | +++ b/build/common.gypi 5 | @@ -377,7 +377,8 @@ 6 | ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="netbsd"', { 7 | 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', 8 | '-Wnon-virtual-dtor', '-Woverloaded-virtual', 9 | - '-Wno-unused-private-field' ], 10 | + '-Wno-unused-private-field', '-Wno-nested-anon-types', 11 | + '-Wno-unused-function' ], 12 | }], 13 | ['OS=="linux" and v8_enable_backtrace==1', { 14 | # Support for backtrace_symbols. 15 | diff --git a/build/standalone.gypi b/build/standalone.gypi 16 | index c8d9b4f..ddd1693 100644 17 | --- a/build/standalone.gypi 18 | +++ b/build/standalone.gypi 19 | @@ -99,7 +99,8 @@ 20 | 'cflags': [ '-Wall', '<(werror)', '-W', '-Wno-unused-parameter', 21 | '-Wnon-virtual-dtor', '-pthread', '-fno-rtti', 22 | '-fno-exceptions', '-pedantic', 23 | - '-Wno-unused-private-field' ], 24 | + '-Wno-unused-private-field', '-Wno-nested-anon-types', 25 | + '-Wno-unused-function' ], 26 | 'ldflags': [ '-pthread', ], 27 | 'conditions': [ 28 | [ 'OS=="linux"', { 29 | -------------------------------------------------------------------------------- /ext/libv8/patcher.rb: -------------------------------------------------------------------------------- 1 | module Libv8 2 | module Patcher 3 | PATCH_DIRECTORY = File.expand_path '../../../patches', __FILE__ 4 | 5 | module_function 6 | 7 | def patch_directories_for(compiler) 8 | patch_directories = [] 9 | 10 | case 11 | when compiler.target =~ /arm/ 12 | patch_directories << 'arm' 13 | end 14 | 15 | case compiler 16 | when Compiler::GCC 17 | patch_directories << 'gcc48' if compiler.version >= '4.8' 18 | when Compiler::Clang 19 | patch_directories << 'clang' 20 | patch_directories << 'clang33' if compiler.version >= '3.3' 21 | patch_directories << 'clang51' if compiler.version >= '5.1' 22 | end 23 | 24 | patch_directories 25 | end 26 | 27 | def patch_directories(*additional_directories) 28 | absolute_paths = [PATCH_DIRECTORY] 29 | 30 | additional_directories.each do |directory| 31 | absolute_paths << File.join(PATCH_DIRECTORY, directory) 32 | end 33 | 34 | absolute_paths.uniq 35 | end 36 | 37 | def patches(*additional_directories) 38 | patch_directories(*additional_directories).map do |directory| 39 | Dir.glob(File.join directory, '*.patch') 40 | end.flatten.sort 41 | end 42 | 43 | def patch!(*additional_directories) 44 | File.open(".applied_patches", File::RDWR|File::CREAT) do |f| 45 | available_patches = patches *additional_directories 46 | applied_patches = f.readlines.map(&:chomp) 47 | 48 | (available_patches - applied_patches).each do |patch| 49 | `patch -p1 -N < #{patch}` 50 | f.puts patch 51 | end 52 | end 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /ext/libv8/checkout.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path '../../../lib/libv8/version.rb', __FILE__ 2 | 3 | module Libv8 4 | module Checkout 5 | module_function 6 | 7 | GYP_SVN = 'http://gyp.googlecode.com/svn' 8 | V8_Source = File.expand_path '../../../vendor/v8', __FILE__ 9 | GYP_Source = File.expand_path '../../../vendor/gyp', __FILE__ 10 | 11 | def checkout! 12 | # When compiling from a source gem, it's not a git repository anymore and 13 | # we assume the right code is already checked out. 14 | return unless git?(V8_Source) 15 | 16 | Dir.chdir(V8_Source) do 17 | `git fetch` 18 | `git checkout #{Libv8::VERSION.gsub(/\.\d+$/,'')} -f` 19 | `rm -f .applied_patches` 20 | end 21 | 22 | return unless git?(GYP_Source) 23 | 24 | check_git_svn! 25 | 26 | Dir.chdir(GYP_Source) do 27 | mkf = File.readlines(File.join(V8_Source, 'Makefile')) 28 | idx = mkf.index {|l| l =~ /#{GYP_SVN}/} + 1 29 | rev = /--revision (\d+)/.match(mkf[idx])[1] 30 | `git fetch` 31 | # --git-dir is needed for older versions of git and git-svn 32 | `git --git-dir=../../.git/modules/vendor/gyp/ svn init #{GYP_SVN} -Ttrunk` 33 | `git config --replace-all svn-remote.svn.fetch trunk:refs/remotes/origin/master` 34 | `git checkout $(git --git-dir=../../.git/modules/vendor/gyp/ svn find-rev r#{rev} | tail -n 1) -f` 35 | end 36 | end 37 | 38 | def git?(dir) 39 | File.exist?(File.join(dir, '.git')) 40 | end 41 | 42 | def check_git_svn! 43 | unless system 'git help svn 2>&1 > /dev/null' 44 | fail "git-svn not installed!\nPlease install git-svn." 45 | end 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/location_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe "libv8 locations" do 4 | before do 5 | @context = double(:CompilationContext) 6 | end 7 | describe "the system location" do 8 | before do 9 | @location = Libv8::Location::System.new 10 | @context.stub(:dir_config) 11 | end 12 | describe "configuring a compliation context with it" do 13 | before do 14 | @context.stub(:find_header) {true} 15 | @location.configure @context 16 | end 17 | it "adds the include path to the front of the include flags" do 18 | @context.should have_received(:dir_config).with('v8').at_least(:once) 19 | @context.should have_received(:find_header).with('v8.h').at_least(:once) 20 | end 21 | end 22 | describe "when the v8.h header cannot be found" do 23 | before do 24 | @context.stub(:find_header) {false} 25 | end 26 | it "raises a NotFoundError" do 27 | expect {@location.configure @context}.to raise_error Libv8::Location::System::NotFoundError 28 | end 29 | end 30 | end 31 | 32 | describe "the vendor location" do 33 | before do 34 | @location = Libv8::Location::Vendor.new 35 | @context.stub(:incflags) {@incflags ||= "-I/usr/include -I/usr/local/include"} 36 | @context.stub(:ldflags) {@ldflags ||= "-lobjc -lpthread"} 37 | 38 | Libv8::Paths.stub(:include_paths) {["/frp/v8/include"]} 39 | Libv8::Paths.stub(:object_paths) {["/frp/v8/obj/libv8_base.a", "/frp/v8/obj/libv8_snapshot.a"]} 40 | @location.configure @context 41 | end 42 | 43 | it "prepends its own incflags before any pre-existing ones" do 44 | @context.incflags.should eql "-I/frp/v8/include -I/usr/include -I/usr/local/include" 45 | end 46 | 47 | it "prepends the locations of any libv8 objects on the the ldflags" do 48 | @context.ldflags.should eql "/frp/v8/obj/libv8_base.a /frp/v8/obj/libv8_snapshot.a -lobjc -lpthread" 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /ext/libv8/location.rb: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | require 'pathname' 3 | require File.expand_path '../paths', __FILE__ 4 | 5 | module Libv8 6 | class Location 7 | def install! 8 | File.open(Pathname(__FILE__).dirname.join('.location.yml'), "w") do |f| 9 | f.write self.to_yaml 10 | end 11 | return 0 12 | end 13 | 14 | def self.load! 15 | File.open(Pathname(__FILE__).dirname.join('.location.yml')) do |f| 16 | YAML.load f 17 | end 18 | end 19 | 20 | class Vendor < Location 21 | def install! 22 | require File.expand_path '../builder', __FILE__ 23 | builder = Libv8::Builder.new 24 | exit_status = builder.build_libv8! 25 | super if exit_status == 0 26 | verify_installation! 27 | return exit_status 28 | end 29 | def configure(context = MkmfContext.new) 30 | context.incflags.insert 0, Libv8::Paths.include_paths.map{|p| "-I#{p}"}.join(" ") + " " 31 | context.ldflags.insert 0, Libv8::Paths.object_paths.join(" ") + " " 32 | end 33 | 34 | def verify_installation! 35 | Libv8::Paths.object_paths.each do |p| 36 | fail ArchiveNotFound, p unless File.exist? p 37 | end 38 | end 39 | 40 | class ArchiveNotFound < StandardError 41 | def initialize(filename) 42 | super "libv8 did not install properly, expected binary v8 archive '#{filename}'to exist, but it was not found" 43 | end 44 | end 45 | end 46 | 47 | class System < Location 48 | def configure(context = MkmfContext.new) 49 | context.send(:dir_config, 'v8') 50 | context.send(:find_header, 'v8.h') or fail NotFoundError 51 | end 52 | 53 | class NotFoundError < StandardError 54 | def initialize(*args) 55 | super(<<-EOS) 56 | You have chosen to use the version of V8 found on your system 57 | and *not* the one that is bundle with the libv8 rubygem. However, 58 | it could not be located. please make sure you have a version of 59 | v8 that is compatible with #{Libv8::VERSION} installed. You may 60 | need to special --with-v8-dir options if it is in a non-standard 61 | location 62 | 63 | thanks, 64 | The Mgmt 65 | 66 | EOS 67 | end 68 | end 69 | end 70 | 71 | class MkmfContext 72 | def incflags 73 | $INCFLAGS 74 | end 75 | 76 | def ldflags 77 | $LDFLAGS 78 | end 79 | end 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/setup' 2 | Bundler::GemHelper.install_tasks 3 | class Bundler::GemHelper 4 | def clean? 5 | sh_with_code('git diff --exit-code --ignore-submodules')[1] == 0 6 | end 7 | end 8 | 9 | require 'rspec/core/rake_task' 10 | RSpec::Core::RakeTask.new(:spec) 11 | 12 | require File.expand_path '../ext/libv8/make.rb', __FILE__ 13 | require File.expand_path '../ext/libv8/checkout.rb', __FILE__ 14 | include Libv8::Make 15 | include Libv8::Checkout 16 | 17 | desc "setup the vendored v8 source to correspond to the libv8 gem version" 18 | task :checkout do 19 | sh "git submodule update --init" 20 | checkout! 21 | end 22 | 23 | desc "compile v8 via the ruby extension mechanism" 24 | task :compile do 25 | sh "ruby ext/libv8/extconf.rb" 26 | end 27 | 28 | desc "manually invoke the GYP compile. Useful for seeing debug output" 29 | task :manual_compile do 30 | require File.expand_path '../ext/libv8/arch.rb', __FILE__ 31 | include Libv8::Arch 32 | Dir.chdir(V8_Source) do 33 | sh %Q{#{make} -j2 #{libv8_arch}.release ARFLAGS.target=crs} 34 | end 35 | end 36 | 37 | def get_binary_gemspec(platform = RUBY_PLATFORM) 38 | gemspec = eval(File.read('libv8.gemspec')) 39 | gemspec.platform = Gem::Platform.new(platform) 40 | gemspec 41 | end 42 | 43 | begin 44 | binary_gem_name = File.basename get_binary_gemspec.cache_file 45 | rescue 46 | binary_gem_name = '' 47 | end 48 | 49 | desc "build a binary gem #{binary_gem_name}" 50 | task :binary => :compile do 51 | gemspec = get_binary_gemspec 52 | gemspec.extensions.clear 53 | # We don't need most things for the binary 54 | gemspec.files = [] 55 | gemspec.files += ['lib/libv8.rb', 'lib/libv8/version.rb'] 56 | gemspec.files += ['ext/libv8/arch.rb', 'ext/libv8/location.rb', 'ext/libv8/paths.rb'] 57 | gemspec.files += ['ext/libv8/.location.yml'] 58 | # V8 59 | gemspec.files += Dir['vendor/v8/include/*'] 60 | gemspec.files += Dir['vendor/v8/out/**/*.a'] 61 | FileUtils.chmod 'a+r', gemspec.files 62 | FileUtils.mkdir_p 'pkg' 63 | package = if Gem::VERSION < '2.0.0' 64 | Gem::Builder.new(gemspec).build 65 | else 66 | require 'rubygems/package' 67 | Gem::Package.build(gemspec) 68 | end 69 | FileUtils.mv(package, 'pkg') 70 | end 71 | 72 | desc "clean up artifacts of the build" 73 | task :clean do 74 | sh "rm -rf pkg" 75 | sh "git clean -df" 76 | sh "cd #{V8_Source} && git checkout -f && git clean -dxf" 77 | sh "cd #{GYP_Source} && git checkout -f && git clean -dxf" 78 | end 79 | 80 | desc "build a binary on heroku (you must have vulcan configured for this)" 81 | task :vulcan => directory("tmp/vulcan") do 82 | Dir.chdir('tmp/vulcan') do 83 | sh "vulcan build -v -c 'LANG=en_US.UTF-8 export BIN=/`pwd`/bin && export GEM=$BIN/gem && curl https://s3.amazonaws.com/heroku-buildpack-ruby/ruby-1.9.3.tgz > ruby-1.9.3.tgz && tar xf ruby-1.9.3.tgz && cd /tmp && $GEM fetch libv8 --platform=ruby --version=#{Libv8::VERSION} && $GEM unpack libv8*.gem && $GEM install bundler -n $BIN --no-ri --no-rdoc && cd libv8-#{Libv8::VERSION} && $BIN/bundle && $BIN/bundle exec rake binary' -p /tmp/libv8-#{Libv8::VERSION}" 84 | end 85 | end 86 | 87 | task :default => [:checkout, :compile, :spec] 88 | task :build => [:clean, :checkout] 89 | -------------------------------------------------------------------------------- /ext/libv8/builder.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | require File.expand_path '../compiler', __FILE__ 3 | require File.expand_path '../arch', __FILE__ 4 | require File.expand_path '../make', __FILE__ 5 | require File.expand_path '../checkout', __FILE__ 6 | require File.expand_path '../patcher', __FILE__ 7 | 8 | module Libv8 9 | class Builder 10 | include Libv8::Arch 11 | include Libv8::Make 12 | include Libv8::Checkout 13 | include Libv8::Patcher 14 | 15 | def initialize 16 | @compiler = choose_compiler 17 | end 18 | 19 | def make_flags(*flags) 20 | profile = enable_config('debug') ? 'debug' : 'release' 21 | 22 | # FreeBSD uses gcc 4.2 by default which leads to 23 | # compilation failures due to warnings about aliasing. 24 | # http://svnweb.freebsd.org/ports/head/lang/v8/Makefile?view=markup 25 | flags << "strictaliasing=off" if @compiler.is_a?(Compiler::GCC) and @compiler.version < '4.4' 26 | 27 | # Avoid compilation failures on the Raspberry Pi. 28 | flags << "vfp2=off vfp3=off" if @compiler.target.include? "arm" 29 | 30 | # FIXME: Determine when to activate this instead of leaving it on by 31 | # default. 32 | flags << "hardfp=on" if @compiler.target.include? "arm" 33 | 34 | # Fix Malformed archive issue caused by GYP creating thin archives by 35 | # default. 36 | flags << "ARFLAGS.target=crs" 37 | 38 | # Solaris / Smart OS requires additional -G flag to use with -fPIC 39 | flags << "CFLAGS=-G" if @compiler.target =~ /solaris/ 40 | 41 | # Disable werror as this version of v8 is getting difficult to maintain 42 | # with it on 43 | flags << 'werror=no' 44 | 45 | "#{libv8_arch}.#{profile} #{flags.join ' '}" 46 | end 47 | 48 | def build_libv8! 49 | Dir.chdir(V8_Source) do 50 | fail 'No compilers available' if @compiler.nil? 51 | checkout! 52 | setup_python! 53 | setup_build_deps! 54 | patch! *patch_directories_for(@compiler) 55 | print_build_info 56 | puts `env CXX=#{@compiler} LINK=#{@compiler} #{make} #{make_flags}` 57 | end 58 | return $?.exitstatus 59 | end 60 | 61 | def setup_python! 62 | # If python v2 cannot be found in PATH, 63 | # create a symbolic link to python2 the current directory and put it 64 | # at the head of PATH. That way all commands that inherit this environment 65 | # will use ./python -> python2 66 | if python_version !~ /^2/ 67 | unless system 'which python2 2>&1 > /dev/null' 68 | fail "libv8 requires python 2 to be installed in order to build, but it is currently #{python_version}" 69 | end 70 | `ln -fs #{`which python2`.chomp} python` 71 | ENV['PATH'] = "#{File.expand_path '.'}:#{ENV['PATH']}" 72 | end 73 | end 74 | 75 | def setup_build_deps! 76 | # This uses the Git mirror of the svn repository used by 77 | # "make dependencies", instead of calling that make target 78 | `rm -rf build/gyp` 79 | `ln -fs #{GYP_Source} build/gyp` 80 | end 81 | 82 | private 83 | 84 | def choose_compiler 85 | compiler_names = if with_config('cxx') then [with_config('cxx')] 86 | elsif ENV['CXX'] then [ENV['CXX']] 87 | else Compiler::KNOWN_COMPILERS 88 | end 89 | 90 | available_compilers = Compiler.available_compilers(*compiler_names) 91 | compatible_compilers = available_compilers.select(&:compatible?) 92 | 93 | unless compatible_compilers.empty? then compatible_compilers 94 | else available_compilers 95 | end.first 96 | end 97 | 98 | def python_version 99 | if system 'which python 2>&1 > /dev/null' 100 | `python -c 'import platform; print(platform.python_version())'`.chomp 101 | else 102 | "not available" 103 | end 104 | end 105 | 106 | def print_build_info 107 | puts "Compiling v8 for #{libv8_arch}" 108 | 109 | puts "Using python #{python_version}" 110 | 111 | puts "Using compiler: #{@compiler} (#{@compiler.name} version #{@compiler.version})" 112 | unless @compiler.compatible? 113 | warn "Unable to find a compiler officially supported by v8." 114 | warn "It is recommended to use GCC v4.4 or higher" 115 | end 116 | end 117 | end 118 | end 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libv8 2 | 3 | A gem for distributing the v8 runtime libraries and headers in both 4 | source and binary form. 5 | 6 | ### Why? 7 | 8 | The goal of libv8 is two fold: provide a binary gem containing the a 9 | pre-compiled libv8.a for as many platforms as possible while at the 10 | same time supporting for an automated compilation for all others. 11 | 12 | Not only does this drastically reduce gem install times, but it also 13 | reduces dependencies on the local machine receiving the gem. It also 14 | opens the door for supporting Windows. 15 | 16 | ### Do I get a binary? 17 | 18 | That depends on your platform. Right now, we support the following 19 | platforms. 20 | 21 | * x86_64-darwin10.7.0 22 | * x86_64-darwin-10 23 | * x86_64-darwin-11 24 | * x86_64-darwin-12 25 | * x86_64-darwin-13 26 | * x86_64-linux 27 | * x86-linux 28 | * x86_64-freebsd-9 29 | * x86_64-freebsd-10 30 | * x86_64-solaris-2.11 31 | 32 | If you don't see your platform on this list, first, make sure that it 33 | installs from source, and second talk to us about setting up a binary 34 | distro for you. 35 | 36 | ### Versioning 37 | 38 | Versions of the libv8 gem track the version of v8 itself, adding its 39 | own point release after the main v8 version. So libv8 `3.11.8.5` and 40 | `3.11.8.14` both correspond to v8 version `3.11.8`. Another way to 41 | think about it would be that `3.11.8.14` is the 14th release of the 42 | libv8 rubygem based on v8 version `3.11.8` 43 | 44 | #### Source and Binary Releases 45 | 46 | Starting with libv8 `3.11.8.0`, all even point releases contain 47 | only a source-based distribution, while odd point releases contain both 48 | a source-based distribution *and* binary distributions. However both 49 | point releases correspond to the *exact* underlying code. The only 50 | difference is the version number. 51 | 52 | This way, the most recent version of the gem always has binary 53 | distributions, but if, for whatever reason, you have problems with the 54 | binaries, you can always "lock in" your dependency a single point version 55 | down, forcing it to compile from source. 56 | 57 | So for example, `3.15.12.3` contains all the binary distributions, while 58 | `3.15.12.2` is the exact same code, but contain only a source-based 59 | distribution 60 | 61 | > This step release system is a workaround to carlhuda/bundler#1537 62 | 63 | ### Using a git version 64 | 65 | If you want to use the latest unstable version of the gem you can do 66 | so by specifying the git repo as a gem source. Just make sure you have 67 | `git-svn` and add the following to your `Gemfile`: 68 | 69 | ```Ruby 70 | gem "libv8", git: "git://github.com/cowboyd/libv8.git", submodules: true 71 | ``` 72 | 73 | You can find more info on using a git repo as a gem source in 74 | [Bundler's documentation](http://bundler.io/v1.3/git.html). 75 | 76 | ### What if I can't install from source? 77 | 78 | If you can fix the "Makefile" so that it correctly compiles for your 79 | platform, we'll pull it right in! 80 | 81 | To get the source, these commands will get you started: 82 | 83 | git clone git://github.com/cowboyd/libv8.git 84 | cd libv8 85 | bundle install 86 | bundle exec rake checkout 87 | bundle exec rake compile 88 | 89 | ### Bring your own V8 90 | 91 | Because libv8 is the interface for the V8 engine used by 92 | [therubyracer](http://github.com/cowboyd/therubyracer), you may need 93 | to use libv8, even if you have V8 installed already. If you wish to 94 | use your own V8 installation, rather than have it built for you, use 95 | the `--with-system-v8` option. 96 | 97 | Using RubyGems: 98 | 99 | gem install libv8 -- --with-system-v8 100 | 101 | Using Bundler (in your Gemfile): 102 | 103 | bundle config build.libv8 --with-system-v8 104 | 105 | Please note that if you intend to run your own V8, you must install 106 | both V8 *and its headers* (found in libv8-dev for Debian distros). 107 | 108 | ### Bring your own compiler 109 | 110 | You can specify a compiler of your choice by either setting the `CXX` 111 | environment variable before compilation, or by adding the 112 | `--with-cxx=` option to the bundle configuration: 113 | 114 | bundle config build.libv8 --with-cxx=clang++ 115 | 116 | ### About 117 | 118 | This project spun off of 119 | [therubyracer](http://github.com/cowboyd/therubyracer) which depends 120 | on having a specific version of v8 to compile and run against. 121 | However, actually delivering that version reliably to all the 122 | different platforms proved to be a challenge to say the least. 123 | 124 | We got tired of waiting 5 minutes for v8 to compile every time we 125 | installed that gem. 126 | 127 | ### Sponsored by 128 | 129 | ![The Frontside](http://github.com/cowboyd/libv8/raw/master/thefrontside.png) 130 | 131 | ### License 132 | 133 | (The MIT License) 134 | 135 | Copyright (c) 2009,2010 Charles Lowell 136 | 137 | Permission is hereby granted, free of charge, to any person obtaining 138 | a copy of this software and associated documentation files (the 139 | 'Software'), to deal in the Software without restriction, including 140 | without limitation the rights to use, copy, modify, merge, publish, 141 | distribute, sublicense, and/or sell copies of the Software, and to 142 | permit persons to whom the Software is furnished to do so, subject to 143 | the following conditions: 144 | 145 | The above copyright notice and this permission notice shall be 146 | included in all copies or substantial portions of the Software. 147 | 148 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 149 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 150 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 151 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 152 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 153 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 154 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 155 | --------------------------------------------------------------------------------