mirror of
https://github.com/kp2pml30/ya-build.git
synced 2026-02-17 00:14:42 +04:00
become more close to actual ninja
This commit is contained in:
parent
b44e5373ed
commit
1ece0617dc
1 changed files with 327 additions and 270 deletions
527
ya-build
527
ya-build
|
|
@ -66,72 +66,103 @@ class OpenStruct
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def escape_args_to(buf, args)
|
class NinjaPiece
|
||||||
args.each { |a|
|
protected def dump_ninja(buf)
|
||||||
|
raise "abstract"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class NinjaPieceRaw
|
||||||
|
def initialize(data)
|
||||||
|
@data = data
|
||||||
|
end
|
||||||
|
def dump_ninja(buf)
|
||||||
|
buf << @data << "\n\n"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Target < NinjaPiece
|
||||||
|
attr_reader :meta, :outputs, :inputs, :implicit_inputs, :implicit_outputs, :rule
|
||||||
|
|
||||||
|
def initialize(outputs:, inputs:, rule:, implicit_inputs: [], implicit_outputs: [])
|
||||||
|
raise "invalid param" if not outputs.kind_of?(Array)
|
||||||
|
raise "invalid param" if not inputs.kind_of?(Array)
|
||||||
|
raise "invalid param" if not implicit_inputs.kind_of?(Array)
|
||||||
|
raise "invalid param" if not implicit_outputs.kind_of?(Array)
|
||||||
|
raise "rule must be a string" if not rule.kind_of?(String)
|
||||||
|
|
||||||
|
@meta = OpenStruct.new
|
||||||
|
@implicit_inputs = implicit_inputs
|
||||||
|
@implicit_outputs = implicit_outputs
|
||||||
|
@inputs = inputs.clone
|
||||||
|
@outputs = outputs.clone
|
||||||
|
@rule = rule
|
||||||
|
end
|
||||||
|
|
||||||
|
def dump_ninja(buf)
|
||||||
|
raise "no output" if outputs.size == 0
|
||||||
|
buf << "build"
|
||||||
|
DefaultTargets::escape_args_to(buf, outputs)
|
||||||
|
if implicit_outputs.size > 0
|
||||||
|
buf << " |"
|
||||||
|
DefaultTargets::escape_args_to(buf, implicit_outputs)
|
||||||
|
end
|
||||||
|
buf << " : #{rule}"
|
||||||
|
DefaultTargets::escape_args_to(buf, inputs)
|
||||||
|
if implicit_inputs.size > 0
|
||||||
|
buf << " |"
|
||||||
|
DefaultTargets::escape_args_to(buf, implicit_inputs)
|
||||||
|
end
|
||||||
|
buf << "\n"
|
||||||
|
cb = Proc.new { |k, v|
|
||||||
|
buf << " " << k << " = " << v << "\n"
|
||||||
|
}
|
||||||
|
dump_vars cb
|
||||||
|
buf << "\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
protected def dump_vars(cb)
|
||||||
|
raise "abstract for #{self}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module DefaultTargets
|
||||||
|
|
||||||
|
def self.escape_args_to(buf, args)
|
||||||
|
raise "buf can't be nil" if buf.nil?
|
||||||
|
dump_args = args.flat_map { |arg|
|
||||||
|
if arg.kind_of?(Target)
|
||||||
|
arg.outputs + arg.implicit_outputs
|
||||||
|
elsif arg.kind_of?(Pathname)
|
||||||
|
[arg.to_s]
|
||||||
|
elsif arg.kind_of?(String)
|
||||||
|
[arg]
|
||||||
|
else
|
||||||
|
raise "unsupported type #{arg.class} of #{arg}"
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
dump_args.each { |a|
|
||||||
buf << ' '
|
buf << ' '
|
||||||
buf << Shellwords.escape(a).gsub(/\\=/, '=')
|
buf << Shellwords.escape(a).gsub(/\\=/, '=')
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
class Target
|
class Phony < Target
|
||||||
attr_reader :trg_name, :meta, :outputs
|
attr_reader :name
|
||||||
|
def initialize(name:, inputs:, implicit_inputs: [])
|
||||||
def initialize(trg_name, dependencies)
|
super(outputs: [name].freeze, inputs: inputs, implicit_inputs: implicit_inputs, implicit_outputs: [].freeze, rule: "phony")
|
||||||
@meta = OpenStruct.new
|
@name = name
|
||||||
if dependencies.nil?
|
|
||||||
raise "dependencies can't be nil"
|
|
||||||
end
|
|
||||||
@trg_name = trg_name
|
|
||||||
if @trg_name.kind_of?(Pathname)
|
|
||||||
@trg_name = @trg_name.to_s
|
|
||||||
end
|
|
||||||
@outputs = [trg_name]
|
|
||||||
raise "target name is not a string (got `#{@trg_name}`)" if not @trg_name.kind_of?(String)
|
|
||||||
@dependencies = dependencies
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_deps(*deps)
|
protected def dump_vars(cb)
|
||||||
@dependencies.concat(deps.flatten)
|
|
||||||
end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
"<#{self.class.name}:#{@trg_name}>"
|
|
||||||
end
|
|
||||||
|
|
||||||
def dump_rules(buf)
|
|
||||||
buf << "build "
|
|
||||||
escape_args_to(buf, outputs)
|
|
||||||
buf << ": #{mode}"
|
|
||||||
@dependencies.each { |d|
|
|
||||||
buf << ' '
|
|
||||||
if d.kind_of?(Target)
|
|
||||||
buf << d.trg_name
|
|
||||||
elsif d.kind_of?(Pathname)
|
|
||||||
buf << d.to_s
|
|
||||||
elsif d.kind_of?(String)
|
|
||||||
buf << d
|
|
||||||
else
|
|
||||||
raise "Invalid dependency #{d} : #{d.class} for #{self}"
|
|
||||||
end
|
|
||||||
}
|
|
||||||
buf << "\n"
|
|
||||||
dump_rules_impl(buf)
|
|
||||||
buf << "\n\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
def mode
|
|
||||||
raise "abstract"
|
|
||||||
end
|
|
||||||
|
|
||||||
protected def dump_rules_impl(buf)
|
|
||||||
raise "abstract"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class CommandTarget < Target
|
class Command < Target
|
||||||
attr_reader :output_file
|
attr_reader :output_file
|
||||||
def initialize(output_file, dependencies, cwd, commands, depfile, pool, env)
|
def initialize(output_file, dependencies, cwd, commands, depfile, pool, env)
|
||||||
super(output_file, dependencies)
|
super(outputs: [output_file], inputs: dependencies, rule: 'CUSTOM_COMMAND')
|
||||||
@env = env
|
@env = env
|
||||||
@depfile = depfile
|
@depfile = depfile
|
||||||
@output_file = output_file
|
@output_file = output_file
|
||||||
|
|
@ -140,139 +171,106 @@ class CommandTarget < Target
|
||||||
@pool = pool
|
@pool = pool
|
||||||
end
|
end
|
||||||
|
|
||||||
protected def dump_rules_impl(buf)
|
protected def dump_vars(cb)
|
||||||
if @env.size > 0
|
if @env.size > 0
|
||||||
buf << " ENV = env"
|
buf = String.new
|
||||||
|
buf << "env"
|
||||||
@env.each { |k, v|
|
@env.each { |k, v|
|
||||||
buf << ' ' << k << '=' << Shellwords.escape(v).gsub(/\\=/, '=')
|
buf << ' ' << k << '=' << Shellwords.escape(v).gsub(/\\=/, '=')
|
||||||
}
|
}
|
||||||
buf << "\n"
|
cb.('ENV', buf)
|
||||||
end
|
end
|
||||||
if not @pool.nil?
|
if not @pool.nil?
|
||||||
buf << " pool = #{@pool}\n"
|
cb.('pool', @pool)
|
||||||
end
|
end
|
||||||
if not @cwd.nil?
|
if not @cwd.nil?
|
||||||
buf << " WD = #{Shellwords.escape @cwd}\n"
|
cb.('CWD', Shellwords.escape(@cwd))
|
||||||
end
|
end
|
||||||
if not @depfile.nil?
|
if not @depfile.nil?
|
||||||
buf << " depfile = #{@depfile}\n"
|
cb.('depfile', Shellwords.escape(@depfile))
|
||||||
end
|
end
|
||||||
buf << " COMMAND ="
|
cmd = String.new
|
||||||
@commands.each_with_index { |c, i|
|
@commands.each_with_index { |c, i|
|
||||||
if i != 0
|
if i != 0
|
||||||
buf << " &&"
|
cmd << " &&"
|
||||||
end
|
end
|
||||||
escape_args_to(buf, c)
|
DefaultTargets::escape_args_to(cmd, c)
|
||||||
}
|
}
|
||||||
buf << "\n"
|
cb.('COMMAND', cmd)
|
||||||
end
|
|
||||||
|
|
||||||
def mode
|
|
||||||
"CUSTOM_COMMAND"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class ConfigureGeneratedTarget < Target
|
class ConfigureGenerated < Target
|
||||||
def initialize(configurator, output_file)
|
def initialize(configurator)
|
||||||
@configurator = configurator
|
@configurator = configurator
|
||||||
super(output_file, [])
|
super(outputs: [], inputs: [], rule: 'RERUN_YA_BUILD')
|
||||||
end
|
end
|
||||||
def dump_rules_impl(buf)
|
|
||||||
buf << " pool = console\n"
|
def dump_vars(cb)
|
||||||
end
|
cb.('pool', 'console')
|
||||||
def mode
|
|
||||||
"RERUN_YA_BUILD"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class CTarget < Target
|
class C < Target
|
||||||
attr_reader :output_file
|
attr_reader :output_file
|
||||||
def initialize(output_file, mode, dependencies, flags, cc, root_dir)
|
def initialize(output:, inputs:, flags:, cc:, rule:, root_dir: nil)
|
||||||
super(output_file, dependencies)
|
super(outputs: [output].freeze, inputs: inputs, rule: rule)
|
||||||
@root_dir = root_dir
|
@root_dir = root_dir
|
||||||
@mode = mode
|
@output_file = output
|
||||||
@output_file = output_file
|
|
||||||
@flags = flags
|
@flags = flags
|
||||||
@cc = cc
|
@cc = cc
|
||||||
end
|
end
|
||||||
|
|
||||||
protected def dump_rules_impl(buf)
|
protected def dump_vars(cb)
|
||||||
if @mode != "link"
|
|
||||||
buf << " ROOT_DIR = #{Shellwords.escape @root_dir}/\n"
|
|
||||||
end
|
|
||||||
if not @cc.nil?
|
if not @cc.nil?
|
||||||
buf << " CC = #{@cc}\n"
|
cb.('CC', Shellwords.escape(@cc))
|
||||||
|
end
|
||||||
|
if not @root_dir.nil?
|
||||||
|
cb.('ROOT_DIR', Shellwords.escape(@root_dir))
|
||||||
end
|
end
|
||||||
if not @flags.nil? and not @flags.empty?
|
if not @flags.nil? and not @flags.empty?
|
||||||
buf << " cflags ="
|
cflags = String.new
|
||||||
escape_args_to(buf, @flags)
|
DefaultTargets::escape_args_to(cflags, @flags)
|
||||||
buf << "\n"
|
cb.('cflags', cflags)
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def mode()
|
|
||||||
case @mode
|
|
||||||
when "compile"
|
|
||||||
"COMPILE_C"
|
|
||||||
when "link"
|
|
||||||
"LINK_C"
|
|
||||||
else
|
|
||||||
raise "unknown mode #{@mode}"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class AliasTarget < Target
|
class Copy < Target
|
||||||
def initialize(name, dependencies)
|
|
||||||
super(name, dependencies)
|
|
||||||
end
|
|
||||||
|
|
||||||
protected def dump_rules_impl(buf)
|
|
||||||
end
|
|
||||||
|
|
||||||
def mode()
|
|
||||||
"phony"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class CopyTarget < Target
|
|
||||||
def initialize(dest, src)
|
def initialize(dest, src)
|
||||||
super(dest, [src])
|
super(outputs: [dest].freeze, inputs: src, rule: "COPY")
|
||||||
end
|
end
|
||||||
|
|
||||||
protected def dump_rules_impl(buf)
|
protected def dump_vars(buf)
|
||||||
end
|
end
|
||||||
|
|
||||||
def mode()
|
|
||||||
"COPY"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class Configurator
|
class Configurator
|
||||||
attr_reader :root_src, :root_build, :config, :logger
|
attr_reader :root_src, :root_build, :config, :logger, :ninja_path, :ninja_files_parts
|
||||||
|
|
||||||
private def get_tag_target(tag)
|
private def get_tag_target(tag)
|
||||||
ret = @tags[tag]
|
ret = @tags[tag]
|
||||||
return ret if not ret.nil?
|
return ret if not ret.nil?
|
||||||
ret = AliasTarget.new("tags/#{tag}", [])
|
ret = DefaultTargets::Phony.new(name: "tags/#{tag}", inputs: [])
|
||||||
@tags[tag] = ret
|
@tags[tag] = ret
|
||||||
register_target(ret)
|
register_target(ret)
|
||||||
ret
|
ret
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(src, build, preloads)
|
def initialize(src, build, preloads)
|
||||||
@rules = []
|
|
||||||
@root_src = Pathname.new(src).realpath
|
@root_src = Pathname.new(src).realpath
|
||||||
@root_build = Pathname.new(build)
|
@root_build = Pathname.new(build)
|
||||||
@root_build.mkpath()
|
@root_build.mkpath()
|
||||||
@root_build = @root_build.realpath
|
@root_build = @root_build.realpath
|
||||||
|
|
||||||
@trivial_targets = String.new
|
@ninja_files_parts = Hash.new
|
||||||
|
@ninja_files_parts[''] = []
|
||||||
|
|
||||||
@tags = {}
|
@tags = {}
|
||||||
|
|
||||||
@config_target = ConfigureGeneratedTarget.new(self, 'build.ninja')
|
@config_target = DefaultTargets::ConfigureGenerated.new(self)
|
||||||
@targets = [@config_target]
|
@named_targets = []
|
||||||
|
|
||||||
@stack = []
|
@stack = []
|
||||||
|
|
||||||
|
|
@ -285,18 +283,80 @@ class Configurator
|
||||||
end
|
end
|
||||||
|
|
||||||
@config = OpenStruct.new
|
@config = OpenStruct.new
|
||||||
|
@config.tools = OpenStruct.new
|
||||||
cnf = root_src.join('yabuild-default-conf.rb')
|
cnf = root_src.join('yabuild-default-conf.rb')
|
||||||
if cnf.exist?
|
if cnf.exist?
|
||||||
@config_target.add_deps(cnf)
|
@config_target.inputs.push(cnf)
|
||||||
@config = self.instance_eval(cnf.read, cnf.to_s)
|
self.instance_eval(cnf.read, cnf.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
preloads.each { |preload|
|
preloads.each { |preload|
|
||||||
preload = Pathname.new(preload).realpath
|
preload = Pathname.new(preload).realpath
|
||||||
@config_target.add_deps(preload)
|
@config_target.inputs.push(preload)
|
||||||
contents = preload.read
|
self.instance_eval(preload.read, preload.to_s)
|
||||||
self.instance_eval(contents, preload.to_s)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ninja_path = find_executable('ninja', critical: true)
|
||||||
|
|
||||||
|
fill_default_ninja
|
||||||
|
register_target(@config_target)
|
||||||
|
end
|
||||||
|
|
||||||
|
private def fill_default_ninja
|
||||||
|
default_pieces = []
|
||||||
|
@ninja_files_parts['default-rules'] = default_pieces
|
||||||
|
|
||||||
|
@ninja_files_parts[''] << NinjaPieceRaw.new(<<-EOF
|
||||||
|
# ya-build generated, do not edit
|
||||||
|
# src: #{root_src}
|
||||||
|
ninja_required_version = 1.5
|
||||||
|
ya_ninja_workdir = #{root_build}
|
||||||
|
include default-rules.ninja
|
||||||
|
|
||||||
|
build clean: CLEAN
|
||||||
|
|
||||||
|
build help: HELP
|
||||||
|
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
default_pieces << NinjaPieceRaw.new(<<-EOF
|
||||||
|
# ya-build generated, do not edit
|
||||||
|
|
||||||
|
CC = clang
|
||||||
|
|
||||||
|
rule RERUN_YA_BUILD
|
||||||
|
command = cd #{Shellwords.escape Dir.getwd} && #{SELF_COMMAND.map { |x| Shellwords.escape x }.join(' ')}
|
||||||
|
description = rerunning ya-build
|
||||||
|
|
||||||
|
rule CLEAN
|
||||||
|
command = #{Shellwords.escape ninja_path} $FILE_ARG -t clean $TARGETS
|
||||||
|
description = Cleaning all built files...
|
||||||
|
|
||||||
|
rule HELP
|
||||||
|
command = #{Shellwords.escape ninja_path} -t targets rule phony rule CLEAN rule HELP
|
||||||
|
description = All primary targets available
|
||||||
|
|
||||||
|
rule CUSTOM_COMMAND
|
||||||
|
command = cd $CWD && $ENV $COMMAND
|
||||||
|
description = $DESC
|
||||||
|
|
||||||
|
rule C_COMPILE
|
||||||
|
depfile = $out.d
|
||||||
|
command = $CC \
|
||||||
|
-MD -MF $out.d \
|
||||||
|
-c $cflags \
|
||||||
|
-o $out \
|
||||||
|
$in
|
||||||
|
|
||||||
|
rule C_LINK
|
||||||
|
command = $CC $cflags -o $out $in
|
||||||
|
|
||||||
|
rule COPY
|
||||||
|
command = cp $in $out
|
||||||
|
|
||||||
|
EOF
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
private def extend_config_impl(l, r)
|
private def extend_config_impl(l, r)
|
||||||
|
|
@ -347,65 +407,21 @@ class Configurator
|
||||||
end
|
end
|
||||||
|
|
||||||
def eval_script(path)
|
def eval_script(path)
|
||||||
script_path = cur_src.join(@stack[-1].path.join(path))
|
script_path = cur_src.join(path)
|
||||||
@config_target.add_deps(script_path)
|
|
||||||
contents = script_path.read
|
contents = script_path.read
|
||||||
|
@config_target.inputs.push script_path
|
||||||
self.instance_eval(contents, script_path.to_s)
|
self.instance_eval(contents, script_path.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
private def run_last_stack()
|
private def run_last_stack()
|
||||||
path = @stack[-1].path
|
path = @stack[-1].path
|
||||||
@logger.info("configuring #{path}")
|
@logger.info("entering #{path}")
|
||||||
script_path = root_src.join(path, 'yabuild.rb')
|
script_path = root_src.join(path, 'yabuild.rb')
|
||||||
@config_target.add_deps(script_path)
|
@config_target.inputs.push(script_path)
|
||||||
contents = script_path.read
|
contents = script_path.read
|
||||||
self.instance_eval(contents, script_path.to_s)
|
self.instance_eval(contents, script_path.to_s)
|
||||||
end
|
end
|
||||||
|
|
||||||
def add_rule(rule)
|
|
||||||
@rules.push(rule)
|
|
||||||
end
|
|
||||||
|
|
||||||
private def rules_str()
|
|
||||||
beg = [<<-EOF
|
|
||||||
# ya-build generated, do not edit
|
|
||||||
|
|
||||||
CC = clang
|
|
||||||
|
|
||||||
rule RERUN_YA_BUILD
|
|
||||||
command = cd #{Shellwords.escape Dir.getwd} && #{SELF_COMMAND.map { |x| Shellwords.escape x }.join(' ')}
|
|
||||||
description = rerunning ya-build
|
|
||||||
|
|
||||||
rule CLEAN
|
|
||||||
command = /usr/bin/ninja $FILE_ARG -t clean $TARGETS
|
|
||||||
description = Cleaning all built files...
|
|
||||||
|
|
||||||
rule HELP
|
|
||||||
command = /usr/bin/ninja -t targets rule phony rule CLEAN rule HELP
|
|
||||||
description = All primary targets available
|
|
||||||
|
|
||||||
rule CUSTOM_COMMAND
|
|
||||||
command = cd $WD && $ENV $COMMAND
|
|
||||||
description = $DESC
|
|
||||||
|
|
||||||
rule COMPILE_C
|
|
||||||
depfile = $out.d
|
|
||||||
command = cd $ROOT_DIR && \
|
|
||||||
$CC -MD -MF $out.d $cflags -o $out "$$(#{[RbConfig.ruby, Pathname.new(__FILE__).realpath, '__realpath_to_from'].map(&Shellwords.method(:escape)).join(' ')} "$in" "$ROOT_DIR")" && \
|
|
||||||
#{[RbConfig.ruby, Pathname.new(__FILE__).realpath, '__patch_dep'].map(&Shellwords.method(:escape)).join(' ')} $ROOT_DIR $out.d
|
|
||||||
|
|
||||||
rule LINK_C
|
|
||||||
command = $CC $cflags -o $out $in
|
|
||||||
|
|
||||||
rule COPY
|
|
||||||
command = cp $in $out
|
|
||||||
|
|
||||||
EOF
|
|
||||||
]
|
|
||||||
beg += @rules
|
|
||||||
beg.join("\n\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
def run()
|
def run()
|
||||||
@stack = [
|
@stack = [
|
||||||
OpenStruct.new(
|
OpenStruct.new(
|
||||||
|
|
@ -418,44 +434,49 @@ EOF
|
||||||
|
|
||||||
File.write(root_build.join('config.json'), @config.to_json)
|
File.write(root_build.join('config.json'), @config.to_json)
|
||||||
|
|
||||||
File.write(root_build.join('rules.ninja'), rules_str)
|
ninja_files_parts.each { |k, v|
|
||||||
|
@config_target.outputs << "#{if k == "" then "build" else k end}.ninja"
|
||||||
build_str = String.new()
|
}
|
||||||
build_str << <<-EOF
|
|
||||||
# ya-build generated, do not edit
|
ninja_files_parts.each { |k, v|
|
||||||
# src: #{root_src}
|
if k == ''
|
||||||
ninja_required_version = 1.5
|
k = 'build'
|
||||||
ya_ninja_workdir = #{root_build}
|
end
|
||||||
include rules.ninja
|
fname = root_build.join("#{k}.ninja")
|
||||||
|
buf = String.new
|
||||||
build clean: CLEAN
|
buf << "# ya-build generated, do not edit\n"
|
||||||
|
v.each do |v|
|
||||||
build help: HELP
|
v.dump_ninja buf
|
||||||
|
rescue => e
|
||||||
EOF
|
logger.error("can't dump #{v.inspect}")
|
||||||
@targets.each { |t|
|
raise
|
||||||
t.dump_rules(build_str)
|
end
|
||||||
|
if k == 'build'
|
||||||
|
buf << "default tags/all\n"
|
||||||
|
end
|
||||||
|
File.write fname, buf
|
||||||
}
|
}
|
||||||
build_str << "default tags/all\n"
|
|
||||||
File.write(root_build.join('build.ninja'), build_str)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_target(name)
|
def find_target(name)
|
||||||
suitable = @targets.filter { |trg|
|
suitable = @named_targets.filter { |trg|
|
||||||
trg.trg_name.match?(name)
|
trg.name.match?(name)
|
||||||
}
|
}
|
||||||
raise "couldn't find target by name #{name} ; suitable: #{suitable}" if suitable.size() != 1
|
raise "couldn't find target by name #{name} ; suitable: #{suitable}" if suitable.size() != 1
|
||||||
suitable[0]
|
suitable[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
private def register_target(trg)
|
private def register_target(trg, to: '')
|
||||||
@targets.push(trg)
|
@ninja_files_parts[to] << trg
|
||||||
|
if trg.kind_of?(DefaultTargets::Phony)
|
||||||
|
@named_targets.push(trg)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private def return_target(trg, tags: [], &block)
|
private def return_target(trg, tags: [], &block)
|
||||||
register_target(trg)
|
register_target(trg)
|
||||||
tags.map { |t| get_tag_target(t) }.each { |t|
|
tags.map { |t| get_tag_target(t) }.each { |t|
|
||||||
t.add_deps trg
|
t.inputs.push trg
|
||||||
}
|
}
|
||||||
if not block.nil?
|
if not block.nil?
|
||||||
trg.instance_eval(&block)
|
trg.instance_eval(&block)
|
||||||
|
|
@ -486,27 +507,68 @@ EOF
|
||||||
root_src.join(@stack[-1].path)
|
root_src.join(@stack[-1].path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_executable(name, critical: false)
|
def find_executable(name, critical: false, check_first: [], check_path: true, check_last: [], &blk)
|
||||||
|
chck = Proc.new { |path|
|
||||||
|
if path.nil?
|
||||||
|
next false
|
||||||
|
end
|
||||||
|
if not path.exist?
|
||||||
|
next false
|
||||||
|
end
|
||||||
|
logger.debug("executable #{name} found at #{path}")
|
||||||
|
if blk.nil?
|
||||||
|
next true
|
||||||
|
end
|
||||||
|
|
||||||
|
begin
|
||||||
|
res = blk.(path)
|
||||||
|
if not res
|
||||||
|
logger.info("executable #{name} found at #{path} does not work (check failed)")
|
||||||
|
end
|
||||||
|
res
|
||||||
|
rescue => e
|
||||||
|
logger.info("executable #{name} found at #{path} does not work\n#{e}")
|
||||||
|
false
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
override = config.tools.send(name)
|
||||||
|
if not override.nil?
|
||||||
|
res = chck.(override)
|
||||||
|
if res.nil? and critical
|
||||||
|
logger.error("executable #{name} not found for override #{override}")
|
||||||
|
raise "#{name} not found"
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
|
||||||
|
check_first.each { |p|
|
||||||
|
path = Pathname.new(p).join(name)
|
||||||
|
if chck.(path)
|
||||||
|
return path
|
||||||
|
end
|
||||||
|
}
|
||||||
|
if check_path
|
||||||
paths = ENV['PATH'].split(':')
|
paths = ENV['PATH'].split(':')
|
||||||
paths << '/usr/bin'
|
|
||||||
paths << '/bin'
|
|
||||||
paths << "#{ENV['HOME']}/.local/bin"
|
|
||||||
paths << "#{ENV['HOME']}/.cargo/bin"
|
|
||||||
paths.each { |p|
|
paths.each { |p|
|
||||||
check = ['', '.elf', '.exe']
|
path = Pathname.new(p).join(name)
|
||||||
check.each { |c|
|
if chck.(path)
|
||||||
cur_p = Pathname.new(p).join("#{name}#{c}")
|
return path
|
||||||
if cur_p.exist?()
|
|
||||||
logger.info("checking for #{name}... located at #{cur_p}")
|
|
||||||
return cur_p
|
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
end
|
||||||
|
check_last.each { |p|
|
||||||
|
path = Pathname.new(p).join(name)
|
||||||
|
if chck.(path)
|
||||||
|
return path
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
if critical
|
if critical
|
||||||
logger.error("checking for #{name}... not found")
|
logger.error("executable #{name} not found")
|
||||||
raise "#{name} not found in path"
|
raise "#{name} not found"
|
||||||
end
|
end
|
||||||
logger.info("checking for #{name}... not found")
|
logger.info("executable #{name} not found")
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -523,7 +585,7 @@ EOF
|
||||||
&blk
|
&blk
|
||||||
)
|
)
|
||||||
if commands.nil? == command.nil?
|
if commands.nil? == command.nil?
|
||||||
raise "exectly one of command or commands must be specified"
|
raise "exactly one of command or commands must be specified"
|
||||||
end
|
end
|
||||||
if commands.nil?
|
if commands.nil?
|
||||||
commands = [command]
|
commands = [command]
|
||||||
|
|
@ -533,29 +595,24 @@ EOF
|
||||||
cwd = cur_src
|
cwd = cur_src
|
||||||
end
|
end
|
||||||
|
|
||||||
trg = CommandTarget.new(output_file, dependencies, cwd, commands, depfile, pool, env)
|
trg = DefaultTargets::Command.new(output_file, dependencies, cwd, commands, depfile, pool, env)
|
||||||
return_target(trg, **kwargs, &blk)
|
return_target(trg, **kwargs, &blk)
|
||||||
end
|
end
|
||||||
|
|
||||||
def target_copy(dest:, src:, **kwargs, &blk)
|
def target_copy(dest:, src:, **kwargs, &blk)
|
||||||
trg = CopyTarget.new(dest, src)
|
trg = DefaultTargets::Copy.new(dest, src)
|
||||||
return_target(trg, **kwargs, &blk)
|
return_target(trg, **kwargs, &blk)
|
||||||
end
|
end
|
||||||
|
|
||||||
def target_c(output_file:, mode:, root_dir: nil, file: nil, objs: nil, flags: nil, cc: nil, **kwargs, &blk)
|
def target_c_compile(output_file:, file:, flags: nil, cc: nil, **kwargs, &blk)
|
||||||
if (mode == "compile") == file.nil?
|
real_out = output_file.relative_path_from(root_build)
|
||||||
raise "file must be provided only for compile"
|
real_file = file.relative_path_from(root_build)
|
||||||
|
trg = DefaultTargets::C.new(output: real_out.to_s, inputs: [real_file.to_s], flags: flags, cc: cc, rule: "C_COMPILE")
|
||||||
|
return_target(trg, **kwargs, &blk)
|
||||||
end
|
end
|
||||||
if (mode == "link") == objs.nil?
|
|
||||||
raise "objs must be provided only for link"
|
def target_c_link(output_file:, objs:, flags: nil, cc: nil, **kwargs, &blk)
|
||||||
end
|
trg = DefaultTargets::C.new(output: output_file, inputs: objs, flags: flags, cc: cc, rule: "C_LINK")
|
||||||
if root_dir.nil?
|
|
||||||
root_dir = cur_src
|
|
||||||
end
|
|
||||||
deps = if objs.nil? then [
|
|
||||||
root_dir.join(file)
|
|
||||||
] else objs end
|
|
||||||
trg = CTarget.new(output_file, mode, deps, flags, cc, root_dir)
|
|
||||||
return_target(trg, **kwargs, &blk)
|
return_target(trg, **kwargs, &blk)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -565,7 +622,7 @@ EOF
|
||||||
name_full += "/"
|
name_full += "/"
|
||||||
end
|
end
|
||||||
name_full += name
|
name_full += name
|
||||||
trg = AliasTarget.new(name_full, dependencies)
|
trg = DefaultTargets::Phony.new(name: name_full, inputs: dependencies)
|
||||||
if dependencies.size() != 1 and inherit_meta.size() != 0
|
if dependencies.size() != 1 and inherit_meta.size() != 0
|
||||||
raise "Can inherit meta only for single dependency alias"
|
raise "Can inherit meta only for single dependency alias"
|
||||||
end
|
end
|
||||||
|
|
@ -576,11 +633,11 @@ EOF
|
||||||
end
|
end
|
||||||
|
|
||||||
def mark_as_config_generated(file)
|
def mark_as_config_generated(file)
|
||||||
@config_target.outputs.push file
|
@config_target.implicit_outputs.push file
|
||||||
end
|
end
|
||||||
|
|
||||||
def reconfigure_on_change(file)
|
def reconfigure_on_change(file)
|
||||||
@config_target.add_deps file
|
@config_target.inputs.push file
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue