class Ryb::Ninja::Generator
Public Class Methods
new(rybfile, opts)
click to toggle source
# File lib/ryb/ninja.rb, line 4 def initialize(rybfile, opts) @rybfile = rybfile @root = opts.fetch(:root, '.') @build = opts.fetch(:build, '_build') @ninjafile = ::Ninja::File.new @path = opts.fetch(:ninjafile, "#{@root}/build.ninja") # HACK(mtwilliams): Create directory structure. require 'fileutils' FileUtils.mkdir_p(["#@build/bin", "#@build/lib", "#@build/obj"]) # HACK(mtwilliams): Assume VisualStudio. @vs = ::VisualStudio.latest @vc = @vs.products[:c_and_cpp] end
Public Instance Methods
generate()
click to toggle source
# File lib/ryb/ninja.rb, line 20 def generate @ninjafile.rule "mv", "move /Y $in $out" @ninjafile.rule "cp", "move /Y /B $in $out" @ninjafile.save(@path) end
on_product(project, product)
click to toggle source
# File lib/ryb/ninja.rb, line 32 def on_product(project, product) puts " -> Generating for #{product.name.pretty || product.name}" end
on_product_triplet(project, product, tripletised)
click to toggle source
# File lib/ryb/ninja.rb, line 39 def on_product_triplet(project, product, tripletised) tripletised = tripletised.() config = tripletised.configuration.name.to_sym platform = tripletised.platform.name.to_sym arch = tripletised.architecture.name.to_sym puts " ~> #{config} for #{platform} (#{arch})" name = product.name.canonicalize namespace = "#{name}_#{tripletised.triplet.join('_')}" sdk = @vc.sdks[:windows].select{|sdk| sdk.version.to_f >= 7.1}.first sys_include_paths = @vc.includes + sdk.includes sys_lib_paths = @vc.libraries[arch] + sdk.libraries[arch] @ninjafile.variable "#{namespace}_cflags_sys", VisualStudio::Compiler.include_paths_to_flags(sys_include_paths).join(' ') @ninjafile.variable "#{namespace}_cxxflags_sys", "$#{namespace}_cflags_sys" @ninjafile.variable "#{namespace}_ldflags_sys", VisualStudio::Linker.library_paths_to_flags(sys_lib_paths).join(' ') cflags = cflags_for_product(project, product, tripletised) arflags = arflags_for_product(project, product, tripletised) ldflags = ldflags_for_product(project, product, tripletised) @ninjafile.variable "#{namespace}_cflags", cflags.join(' ') @ninjafile.variable "#{namespace}_cxxflags", "$#{namespace}_cflags" @ninjafile.variable "#{namespace}_arflags", arflags.join(' ') @ninjafile.variable "#{namespace}_ldflags", ldflags.join(' ') sources = sources_for_product(product, tripletised) @ninjafile.variable "#{namespace}_sources", sources.map{|src| "#@root/#{src.path}"}.join(' ') deps = deps_for_product(product, tripletised) @ninjafile.variable "#{namespace}_deps", deps.join(' ') artifacts = artifacts_for_product(product, tripletised) @ninjafile.variable "#{namespace}_artifacts", artifacts.join(' ') @ninjafile.variable("#{namespace}_as_linkable", artifacts[0]) if product.is_a? Ryb::Library @ninjafile.variable "#{namespace}_symbols", artifacts[0].gsub(/\.(exe|lib|dll)/, ".pdb") # https://github.com/ninja-build/ninja/blob/d1763746b65cc7349d4ed9478befdb651aa24589/src/msvc_helper_main-win32.cc#L38 env_block = "#@build/#{namespace}.env_block" env = @vc.environment(target: {platform: :windows, architecture: arch}, base: environment) # "PATH=#{(@vc.binaries[arch] + sdk.binaries[arch]).join(';')}\0" File.write(env_block, env.map{|env_var, value| "#{env_var}=#{value}"}.join("\0")) @ninjafile.rule( "cc_#{namespace}", "ninja -t msvc -e #{env_block} -- cl.exe /showIncludes $#{namespace}_cflags_sys $#{namespace}_cflags /Fd$#{namespace}_symbols /Fo$out /Tc$in", dependencies: :msvc ) @ninjafile.rule( "cxx_#{namespace}", "ninja -t msvc -e #{env_block} -- cl.exe /showIncludes $#{namespace}_cxxflags_sys $#{namespace}_cxxflags /Fd$#{namespace}_symbols /Fo$out /Tp$in", dependencies: :msvc ) @ninjafile.rule( "ar_#{namespace}", "ninja -t msvc -e #{env_block} -- lib.exe @$out.rsp", response_file: "$#{namespace}_arflags /OUT:$out $in" ) @ninjafile.rule( "ld_#{namespace}", "ninja -t msvc -e #{env_block} -- link.exe @$out.rsp", response_file: "$#{namespace}_ldflags_sys $#{namespace}_ldflags /OUT:$out $#{namespace}_deps $in" ) @ninjafile.rule( "so_#{namespace}", "ninja -t msvc -e #{env_block} -- link.exe @$out.rsp", response_file: "$#{namespace}_ldflags_sys $#{namespace}_ldflags /DLL /IMPLIB:$#{namespace}_as_linkable /OUT:$out $#{namespace}_deps $in" ) c_sources = sources.select{|src| src.language == :c}.map(&:path).map{|src| "#@root/#{src}"} c_objects = c_sources.map{|src| src.gsub(/\.(c)/, ".#{namespace}.obj")}.map{|obj| "#@build/obj/#{obj}"} cxx_sources = sources.select{|src| src.language == :cpp}.map(&:path).map{|src| "#@root/#{src}"} cxx_objects = cxx_sources.map{|src| src.gsub(/\.(cc|cpp|cxx|c++)/, ".#{namespace}.obj")}.map{|obj| "#@build/obj/#{obj}"} @ninjafile.build "cc_#{namespace}", Hash[c_objects.zip(c_sources)] @ninjafile.build "cxx_#{namespace}", Hash[cxx_objects.zip(cxx_sources)] case product when Ryb::Application @ninjafile.build "ld_#{namespace}", {artifacts[0] => c_objects + cxx_objects} @ninjafile.alias namespace, artifacts[0] when Ryb::Library case product.linkage when :static @ninjafile.build "ar_#{namespace}", {artifacts[0] => c_objects + cxx_objects} @ninjafile.alias namespace, artifacts[0] when :dynamic @ninjafile.build "so_#{namespace}", {artifacts[1] => c_objects + cxx_objects} @ninjafile.alias namespace, artifacts[1] end end end
on_project(project)
click to toggle source
TODO(mtwilliams): Generate phony commands that proxy to all triplets.
# File lib/ryb/ninja.rb, line 28 def on_project(project) puts "=> #{project.name.pretty || project.name}" end
on_project_triplet(project, tripletised)
click to toggle source
# File lib/ryb/ninja.rb, line 36 def on_project_triplet(project, tripletised) end
Private Instance Methods
arflags_for_product(_project, _product, _tripletised)
click to toggle source
# File lib/ryb/ninja.rb, line 241 def arflags_for_product(_project, _product, _tripletised) %w{/nologo} end
artifacts_for_product(product, tripletised)
click to toggle source
# File lib/ryb/ninja.rb, line 208 def artifacts_for_product(product, tripletised) name = product.name.canonicalize config_suffix = tripletised.configuration.suffix || "_#{tripletised.configuration.name}" platform_suffix = tripletised.platform.suffix || "_#{tripletised.platform.name}" arch_suffix = tripletised.architecture.suffix || "_#{tripletised.architecture.name}" suffix = [config_suffix, platform_suffix, arch_suffix].join('') if product.is_a? Ryb::Application ["#@build/bin/#{name}#{suffix}.exe"] elsif product.is_a? Ryb::Library case product.linkage when :static ["#@build/lib/#{name}#{suffix}.lib"] when :dynamic ["#@build/lib/#{name}#{suffix}.lib", "#@build/bin/#{name}#{suffix}.dll"] end end end
cflags_for_architecture(arch)
click to toggle source
# File lib/ryb/ninja.rb, line 277 def cflags_for_architecture(arch) flags = [] # TODO(mtwilliams): @toolchains.for(target) flags += VisualStudio::Compiler.architecture_to_flags(arch.name.canonicalize.to_sym) flags += VisualStudio::Compiler.include_paths_to_flags(arch.paths.includes) if arch.paths flags += VisualStudio::Compiler.defines_to_flags(arch.defines) flags end
cflags_for_configuration(config)
click to toggle source
# File lib/ryb/ninja.rb, line 258 def cflags_for_configuration(config) flags = [] # TODO(mtwilliams): @toolchains.for(target) flags += VisualStudio::Compiler.include_paths_to_flags(config.paths.includes) if config.paths flags += VisualStudio::Compiler.defines_to_flags(config.defines) flags += VisualStudio::Compiler.treat_warnings_as_errors_to_flag(config.treat_warnings_as_errors) flags += VisualStudio::Compiler.generate_debug_symbols_to_flag(config.generate_debug_symbols) flags += VisualStudio::Compiler.optimization_to_flags(config.optimize) flags end
cflags_for_platform(platform)
click to toggle source
# File lib/ryb/ninja.rb, line 269 def cflags_for_platform(platform) flags = [] # TODO(mtwilliams): @toolchains.for(target) flags += VisualStudio::Compiler.include_paths_to_flags(platform.paths.includes) if platform.paths flags += VisualStudio::Compiler.defines_to_flags(platform.defines) flags end
cflags_for_product(project, product, tripletised)
click to toggle source
# File lib/ryb/ninja.rb, line 228 def cflags_for_product(project, product, tripletised) flags = VisualStudio::Compiler::STANDARD_FLAGS + cflags_for_configuration(tripletised.configuration) + cflags_for_platform(tripletised.platform) + cflags_for_architecture(tripletised.architecture) flags += VisualStudio::Compiler.include_paths_to_flags(project.paths.includes) if project.paths flags += VisualStudio::Compiler.include_paths_to_flags(product.paths.includes) if product.paths flags += VisualStudio::Compiler.defines_to_flags(project.defines) flags += VisualStudio::Compiler.defines_to_flags(product.defines) flags += VisualStudio::Compiler.architecture_to_flags(tripletised.architecture.name.to_sym) flags end
deps_for_product(product, tripletised)
click to toggle source
# File lib/ryb/ninja.rb, line 191 def deps_for_product(product, tripletised) deps = [*product.dependencies] | [*tripletised.configuration.dependencies] | [*tripletised.platform.dependencies] | [*tripletised.architecture.dependencies] deps.map do |dep| case dep when Ryb::InternalDependency "${#{dep.product}_#{tripletised.triplet.join('_')}_as_linkable}" when Ryb::ExternalDependency triplet = [tripletised.configuration, tripletised.platform, tripletised.architecture].map(&:name).map(&:to_sym) mangled = dep.mangled(*triplet) "#{mangled}.lib" end end end
environment()
click to toggle source
# File lib/ryb/ninja.rb, line 140 def environment variables = [ 'ALLUSERSPROFILE', 'APPDATA', 'CommonProgramFiles', 'CommonProgramFiles(x86)', 'CommonProgramW6432', 'ComSpec', 'HOMEDRIVE', 'HOMEPATH', 'LOCALAPPDATA', 'Path', 'PATHEXT', 'ProgramData', 'ProgramFiles', 'ProgramFiles(x86)', 'ProgramW6432', 'PUBLIC', 'SystemDrive', 'SystemRoot', 'TEMP', 'TMP', 'USERDOMAIN', 'USERNAME', 'USERPROFILE', 'windir' ] @environment ||= begin require 'win32/registry' ::Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment", ::Win32::Registry::KEY_READ) do |originals| variables.map { |variable| value = begin originals[variable] rescue ENV[variable] end [variable, value] }.to_h end end end
ldflags_for_architecture(arch)
click to toggle source
# File lib/ryb/ninja.rb, line 301 def ldflags_for_architecture(arch) flags = [] # TODO(mtwilliams): @toolchains.for(target) flags += VisualStudio::Linker.library_paths_to_flags(arch.paths.libraries) if arch.paths flags end
ldflags_for_configuration(config)
click to toggle source
# File lib/ryb/ninja.rb, line 286 def ldflags_for_configuration(config) flags = [] # TODO(mtwilliams): @toolchains.for(target) flags += VisualStudio::Linker.library_paths_to_flags(config.paths.libraries) if config.paths flags += VisualStudio::Linker.generate_debug_symbols_to_flag(config.generate_debug_symbols) flags end
ldflags_for_platform(platform)
click to toggle source
# File lib/ryb/ninja.rb, line 294 def ldflags_for_platform(platform) flags = [] # TODO(mtwilliams): @toolchains.for(target) flags += VisualStudio::Linker.library_paths_to_flags(platform.paths.libraries) if platform.paths flags end
ldflags_for_product(project, product, tripletised)
click to toggle source
# File lib/ryb/ninja.rb, line 245 def ldflags_for_product(project, product, tripletised) flags = VisualStudio::Linker::STANDARD_FLAGS + ldflags_for_configuration(tripletised.configuration) + ldflags_for_platform(tripletised.platform) + ldflags_for_architecture(tripletised.architecture) flags += VisualStudio::Linker.library_paths_to_flags(project.paths.libraries) if project.paths flags += VisualStudio::Linker.library_paths_to_flags(product.paths.libraries) if product.paths flags += VisualStudio::Linker.architecture_to_flags(tripletised.architecture.name.to_sym) # TODO: Linkage. flags end
sources_for_product(product, tripletised)
click to toggle source
# File lib/ryb/ninja.rb, line 183 def sources_for_product(product, tripletised) sources = [*product.sources] | [*tripletised.configuration.sources] | [*tripletised.platform.sources] | [*tripletised.architecture.sources] sources.reject{|src| src.inconsequential}.compact.uniq end