PageRenderTime 37ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/Rakefile

http://github.com/shoes/shoes
Rakefile | 495 lines | 410 code | 69 blank | 16 comment | 26 complexity | 7d66bf0a301782dba8b93e19a7fa8c3e MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, 0BSD, BSD-3-Clause
  1. $:.unshift '.'
  2. require 'rubygems'
  3. require 'rake'
  4. require 'rake/clean'
  5. if RUBY_VERSION != '1.8.7'
  6. require_relative 'platform/skel'
  7. else
  8. require File.join(File.dirname(__FILE__), 'platform/skel')
  9. end
  10. require 'fileutils'
  11. require 'find'
  12. require 'yaml'
  13. include FileUtils
  14. # Use Syck for backward compatibility
  15. YAML::ENGINE.yamler = 'syck'
  16. APP = YAML.load_file(File.join(ENV['APP'] || ".", "app.yaml"))
  17. APPNAME = APP['name']
  18. RELEASE_ID, RELEASE_NAME = APP['version'], APP['release']
  19. NAME = APP['shortname'] || APP['name'].downcase.gsub(/\W+/, '')
  20. SONAME = 'shoes'
  21. # Like puts, but only if we've --trace'd
  22. def vputs(str)
  23. puts str if Rake.application.options.trace
  24. end
  25. begin
  26. require 'cucumber'
  27. require 'cucumber/rake/task'
  28. Cucumber::Rake::Task.new(:features) do |t|
  29. t.cucumber_opts = "--format pretty"
  30. end
  31. rescue LoadError
  32. vputs("Cukes is not loaded -- please `bundle install`")
  33. end
  34. begin
  35. require 'rspec/core/rake_task'
  36. RSpec::Core::RakeTask.new(:spec) do |t|
  37. t.rspec_opts = ["--color"]
  38. end
  39. rescue LoadError
  40. vputs("RSpec is not loaded -- please `bundle install`")
  41. end
  42. begin
  43. require 'bundler'
  44. Bundler::GemHelper.install_tasks
  45. rescue LoadError
  46. vputs("Bundler is not loaded -- please `gem install bundler && bundle install`")
  47. end
  48. GIT = ENV['GIT'] || "git"
  49. REVISION = (`#{GIT} rev-list HEAD`.split.length + 1).to_s
  50. VERS = ENV['VERSION'] || "0.r#{REVISION}"
  51. PKG = "#{NAME}-#{VERS}"
  52. APPARGS = APP['run']
  53. FLAGS = %w[DEBUG VIDEO]
  54. VLC_VERSION = (RUBY_PLATFORM =~ /win32/ ? "0.8": `vlc --version 2>/dev/null`.split[2])
  55. VLC_0_8 = VLC_VERSION !~ /^0\.9/
  56. BIN = "*.{bundle,jar,o,so,obj,pdb,pch,res,lib,def,exp,exe,ilk}"
  57. CLEAN.include ["{bin,shoes}/#{BIN}", "req/**/#{BIN}", "dist/**/*", "dist", "*.app"]
  58. RUBY_SO = RbConfig::CONFIG['RUBY_SO_NAME']
  59. RUBY_V = RbConfig::CONFIG['ruby_version']
  60. RUBY_LIB_BASE = File.basename(RbConfig::CONFIG['libdir'])
  61. RUBY_PROGRAM_VERSION = RbConfig::CONFIG['RUBY_PROGRAM_VERSION']
  62. SHOES_RUBY_ARCH = RbConfig::CONFIG['arch']
  63. RUBY_1_9 = (RUBY_V =~ /^1\.9/)
  64. if RUBY_1_9
  65. $: << "."
  66. end
  67. if ENV['APP']
  68. %w[dmg icons].each do |subk|
  69. APP[subk].keys.each do |name|
  70. APP[subk][name] = File.join(ENV['APP'], APP[subk][name])
  71. end
  72. end
  73. end
  74. if File.exists? ".git/refs/tags/#{RELEASE_ID}/#{RELEASE_NAME}"
  75. abort "** Rename this release (and add to lib/shoes.rb) #{RELEASE_NAME} has already been tagged."
  76. end
  77. # Same effect as sourcing a shell script before running rake. It's necessary to
  78. # set these values before the make/{platform}/env.rb files are loaded.
  79. def osx_bootstrap_env
  80. ENV['DYLD_LIBRARY_PATH'] = '/usr/local/Cellar/cairo/1.10.2/lib:/usr/local/Cellar/cairo/1.10.2/include/cairo'
  81. ENV['LD_LIBRARY_PATH'] = '/usr/local/Cellar/cairo/1.10.2/lib:/usr/local/Cellar/cairo/1.10.2/include/cairo'
  82. ENV['CAIRO_CFLAGS'] = '-I/usr/local/Cellar/cairo/1.10.2/include/cairo'
  83. ENV['SHOES_DEPS_PATH'] = '/usr/local'
  84. end
  85. case RUBY_PLATFORM
  86. when /mingw/
  87. require File.expand_path('rakefile_mingw')
  88. Builder = MakeMinGW
  89. NAMESPACE = :win32
  90. when /darwin/
  91. osx_bootstrap_env
  92. require File.expand_path('make/darwin/env')
  93. require_relative "make/darwin/homebrew"
  94. import "tasks/req.rake"
  95. task :stub do
  96. ENV['MACOSX_DEPLOYMENT_TARGET'] = '10.4'
  97. sh "gcc -O -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc -framework Cocoa -o stub platform/mac/stub.m -I."
  98. end
  99. NAMESPACE = :osx
  100. when /linux/
  101. require File.expand_path('rakefile_linux')
  102. Builder = MakeLinux
  103. NAMESPACE = :linux
  104. else
  105. puts "Sorry, your platform [#{RUBY_PLATFORM}] is not supported..."
  106. end
  107. # --------------------------
  108. # common platform tasks
  109. desc "Same as `rake build'"
  110. task :default => [:build]
  111. desc "Does a full compile, with installer"
  112. task :package => [:build, :installer]
  113. task :build_os => [:build_skel, "dist/#{NAME}"]
  114. task "shoes/version.h" do |t|
  115. File.open(t.name, 'w') do |f|
  116. f << %{#define SHOES_RELEASE_ID #{RELEASE_ID}\n#define SHOES_RELEASE_NAME "#{RELEASE_NAME}"\n#define SHOES_REVISION #{REVISION}\n#define SHOES_BUILD_DATE #{Time.now.strftime("%Y%m%d")}\n#define SHOES_PLATFORM "#{SHOES_RUBY_ARCH}"\n}
  117. end
  118. end
  119. task "dist/VERSION.txt" do |t|
  120. File.open(t.name, 'w') do |f|
  121. f << %{shoes #{RELEASE_ID} \"#{RELEASE_NAME}\" [#{RUBY_PLATFORM} Ruby-#{RUBY_VERSION}]}
  122. %w[VIDEO DEBUG].each { |x| f << " +#{x.downcase}" if ENV[x] }
  123. f << "\n"
  124. end
  125. end
  126. # shoes is small, if any include changes, go ahead and build from scratch.
  127. SRC.zip(OBJ).each do |c, o|
  128. file o => [c] + Dir["shoes/*.h"]
  129. end
  130. # ------
  131. # skel
  132. def skel_replace(line)
  133. line.gsub! /\s+%DEFAULTS%/ do
  134. if APPARGS
  135. args = APPARGS.split(/\s+/)
  136. %{
  137. char *default_argv[] = {argv[0], #{args.inspect[1..-2]}};
  138. argv = default_argv;
  139. argc = #{args.length + 1};
  140. }
  141. end
  142. end
  143. line
  144. end
  145. # preprocess .skel
  146. task :build_skel do |t|
  147. Dir["bin/*.skel"].each do |src|
  148. name = src.gsub(/\.skel$/, '.c')
  149. File.open(src) do |skel|
  150. File.open(name, 'w') do |c|
  151. skel.each_line do |line|
  152. c << skel_replace(line)
  153. end
  154. end
  155. end
  156. end
  157. end
  158. # --------------------------
  159. # tasks depending on Builder = MakeLinux|MakeDarwin|MakeMinGW
  160. desc "Does a full compile, for the OS you're running on"
  161. task :build => ["#{NAMESPACE}:build"]
  162. # first refactor ; build calls platform namespaced build;
  163. # for now, each of those calls the old build method.
  164. task :old_build => [:build_os, "dist/VERSION.txt"] do
  165. Builder.common_build
  166. Builder.copy_deps_to_dist
  167. Builder.copy_files_to_dist
  168. Builder.setup_system_resources
  169. end
  170. directory 'dist'
  171. task "dist/#{NAME}" => ["dist/lib#{SONAME}.#{DLEXT}", "bin/main.o"] + ADD_DLL + ["#{NAMESPACE}:make_app"]
  172. task "dist/lib#{SONAME}.#{DLEXT}" => ['shoes/version.h', 'dist'] + OBJ + ["#{NAMESPACE}:make_so"]
  173. def cc(t)
  174. sh "#{CC} -I. -c -o #{t.name} #{LINUX_CFLAGS} #{t.source}"
  175. end
  176. rule ".o" => ".m" do |t|
  177. cc t
  178. end
  179. rule ".o" => ".c" do |t|
  180. cc t
  181. end
  182. desc "Generate an installer for the current platform"
  183. task :installer => ["#{NAMESPACE}:installer"]
  184. def rewrite before, after, reg = /\#\{(\w+)\}/, reg2 = '\1'
  185. File.open(after, 'w') do |a|
  186. File.open(before) do |b|
  187. b.each do |line|
  188. a << line.gsub(reg) do
  189. if reg2.include? '\1'
  190. reg2.gsub(%r!\\1!, Object.const_get($1))
  191. else
  192. reg2
  193. end
  194. end
  195. end
  196. end
  197. end
  198. end
  199. def copy_files glob, dir
  200. FileList[glob].each { |f| cp_r f, dir }
  201. end
  202. namespace :osx do
  203. namespace :deps do
  204. task :install => "homebrew:install"
  205. namespace :homebrew do
  206. desc "Install OS X dependencies using Homebrew"
  207. task :install => [:customize, :install_libs, :uncustomize]
  208. task :install_libs do
  209. brew = Homebrew.new
  210. brew.universal if ENV['SHOES_OSX_ARCH'] == "universal"
  211. brew.install_packages
  212. end
  213. task :customize do
  214. brew = Homebrew.new
  215. brew.universal if ENV['SHOES_OSX_ARCH'] == "universal"
  216. brew.add_custom_remote
  217. brew.add_custom_formulas
  218. end
  219. task :uncustomize do
  220. brew = Homebrew.new
  221. brew.universal if ENV['SHOES_OSX_ARCH'] == "universal"
  222. brew.remove_custom_formulas
  223. brew.remove_custom_remote
  224. end
  225. end
  226. end
  227. task :build => ["build_tasks:pre_build", :build_skel, "dist/#{NAME}", "dist/VERSION.txt", "build_tasks:build"]
  228. namespace :build_tasks do
  229. task :build => [:common_build, :copy_deps_to_dist, :change_install_names, :copy_files_to_dist, :setup_system_resources, :verify]
  230. # Make sure the installed ruby is capable of this build
  231. task :check_ruby_arch do
  232. build_arch, ruby_arch = [OSX_ARCH, RbConfig::CONFIG['ARCH_FLAG']].map {|s| s.split.reject {|w| w.include?("arch")}}
  233. if build_arch.length > 1 and build_arch.sort != ruby_arch.sort
  234. abort("To build universal shoes, you must first install a universal ruby")
  235. end
  236. end
  237. task :pre_build => :check_ruby_arch
  238. def dylibs_to_change lib
  239. `otool -L #{lib}`.split("\n").inject([]) do |dylibs, line|
  240. if line =~ /^\S/ or line =~ /System|@executable_path|libobjc/
  241. dylibs
  242. else
  243. dylibs << line.gsub(/\s\(compatibility.*$/, '').strip
  244. end
  245. end
  246. end
  247. # Find additional dylibs needed by other_lib (ignoring duplicates)
  248. def additional_dylibs dylibs, other_lib
  249. dylibs_to_change(other_lib).delete_if do |d|
  250. basenames = dylibs.map { |lib| File.basename(lib) }
  251. basenames.include? File.basename(d)
  252. end
  253. end
  254. task :change_install_names do
  255. cd "dist" do
  256. ["#{NAME}-bin", "pango-querymodules", *Dir['*.dylib'], *Dir['pango/modules/*.so']].each do |f|
  257. sh "install_name_tool -id @executable_path/#{File.basename f} #{f}"
  258. dylibs = dylibs_to_change(f)
  259. dylibs.each do |dylib|
  260. sh "install_name_tool -change #{dylib} @executable_path/#{File.basename dylib} #{f}"
  261. end
  262. end
  263. end
  264. end
  265. task :copy_pango_modules_to_dist do
  266. modules_file = `brew --prefix`.chomp << '/etc/pango/pango.modules'
  267. modules_path = File.open(modules_file) {|f| f.grep(/^# ModulesPath = (.*)$/){$1}.first}
  268. mkdir_p 'dist/pango'
  269. unless File.exists?('dist/pango/modules')
  270. cp_r modules_path, 'dist/pango'
  271. end
  272. unless File.exists?("dist/pango-querymodules")
  273. cp `which pango-querymodules`.chomp, 'dist/'
  274. end
  275. end
  276. task :copy_deps_to_dist => :copy_pango_modules_to_dist do
  277. # Generate a list of dependencies straight from the generated files.
  278. # Start with dependencies of shoes-bin and pango-querymodules, and then
  279. # add the dependencies of those dependencies.
  280. dylibs = dylibs_to_change("dist/#{NAME}-bin")
  281. dylibs.dup.each do |dylib|
  282. dylibs.concat additional_dylibs(dylibs, dylib)
  283. end
  284. dylibs.each {|libn| cp "#{libn}", "dist/"}
  285. # Verbose mode raises an exception (ruby bug?)
  286. chmod_R "u+w", "dist/", :verbose => false
  287. end
  288. task :copy_files_to_dist do
  289. if ENV['APP']
  290. if APP['clone']
  291. sh APP['clone'].gsub(/^git /, "#{GIT} --git-dir=#{ENV['APP']}/.git ")
  292. else
  293. cp_r ENV['APP'], "dist/app"
  294. end
  295. if APP['ignore']
  296. APP['ignore'].each do |nn|
  297. rm_rf "dist/app/#{nn}"
  298. end
  299. end
  300. end
  301. cp_r "fonts", "dist/fonts"
  302. cp_r "lib", "dist/lib"
  303. cp_r "samples", "dist/samples"
  304. cp_r "static", "dist/static"
  305. cp "README.md", "dist/README.txt"
  306. cp "CHANGELOG", "dist/CHANGELOG.txt"
  307. cp "COPYING", "dist/COPYING.txt"
  308. end
  309. task :setup_system_resources do
  310. rm_rf "#{APPNAME}.app"
  311. mkdir "#{APPNAME}.app"
  312. mkdir "#{APPNAME}.app/Contents"
  313. cp_r "dist", "#{APPNAME}.app/Contents/MacOS"
  314. mkdir "#{APPNAME}.app/Contents/Resources"
  315. mkdir "#{APPNAME}.app/Contents/Resources/English.lproj"
  316. sh "ditto \"#{APP['icons']['osx']}\" \"#{APPNAME}.app/App.icns\""
  317. sh "ditto \"#{APP['icons']['osx']}\" \"#{APPNAME}.app/Contents/Resources/App.icns\""
  318. rewrite "platform/mac/Info.plist", "#{APPNAME}.app/Contents/Info.plist"
  319. cp "platform/mac/version.plist", "#{APPNAME}.app/Contents/"
  320. rewrite "platform/mac/pangorc", "#{APPNAME}.app/Contents/MacOS/pangorc"
  321. cp "platform/mac/command-manual.rb", "#{APPNAME}.app/Contents/MacOS/"
  322. rewrite "platform/mac/shoes-launch", "#{APPNAME}.app/Contents/MacOS/#{NAME}-launch"
  323. chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}-launch"
  324. chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}-bin"
  325. rewrite "platform/mac/shoes", "#{APPNAME}.app/Contents/MacOS/#{NAME}"
  326. chmod 0755, "#{APPNAME}.app/Contents/MacOS/#{NAME}"
  327. chmod_R 0755, "#{APPNAME}.app/Contents/MacOS/pango-querymodules"
  328. # cp InfoPlist.strings YourApp.app/Contents/Resources/English.lproj/
  329. `echo -n 'APPL????' > "#{APPNAME}.app/Contents/PkgInfo"`
  330. end
  331. end
  332. desc "Verify the build products"
  333. task :verify => ['verify:sanity', 'verify:lib_paths']
  334. namespace :verify do
  335. def report_error message
  336. STDERR.puts "BUILD ERROR: " + message
  337. end
  338. task :sanity do
  339. report_error "No #{APPNAME}.app file found" unless File.exist? "#{APPNAME}.app"
  340. [NAME, "#{NAME}-launch", "#{NAME}-bin"].each do |f|
  341. report_error "No #{f} file found" unless File.exist? "#{APPNAME}.app/Contents/MacOS/#{f}"
  342. end
  343. end
  344. task :lib_paths do
  345. cd "#{APPNAME}.app/Contents/MacOS" do
  346. errors = []
  347. ["#{NAME}-bin", "pango-querymodules", *Dir['*.dylib'], *Dir['pango/modules/*.so']].each do |f|
  348. dylibs = dylibs_to_change(f)
  349. dylibs.each do |dylib|
  350. errors << "Suspect library path on #{f}:\n #{dylib}\n (check with `otool -L #{File.expand_path f}`)"
  351. end
  352. end
  353. errors.each {|e| report_error e}
  354. end
  355. end
  356. end
  357. task :make_app do
  358. # Builder.make_app "dist/#{NAME}"
  359. bin = "dist/#{NAME}-bin"
  360. rm_f "dist/#{NAME}"
  361. rm_f bin
  362. sh "#{CC} -Ldist -o #{bin} bin/main.o #{LINUX_LIBS} -lshoes #{OSX_ARCH}"
  363. end
  364. task :make_so do
  365. name = "dist/lib#{SONAME}.#{DLEXT}"
  366. ldflags = LINUX_LDFLAGS.sub! /INSTALL_NAME/, "-install_name @executable_path/lib#{SONAME}.#{DLEXT}"
  367. sh "#{CC} -o #{name} #{OBJ.join(' ')} #{LINUX_LDFLAGS} #{LINUX_LIBS}"
  368. %w[libpostproc.dylib libavformat.dylib libavcodec.dylib libavutil.dylib libruby.dylib].each do |libn|
  369. sh "install_name_tool -change /tmp/dep/lib/#{libn} ./deps/lib/#{libn} #{name}"
  370. end
  371. end
  372. task :installer do
  373. dmg_ds, dmg_jpg = "platform/mac/dmg_ds_store", "static/shoes-dmg.jpg"
  374. if APP['dmg']
  375. dmg_ds, dmg_jpg = APP['dmg']['ds_store'], APP['dmg']['background']
  376. end
  377. mkdir_p "pkg"
  378. rm_rf "dmg"
  379. mkdir_p "dmg"
  380. cp_r "#{APPNAME}.app", "dmg"
  381. unless ENV['APP']
  382. mv "dmg/#{APPNAME}.app/Contents/MacOS/samples", "dmg/samples"
  383. end
  384. ln_s "/Applications", "dmg/Applications"
  385. sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/pango-querymodules"
  386. sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}"
  387. sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}-bin"
  388. sh "chmod +x dmg/\"#{APPNAME}.app\"/Contents/MacOS/#{NAME}-launch"
  389. sh "DYLD_LIBRARY_PATH= platform/mac/pkg-dmg --target pkg/#{PKG}.dmg --source dmg --volname '#{APPNAME}' --copy #{dmg_ds}:/.DS_Store --mkdir /.background --copy #{dmg_jpg}:/.background" # --format UDRW"
  390. rm_rf "dmg"
  391. end
  392. end
  393. namespace :win32 do
  394. task :build => [:old_build]
  395. task :make_app do
  396. Builder.make_app "dist/#{NAME}"
  397. end
  398. task :make_so do
  399. Builder.make_so "dist/lib#{SONAME}.#{DLEXT}"
  400. end
  401. task :installer do
  402. Builder.make_installer
  403. end
  404. end
  405. namespace :linux do
  406. task :build => [:old_build]
  407. task :make_app do
  408. Builder.make_app "dist/#{NAME}"
  409. end
  410. task :make_so do
  411. Builder.make_so "dist/lib#{SONAME}.#{DLEXT}"
  412. end
  413. task :installer do
  414. Builder.make_installer
  415. end
  416. end