The Meson Build System
http://mesonbuild.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1829 lines
82 KiB
1829 lines
82 KiB
9 years ago
|
# Copyright 2012-2016 The Meson development team
|
||
11 years ago
|
|
||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
# you may not use this file except in compliance with the License.
|
||
|
# You may obtain a copy of the License at
|
||
|
|
||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
# Unless required by applicable law or agreed to in writing, software
|
||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
# See the License for the specific language governing permissions and
|
||
|
# limitations under the License.
|
||
|
|
||
9 years ago
|
from . import backends
|
||
9 years ago
|
from .. import environment, mesonlib
|
||
|
from .. import build
|
||
|
from .. import mlog
|
||
|
from .. import dependencies
|
||
|
from ..mesonlib import File
|
||
9 years ago
|
from .backends import InstallData
|
||
9 years ago
|
from ..build import InvalidArguments
|
||
|
from ..coredata import MesonException
|
||
9 years ago
|
import os, sys, pickle, re
|
||
9 years ago
|
import subprocess, shutil
|
||
11 years ago
|
|
||
10 years ago
|
if mesonlib.is_windows():
|
||
11 years ago
|
quote_char = '"'
|
||
|
execute_wrapper = 'cmd /c'
|
||
|
else:
|
||
|
quote_char = "'"
|
||
|
execute_wrapper = ''
|
||
|
|
||
|
def ninja_quote(text):
|
||
|
return text.replace(' ', '$ ').replace(':', '$:')
|
||
|
|
||
10 years ago
|
class RawFilename():
|
||
|
def __init__(self, fname):
|
||
|
self.fname = fname
|
||
|
|
||
|
def split(self, c):
|
||
|
return self.fname.split(c)
|
||
|
|
||
|
def startswith(self, s):
|
||
|
return self.fname.startswith(s)
|
||
11 years ago
|
|
||
|
class NinjaBuildElement():
|
||
|
def __init__(self, outfilenames, rule, infilenames):
|
||
|
if isinstance(outfilenames, str):
|
||
|
self.outfilenames = [outfilenames]
|
||
|
else:
|
||
|
self.outfilenames = outfilenames
|
||
|
assert(isinstance(rule, str))
|
||
|
self.rule = rule
|
||
|
if isinstance(infilenames, str):
|
||
|
self.infilenames = [infilenames]
|
||
|
else:
|
||
|
self.infilenames = infilenames
|
||
|
self.deps = []
|
||
|
self.orderdeps = []
|
||
|
self.elems = []
|
||
|
|
||
|
def add_dep(self, dep):
|
||
|
if isinstance(dep, list):
|
||
|
self.deps += dep
|
||
|
else:
|
||
|
self.deps.append(dep)
|
||
|
|
||
|
def add_orderdep(self, dep):
|
||
|
if isinstance(dep, list):
|
||
|
self.orderdeps += dep
|
||
|
else:
|
||
|
self.orderdeps.append(dep)
|
||
|
|
||
|
def add_item(self, name, elems):
|
||
|
if isinstance(elems, str):
|
||
|
elems = [elems]
|
||
|
self.elems.append((name, elems))
|
||
|
|
||
|
def write(self, outfile):
|
||
11 years ago
|
line = 'build %s: %s %s' % (' '.join([ninja_quote(i) for i in self.outfilenames]),\
|
||
11 years ago
|
self.rule,
|
||
11 years ago
|
' '.join([ninja_quote(i) for i in self.infilenames]))
|
||
11 years ago
|
if len(self.deps) > 0:
|
||
|
line += ' | ' + ' '.join([ninja_quote(x) for x in self.deps])
|
||
|
if len(self.orderdeps) > 0:
|
||
|
line += ' || ' + ' '.join([ninja_quote(x) for x in self.orderdeps])
|
||
|
line += '\n'
|
||
9 years ago
|
# This is the only way I could find to make this work on all
|
||
|
# platforms including Windows command shell. Slash is a dir separator
|
||
|
# on Windows, too, so all characters are unambiguous and, more importantly,
|
||
|
# do not require quoting.
|
||
9 years ago
|
line = line.replace('\\', '/')
|
||
11 years ago
|
outfile.write(line)
|
||
|
|
||
|
for e in self.elems:
|
||
|
(name, elems) = e
|
||
|
should_quote = True
|
||
10 years ago
|
if name == 'DEPFILE' or name == 'DESC' or name == 'pool':
|
||
11 years ago
|
should_quote = False
|
||
|
line = ' %s = ' % name
|
||
|
q_templ = quote_char + "%s" + quote_char
|
||
|
noq_templ = "%s"
|
||
|
newelems = []
|
||
|
for i in elems:
|
||
|
if not should_quote or i == '&&': # Hackety hack hack
|
||
|
templ = noq_templ
|
||
|
else:
|
||
|
templ = q_templ
|
||
9 years ago
|
i = i.replace('\\', '\\\\')
|
||
|
if quote_char == '"':
|
||
|
i = i.replace('"', '\\"')
|
||
11 years ago
|
newelems.append(templ % ninja_quote(i))
|
||
|
line += ' '.join(newelems)
|
||
|
line += '\n'
|
||
|
outfile.write(line)
|
||
|
outfile.write('\n')
|
||
|
|
||
|
class NinjaBackend(backends.Backend):
|
||
|
|
||
9 years ago
|
def __init__(self, build):
|
||
|
super().__init__(build)
|
||
11 years ago
|
self.source_suffix_in_objs = True
|
||
|
self.ninja_filename = 'build.ninja'
|
||
10 years ago
|
self.fortran_deps = {}
|
||
9 years ago
|
self.all_outputs = {}
|
||
|
|
||
|
def check_outputs(self, elem):
|
||
|
for n in elem.outfilenames:
|
||
|
if n in self.all_outputs:
|
||
|
raise MesonException('Multiple producers for Ninja target "%s". Please rename your targets.' % n)
|
||
|
self.all_outputs[n] = True
|
||
11 years ago
|
|
||
9 years ago
|
def detect_vs_dep_prefix(self, outfile, tempfilename):
|
||
|
'''VS writes its dependency in a locale dependent format.
|
||
|
Detect the search prefix to use.'''
|
||
|
if shutil.which('cl') is None:
|
||
|
return outfile
|
||
|
outfile.close()
|
||
|
open(os.path.join(self.environment.get_scratch_dir(), 'incdetect.c'),
|
||
|
'w').write('''#include<stdio.h>
|
||
|
int dummy;
|
||
|
''')
|
||
|
|
||
|
pc = subprocess.Popen(['cl', '/showIncludes', '/c', 'incdetect.c'],
|
||
|
stdout=subprocess.PIPE,
|
||
|
stderr=subprocess.PIPE,
|
||
|
cwd=self.environment.get_scratch_dir())
|
||
|
|
||
|
(stdo, _) = pc.communicate()
|
||
|
|
||
|
for line in stdo.split(b'\r\n'):
|
||
|
if line.endswith(b'stdio.h'):
|
||
|
matchstr = b':'.join(line.split(b':')[0:2]) + b':'
|
||
|
binfile = open(tempfilename, 'ab')
|
||
|
binfile.write(b'msvc_deps_prefix = ' + matchstr + b'\r\n')
|
||
|
binfile.close()
|
||
|
return open(tempfilename, 'a')
|
||
|
raise MesonException('Could not determine vs dep dependency prefix string.')
|
||
|
|
||
9 years ago
|
def generate(self, interp):
|
||
|
self.interpreter = interp
|
||
11 years ago
|
outfilename = os.path.join(self.environment.get_build_dir(), self.ninja_filename)
|
||
|
tempfilename = outfilename + '~'
|
||
|
outfile = open(tempfilename, 'w')
|
||
|
outfile.write('# This is the build file for project "%s"\n' % self.build.get_project())
|
||
|
outfile.write('# It is autogenerated by the Meson build system.\n')
|
||
|
outfile.write('# Do not edit by hand.\n\n')
|
||
10 years ago
|
outfile.write('ninja_required_version = 1.5.1\n\n')
|
||
9 years ago
|
outfile = self.detect_vs_dep_prefix(outfile, tempfilename)
|
||
11 years ago
|
self.generate_rules(outfile)
|
||
10 years ago
|
self.generate_phony(outfile)
|
||
11 years ago
|
outfile.write('# Build rules for targets\n\n')
|
||
|
[self.generate_target(t, outfile) for t in self.build.get_targets().values()]
|
||
|
if len(self.build.pot) > 0:
|
||
|
outfile.write('# Build rules for localisation.\n\n')
|
||
|
self.generate_po(outfile)
|
||
|
outfile.write('# Test rules\n\n')
|
||
|
self.generate_tests(outfile)
|
||
|
outfile.write('# Install rules\n\n')
|
||
|
self.generate_install(outfile)
|
||
9 years ago
|
if self.environment.coredata.get_builtin_option('coverage'):
|
||
11 years ago
|
outfile.write('# Coverage rules\n\n')
|
||
|
self.generate_coverage_rules(outfile)
|
||
|
outfile.write('# Suffix\n\n')
|
||
|
self.generate_ending(outfile)
|
||
|
# Only ovewrite the old build file after the new one has been
|
||
|
# fully created.
|
||
|
outfile.close()
|
||
|
os.replace(tempfilename, outfilename)
|
||
9 years ago
|
self.generate_compdb()
|
||
|
|
||
|
# http://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||
|
def generate_compdb(self):
|
||
|
ninja_exe = environment.detect_ninja()
|
||
|
builddir = self.environment.get_build_dir()
|
||
|
jsondb = subprocess.check_output([ninja_exe, '-t', 'compdb', 'c_COMPILER', 'cpp_COMPILER'], cwd=builddir)
|
||
|
open(os.path.join(builddir, 'compile_commands.json'), 'wb').write(jsondb)
|
||
11 years ago
|
|
||
10 years ago
|
# Get all generated headers. Any source file might need them so
|
||
|
# we need to add an order dependency to them.
|
||
|
def get_generated_headers(self, target):
|
||
|
header_deps = []
|
||
|
for gensource in target.get_generated_sources():
|
||
|
if isinstance(gensource, build.CustomTarget):
|
||
|
continue
|
||
|
for src in gensource.get_outfilelist():
|
||
|
if self.environment.is_header(src):
|
||
9 years ago
|
header_deps.append(os.path.join(self.get_target_private_dir(target), src))
|
||
|
for dep in target.link_targets:
|
||
|
if isinstance(dep, (build.StaticLibrary, build.SharedLibrary)):
|
||
|
header_deps += self.get_generated_headers(dep)
|
||
10 years ago
|
return header_deps
|
||
|
|
||
10 years ago
|
def generate_target(self, target, outfile):
|
||
|
if isinstance(target, build.CustomTarget):
|
||
|
self.generate_custom_target(target, outfile)
|
||
|
if isinstance(target, build.RunTarget):
|
||
|
self.generate_run_target(target, outfile)
|
||
9 years ago
|
name = target.get_id()
|
||
10 years ago
|
gen_src_deps = []
|
||
|
if name in self.processed_targets:
|
||
|
return
|
||
|
if isinstance(target, build.Jar):
|
||
|
self.generate_jar_target(target, outfile)
|
||
|
return
|
||
|
if 'rust' in self.environment.coredata.compilers.keys() and self.has_rust(target):
|
||
|
self.generate_rust_target(target, outfile)
|
||
|
return
|
||
|
if 'cs' in self.environment.coredata.compilers.keys() and self.has_cs(target):
|
||
|
self.generate_cs_target(target, outfile)
|
||
|
return
|
||
|
if 'vala' in self.environment.coredata.compilers.keys() and self.has_vala(target):
|
||
9 years ago
|
vala_output_files = self.generate_vala_compile(target, outfile)
|
||
|
gen_src_deps += vala_output_files
|
||
9 years ago
|
if 'swift' in self.environment.coredata.compilers.keys() and self.has_swift(target):
|
||
|
self.generate_swift_target(target, outfile)
|
||
|
return
|
||
10 years ago
|
self.scan_fortran_module_outputs(target)
|
||
|
# The following deals with C/C++ compilation.
|
||
|
(gen_src, gen_other_deps) = self.process_dep_gens(outfile, target)
|
||
|
gen_src_deps += gen_src
|
||
|
self.process_target_dependencies(target, outfile)
|
||
|
self.generate_custom_generator_rules(target, outfile)
|
||
|
outname = self.get_target_filename(target)
|
||
|
obj_list = []
|
||
9 years ago
|
use_pch = self.environment.coredata.get_builtin_option('use_pch')
|
||
|
is_unity = self.environment.coredata.get_builtin_option('unity')
|
||
10 years ago
|
if use_pch and target.has_pch():
|
||
10 years ago
|
pch_objects = self.generate_pch(target, outfile)
|
||
|
else:
|
||
|
pch_objects = []
|
||
10 years ago
|
header_deps = gen_other_deps
|
||
|
unity_src = []
|
||
|
unity_deps = [] # Generated sources that must be built before compiling a Unity target.
|
||
10 years ago
|
header_deps += self.get_generated_headers(target)
|
||
10 years ago
|
for gensource in target.get_generated_sources():
|
||
|
if isinstance(gensource, build.CustomTarget):
|
||
|
for src in gensource.output:
|
||
9 years ago
|
src = os.path.join(self.get_target_dir(gensource), src)
|
||
10 years ago
|
if self.environment.is_source(src) and not self.environment.is_header(src):
|
||
10 years ago
|
if is_unity:
|
||
|
unity_deps.append(os.path.join(self.environment.get_build_dir(), RawFilename(src)))
|
||
|
else:
|
||
10 years ago
|
obj_list.append(self.generate_single_compile(target, outfile, RawFilename(src), True,
|
||
|
header_deps))
|
||
10 years ago
|
elif self.environment.is_object(src):
|
||
|
obj_list.append(src)
|
||
9 years ago
|
elif self.environment.is_library(src):
|
||
|
pass
|
||
10 years ago
|
else:
|
||
10 years ago
|
# Assume anything not specifically a source file is a header. This is because
|
||
|
# people generate files with weird suffixes (.inc, .fh) that they then include
|
||
|
# in their source files.
|
||
|
header_deps.append(RawFilename(src))
|
||
10 years ago
|
else:
|
||
|
for src in gensource.get_outfilelist():
|
||
|
if self.environment.is_object(src):
|
||
9 years ago
|
obj_list.append(os.path.join(self.get_target_private_dir(target), src))
|
||
10 years ago
|
elif not self.environment.is_header(src):
|
||
|
if is_unity:
|
||
9 years ago
|
if self.has_dir_part(src):
|
||
10 years ago
|
rel_src = src
|
||
|
else:
|
||
9 years ago
|
rel_src = os.path.join(self.get_target_private_dir(target), src)
|
||
10 years ago
|
unity_deps.append(rel_src)
|
||
|
abs_src = os.path.join(self.environment.get_build_dir(), rel_src)
|
||
|
unity_src.append(abs_src)
|
||
10 years ago
|
else:
|
||
10 years ago
|
obj_list.append(self.generate_single_compile(target, outfile, src, True,
|
||
|
header_deps=header_deps))
|
||
10 years ago
|
src_list = []
|
||
|
for src in gen_src_deps:
|
||
|
src_list.append(src)
|
||
|
if is_unity:
|
||
|
unity_src.append(os.path.join(self.environment.get_build_dir(), src))
|
||
|
header_deps.append(src)
|
||
|
else:
|
||
|
# Generated targets are ordered deps because the must exist
|
||
|
# before the sources compiling them are used. After the first
|
||
|
# compile we get precise dependency info from dep files.
|
||
|
# This should work in all cases. If it does not, then just
|
||
|
# move them from orderdeps to proper deps.
|
||
9 years ago
|
if self.environment.is_header(src):
|
||
|
header_deps.append(src)
|
||
|
else:
|
||
|
obj_list.append(self.generate_single_compile(target, outfile, src, True, [], header_deps))
|
||
10 years ago
|
for src in target.get_sources():
|
||
|
if src.endswith('.vala'):
|
||
|
continue
|
||
|
if not self.environment.is_header(src):
|
||
|
src_list.append(src)
|
||
|
if is_unity:
|
||
9 years ago
|
abs_src = os.path.join(self.environment.get_build_dir(),
|
||
|
src.rel_to_builddir(self.build_to_src))
|
||
10 years ago
|
unity_src.append(abs_src)
|
||
|
else:
|
||
|
obj_list.append(self.generate_single_compile(target, outfile, src, False, [], header_deps))
|
||
|
obj_list += self.flatten_object_list(target)
|
||
|
if is_unity:
|
||
|
for src in self.generate_unity_files(target, unity_src):
|
||
|
obj_list.append(self.generate_single_compile(target, outfile, src, True, unity_deps + header_deps))
|
||
|
linker = self.determine_linker(target, src_list)
|
||
9 years ago
|
elem = self.generate_link(target, outfile, outname, obj_list, linker, pch_objects)
|
||
9 years ago
|
self.generate_shlib_aliases(target, self.get_target_dir(target))
|
||
|
elem.write(outfile)
|
||
10 years ago
|
self.processed_targets[name] = True
|
||
|
|
||
|
def process_target_dependencies(self, target, outfile):
|
||
|
for t in target.get_dependencies():
|
||
10 years ago
|
tname = t.get_basename() + t.type_suffix()
|
||
10 years ago
|
if not tname in self.processed_targets:
|
||
|
self.generate_target(t, outfile)
|
||
|
|
||
11 years ago
|
def generate_custom_target(self, target, outfile):
|
||
9 years ago
|
(srcs, ofilenames, cmd) = self.eval_custom_target_command(target)
|
||
9 years ago
|
deps = []
|
||
|
for i in target.get_dependencies():
|
||
|
# FIXME, should not grab element at zero but rather expand all.
|
||
|
if isinstance(i, list):
|
||
|
i = i[0]
|
||
9 years ago
|
fname = i.get_filename()
|
||
|
if isinstance(fname, list):
|
||
|
fname = fname[0]
|
||
|
deps.append(os.path.join(self.get_target_dir(i), fname))
|
||
10 years ago
|
if target.build_always:
|
||
|
deps.append('PHONY')
|
||
9 years ago
|
elem = NinjaBuildElement(ofilenames, 'CUSTOM_COMMAND', srcs)
|
||
|
for i in target.depend_files:
|
||
|
if isinstance(i, mesonlib.File):
|
||
|
deps.append(i.rel_to_builddir(self.build_to_src))
|
||
|
else:
|
||
|
deps.append(os.path.join(self.build_to_src, i))
|
||
|
elem.add_dep(deps)
|
||
10 years ago
|
for d in target.extra_depends:
|
||
|
tmp = d.get_filename()
|
||
|
if not isinstance(tmp, list):
|
||
|
tmp = [tmp]
|
||
|
for fname in tmp:
|
||
9 years ago
|
elem.add_dep(os.path.join(self.get_target_dir(d), fname))
|
||
|
|
||
11 years ago
|
elem.add_item('COMMAND', cmd)
|
||
10 years ago
|
elem.add_item('description', 'Generating %s with a custom command.' % target.name)
|
||
11 years ago
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
10 years ago
|
self.processed_targets[target.name + target.type_suffix()] = True
|
||
11 years ago
|
|
||
11 years ago
|
def generate_run_target(self, target, outfile):
|
||
9 years ago
|
runnerscript = [sys.executable, self.environment.get_build_command(), '--internal', 'commandrunner']
|
||
9 years ago
|
deps = []
|
||
|
arg_strings = []
|
||
|
for i in target.args:
|
||
|
if isinstance(i, str):
|
||
|
arg_strings.append(i)
|
||
9 years ago
|
elif isinstance(i, (build.BuildTarget, build.CustomTarget)):
|
||
9 years ago
|
relfname = self.get_target_filename(i)
|
||
|
deps.append(relfname)
|
||
|
arg_strings.append(os.path.join(self.environment.get_build_dir(), relfname))
|
||
9 years ago
|
else:
|
||
9 years ago
|
mlog.debug(str(i))
|
||
9 years ago
|
raise MesonException('Unreachable code in generate_run_target.')
|
||
9 years ago
|
elem = NinjaBuildElement(target.name, 'CUSTOM_COMMAND', deps)
|
||
9 years ago
|
cmd = runnerscript + [self.environment.get_source_dir(), self.environment.get_build_dir(), target.subdir]
|
||
9 years ago
|
texe = target.command
|
||
|
try:
|
||
|
texe = texe.held_object
|
||
|
except AttributeError:
|
||
|
pass
|
||
|
if isinstance(texe, build.Executable):
|
||
9 years ago
|
abs_exe = os.path.join(self.environment.get_build_dir(), self.get_target_filename(texe))
|
||
9 years ago
|
deps.append(self.get_target_filename(texe))
|
||
|
if self.environment.is_cross_build() \
|
||
9 years ago
|
and self.environment.cross_info.config['binaries'].get('exe_wrapper', None) is not None:
|
||
9 years ago
|
cmd += [self.environment.cross_info.config['binaries']['exe_wrapper']]
|
||
|
cmd.append(abs_exe)
|
||
9 years ago
|
else:
|
||
|
cmd.append(target.command)
|
||
9 years ago
|
cmd += arg_strings
|
||
11 years ago
|
elem.add_item('COMMAND', cmd)
|
||
|
elem.add_item('description', 'Running external command %s.' % target.name)
|
||
10 years ago
|
elem.add_item('pool', 'console')
|
||
11 years ago
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
10 years ago
|
self.processed_targets[target.name + target.type_suffix()] = True
|
||
11 years ago
|
|
||
11 years ago
|
def generate_po(self, outfile):
|
||
|
for p in self.build.pot:
|
||
|
(packagename, languages, subdir) = p
|
||
|
input_file = os.path.join(subdir, 'POTFILES')
|
||
|
elem = NinjaBuildElement('pot', 'GEN_POT', [])
|
||
|
elem.add_item('PACKAGENAME', packagename)
|
||
|
elem.add_item('OUTFILE', packagename + '.pot')
|
||
|
elem.add_item('FILELIST', os.path.join(self.environment.get_source_dir(), input_file))
|
||
|
elem.add_item('OUTDIR', os.path.join(self.environment.get_source_dir(), subdir))
|
||
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
for l in languages:
|
||
|
infile = os.path.join(self.environment.get_source_dir(), subdir, l + '.po')
|
||
|
outfilename = os.path.join(subdir, l + '.gmo')
|
||
|
lelem = NinjaBuildElement(outfilename, 'GEN_GMO', infile)
|
||
|
lelem.add_item('INFILE', infile)
|
||
|
lelem.add_item('OUTFILE', outfilename)
|
||
|
lelem.write(outfile)
|
||
9 years ago
|
self.check_outputs(lelem)
|
||
11 years ago
|
|
||
|
def generate_coverage_rules(self, outfile):
|
||
|
(gcovr_exe, lcov_exe, genhtml_exe) = environment.find_coverage_tools()
|
||
|
added_rule = False
|
||
|
if gcovr_exe:
|
||
|
added_rule = True
|
||
|
elem = NinjaBuildElement('coverage-xml', 'CUSTOM_COMMAND', '')
|
||
|
elem.add_item('COMMAND', [gcovr_exe, '-x', '-r', self.environment.get_build_dir(),\
|
||
|
'-o', os.path.join(self.environment.get_log_dir(), 'coverage.xml')])
|
||
|
elem.add_item('DESC', 'Generating XML coverage report.')
|
||
|
elem.write(outfile)
|
||
|
elem = NinjaBuildElement('coverage-text', 'CUSTOM_COMMAND', '')
|
||
|
elem.add_item('COMMAND', [gcovr_exe, '-r', self.environment.get_build_dir(),\
|
||
|
'-o', os.path.join(self.environment.get_log_dir(), 'coverage.txt')])
|
||
|
elem.add_item('DESC', 'Generating text coverage report.')
|
||
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
if lcov_exe and genhtml_exe:
|
||
|
added_rule = True
|
||
|
phony_elem = NinjaBuildElement('coverage-html', 'phony', 'coveragereport/index.html')
|
||
|
phony_elem.write(outfile)
|
||
|
|
||
|
elem = NinjaBuildElement('coveragereport/index.html', 'CUSTOM_COMMAND', '')
|
||
|
command = [lcov_exe, '--directory', self.environment.get_build_dir(),\
|
||
|
'--capture', '--output-file', 'coverage.info', '--no-checksum',\
|
||
|
'&&', genhtml_exe, '--prefix', self.environment.get_build_dir(),\
|
||
|
'--output-directory', self.environment.get_log_dir(), '--title', 'Code coverage',\
|
||
|
'--legend', '--show-details', 'coverage.info']
|
||
|
elem.add_item('COMMAND', command)
|
||
|
elem.add_item('DESC', 'Generating HTML coverage report.')
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
elem.write(outfile)
|
||
|
if not added_rule:
|
||
|
mlog.log(mlog.red('Warning:'), 'coverage requested but neither gcovr nor lcov/genhtml found.')
|
||
|
|
||
|
def generate_install(self, outfile):
|
||
|
script_root = self.environment.get_script_dir()
|
||
|
install_script = os.path.join(script_root, 'meson_install.py')
|
||
|
install_data_file = os.path.join(self.environment.get_scratch_dir(), 'install.dat')
|
||
9 years ago
|
depfixer = [sys.executable, self.environment.get_build_command(), '--internal', 'depfixer']
|
||
11 years ago
|
d = InstallData(self.environment.get_source_dir(),
|
||
|
self.environment.get_build_dir(),
|
||
11 years ago
|
self.environment.get_prefix(), depfixer)
|
||
9 years ago
|
elem = NinjaBuildElement('install', 'CUSTOM_COMMAND', 'PHONY')
|
||
11 years ago
|
elem.add_dep('all')
|
||
|
elem.add_item('DESC', 'Installing files.')
|
||
9 years ago
|
elem.add_item('COMMAND', [sys.executable, self.environment.get_build_command(), '--internal', 'install', install_data_file])
|
||
10 years ago
|
elem.add_item('pool', 'console')
|
||
9 years ago
|
self.generate_depmf_install(d)
|
||
11 years ago
|
self.generate_target_install(d)
|
||
|
self.generate_header_install(d)
|
||
|
self.generate_man_install(d)
|
||
|
self.generate_data_install(d)
|
||
|
self.generate_po_install(d, elem)
|
||
11 years ago
|
self.generate_custom_install_script(d)
|
||
10 years ago
|
self.generate_subdir_install(d)
|
||
11 years ago
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
|
||
|
ofile = open(install_data_file, 'wb')
|
||
|
pickle.dump(d, ofile)
|
||
|
|
||
|
def generate_po_install(self, d, elem):
|
||
|
for p in self.build.pot:
|
||
|
(package_name, languages, subdir) = p
|
||
|
# FIXME: assumes only one po package per source
|
||
|
d.po_package_name = package_name
|
||
|
for lang in languages:
|
||
|
rel_src = os.path.join(subdir, lang + '.gmo')
|
||
|
src_file = os.path.join(self.environment.get_build_dir(), rel_src)
|
||
9 years ago
|
d.po.append((src_file, self.environment.coredata.get_builtin_option('localedir'), lang))
|
||
11 years ago
|
elem.add_dep(rel_src)
|
||
|
|
||
|
def generate_target_install(self, d):
|
||
|
libdir = self.environment.get_libdir()
|
||
|
bindir = self.environment.get_bindir()
|
||
|
|
||
9 years ago
|
should_strip = self.environment.coredata.get_builtin_option('strip')
|
||
11 years ago
|
for t in self.build.get_targets().values():
|
||
|
if t.should_install():
|
||
|
outdir = t.get_custom_install_dir()
|
||
|
if outdir is None:
|
||
|
if isinstance(t, build.Executable):
|
||
|
outdir = bindir
|
||
|
else:
|
||
|
outdir = libdir
|
||
11 years ago
|
i = [self.get_target_filename(t), outdir, t.get_aliaslist(),\
|
||
|
should_strip, t.install_rpath]
|
||
11 years ago
|
d.targets.append(i)
|
||
|
|
||
11 years ago
|
def generate_custom_install_script(self, d):
|
||
9 years ago
|
d.install_scripts = self.build.install_scripts
|
||
11 years ago
|
|
||
11 years ago
|
def generate_header_install(self, d):
|
||
|
incroot = self.environment.get_includedir()
|
||
|
headers = self.build.get_headers()
|
||
|
|
||
|
for h in headers:
|
||
|
outdir = h.get_custom_install_dir()
|
||
|
if outdir is None:
|
||
10 years ago
|
outdir = os.path.join(incroot, h.get_install_subdir())
|
||
11 years ago
|
for f in h.get_sources():
|
||
10 years ago
|
abspath = os.path.join(self.environment.get_source_dir(), h.get_source_subdir(), f)
|
||
11 years ago
|
i = [abspath, outdir]
|
||
|
d.headers.append(i)
|
||
|
|
||
|
def generate_man_install(self, d):
|
||
|
manroot = self.environment.get_mandir()
|
||
|
man = self.build.get_man()
|
||
|
for m in man:
|
||
|
for f in m.get_sources():
|
||
|
num = f.split('.')[-1]
|
||
|
subdir = m.get_custom_install_dir()
|
||
|
if subdir is None:
|
||
|
subdir = os.path.join(manroot, 'man' + num)
|
||
10 years ago
|
srcabs = os.path.join(self.environment.get_source_dir(), m.get_source_subdir(), f)
|
||
11 years ago
|
dstabs = os.path.join(subdir, f + '.gz')
|
||
|
i = [srcabs, dstabs]
|
||
|
d.man.append(i)
|
||
|
|
||
|
def generate_data_install(self, d):
|
||
|
data = self.build.get_data()
|
||
|
for de in data:
|
||
9 years ago
|
assert(isinstance(de, build.Data))
|
||
|
subdir = de.install_dir
|
||
|
for f in de.sources:
|
||
10 years ago
|
if de.in_sourcetree:
|
||
|
srcprefix = self.environment.get_source_dir()
|
||
|
else:
|
||
|
srcprefix = self.environment.get_build_dir()
|
||
9 years ago
|
srcabs = os.path.join(srcprefix, de.source_subdir, f)
|
||
11 years ago
|
dstabs = os.path.join(subdir, f)
|
||
|
i = [srcabs, dstabs]
|
||
|
d.data.append(i)
|
||
|
|
||
10 years ago
|
def generate_subdir_install(self, d):
|
||
|
for sd in self.build.get_install_subdirs():
|
||
|
src_dir = os.path.join(self.environment.get_source_dir(), sd.source_subdir, sd.installable_subdir)
|
||
|
dst_dir = os.path.join(self.environment.get_prefix(), sd.install_dir)
|
||
|
d.install_subdirs.append([src_dir, dst_dir])
|
||
|
|
||
9 years ago
|
def write_test_suite_targets(self, cmd, outfile):
|
||
|
suites = {}
|
||
|
for t in self.build.get_tests():
|
||
9 years ago
|
for s in t.suite:
|
||
|
suites[s] = True
|
||
9 years ago
|
suites = list(suites.keys())
|
||
|
suites.sort()
|
||
|
for s in suites:
|
||
|
if s == '':
|
||
|
visible_name = 'for top level tests'
|
||
|
else:
|
||
|
visible_name = s
|
||
|
elem = NinjaBuildElement('test-' + s, 'CUSTOM_COMMAND', ['all', 'PHONY'])
|
||
|
elem.add_item('COMMAND', cmd + ['--suite=' + s])
|
||
|
elem.add_item('DESC', 'Running test suite %s.' % visible_name)
|
||
|
elem.add_item('pool', 'console')
|
||
|
elem.write(outfile)
|
||
|
self.check_outputs(elem)
|
||
|
|
||
11 years ago
|
def generate_tests(self, outfile):
|
||
|
self.serialise_tests()
|
||
|
valgrind = environment.find_valgrind()
|
||
|
script_root = self.environment.get_script_dir()
|
||
|
test_data = os.path.join(self.environment.get_scratch_dir(), 'meson_test_setup.dat')
|
||
9 years ago
|
cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'test', test_data]
|
||
10 years ago
|
elem = NinjaBuildElement('test', 'CUSTOM_COMMAND', ['all', 'PHONY'])
|
||
11 years ago
|
elem.add_item('COMMAND', cmd)
|
||
9 years ago
|
elem.add_item('DESC', 'Running all tests.')
|
||
10 years ago
|
elem.add_item('pool', 'console')
|
||
11 years ago
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
9 years ago
|
self.write_test_suite_targets(cmd, outfile)
|
||
11 years ago
|
|
||
|
if valgrind:
|
||
10 years ago
|
velem = NinjaBuildElement('test-valgrind', 'CUSTOM_COMMAND', ['all', 'PHONY'])
|
||
11 years ago
|
velem.add_item('COMMAND', cmd + ['--wrapper=' + valgrind])
|
||
|
velem.add_item('DESC', 'Running test suite under Valgrind.')
|
||
10 years ago
|
velem.add_item('pool', 'console')
|
||
11 years ago
|
velem.write(outfile)
|
||
9 years ago
|
self.check_outputs(velem)
|
||
11 years ago
|
|
||
9 years ago
|
# And then benchmarks.
|
||
|
benchmark_script = os.path.join(script_root, 'meson_benchmark.py')
|
||
|
benchmark_data = os.path.join(self.environment.get_scratch_dir(), 'meson_benchmark_setup.dat')
|
||
9 years ago
|
cmd = [sys.executable, self.environment.get_build_command(), '--internal', 'benchmark', benchmark_data]
|
||
9 years ago
|
elem = NinjaBuildElement('benchmark', 'CUSTOM_COMMAND', ['all', 'PHONY'])
|
||
|
elem.add_item('COMMAND', cmd)
|
||
|
elem.add_item('DESC', 'Running benchmark suite.')
|
||
|
elem.add_item('pool', 'console')
|
||
|
elem.write(outfile)
|
||
|
self.check_outputs(elem)
|
||
|
|
||
11 years ago
|
def generate_rules(self, outfile):
|
||
|
outfile.write('# Rules for compiling.\n\n')
|
||
|
self.generate_compile_rules(outfile)
|
||
|
outfile.write('# Rules for linking.\n\n')
|
||
|
if self.environment.is_cross_build():
|
||
|
self.generate_static_link_rules(True, outfile)
|
||
|
self.generate_static_link_rules(False, outfile)
|
||
|
self.generate_dynamic_link_rules(outfile)
|
||
|
outfile.write('# Other rules\n\n')
|
||
|
outfile.write('rule CUSTOM_COMMAND\n')
|
||
|
outfile.write(' command = $COMMAND\n')
|
||
|
outfile.write(' description = $DESC\n')
|
||
|
outfile.write(' restat = 1\n\n')
|
||
|
outfile.write('rule REGENERATE_BUILD\n')
|
||
9 years ago
|
c = (quote_char + ninja_quote(sys.executable) + quote_char,
|
||
11 years ago
|
quote_char + ninja_quote(self.environment.get_build_command()) + quote_char,
|
||
9 years ago
|
'--internal',
|
||
|
'regenerate',
|
||
11 years ago
|
quote_char + ninja_quote(self.environment.get_source_dir()) + quote_char,
|
||
|
quote_char + ninja_quote(self.environment.get_build_dir()) + quote_char)
|
||
9 years ago
|
outfile.write(" command = %s %s %s %s %s %s --backend ninja\n" % c)
|
||
11 years ago
|
outfile.write(' description = Regenerating build files\n')
|
||
|
outfile.write(' generator = 1\n\n')
|
||
|
if len(self.build.pot) > 0:
|
||
|
self.generate_gettext_rules(outfile)
|
||
|
outfile.write('\n')
|
||
|
|
||
|
def generate_gettext_rules(self, outfile):
|
||
|
rule = 'rule GEN_POT\n'
|
||
|
command = " command = xgettext --package-name=$PACKAGENAME -p $OUTDIR -f $FILELIST -D '%s' -k_ -o $OUTFILE\n" % \
|
||
|
self.environment.get_source_dir()
|
||
|
desc = " description = Creating pot file for package $PACKAGENAME.\n"
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(desc)
|
||
|
outfile.write('\n')
|
||
|
rule = 'rule GEN_GMO\n'
|
||
|
command = ' command = msgfmt $INFILE -o $OUTFILE\n'
|
||
|
desc = ' description = Generating gmo file $OUTFILE\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(desc)
|
||
|
outfile.write('\n')
|
||
|
|
||
10 years ago
|
def generate_phony(self, outfile):
|
||
|
outfile.write('# Phony build target, always out of date\n')
|
||
|
outfile.write('build PHONY: phony\n')
|
||
|
outfile.write('\n')
|
||
|
|
||
11 years ago
|
def generate_jar_target(self, target, outfile):
|
||
|
fname = target.get_filename()
|
||
|
subdir = target.get_subdir()
|
||
9 years ago
|
outname_rel = os.path.join(self.get_target_dir(target), fname)
|
||
11 years ago
|
src_list = target.get_sources()
|
||
|
class_list = []
|
||
|
compiler = self.get_compiler_for_source(src_list[0])
|
||
|
assert(compiler.get_language() == 'java')
|
||
|
c = 'c'
|
||
|
m = ''
|
||
|
e = ''
|
||
|
f = 'f'
|
||
|
main_class = target.get_main_class()
|
||
|
if main_class != '':
|
||
|
e = 'e'
|
||
|
for src in src_list:
|
||
9 years ago
|
plain_class_path = self.generate_single_java_compile(src, target, compiler, outfile)
|
||
|
class_list.append(plain_class_path)
|
||
|
class_dep_list = [os.path.join(self.get_target_private_dir(target), i) for i in class_list]
|
||
11 years ago
|
jar_rule = 'java_LINKER'
|
||
|
commands = [c+m+e+f]
|
||
|
if e != '':
|
||
|
commands.append(main_class)
|
||
|
commands.append(self.get_target_filename(target))
|
||
9 years ago
|
for cls in class_list:
|
||
|
commands += ['-C', self.get_target_private_dir(target), cls]
|
||
11 years ago
|
elem = NinjaBuildElement(outname_rel, jar_rule, [])
|
||
9 years ago
|
elem.add_dep(class_dep_list)
|
||
11 years ago
|
elem.add_item('ARGS', commands)
|
||
11 years ago
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
|
||
10 years ago
|
def generate_cs_resource_tasks(self, target, outfile):
|
||
|
args = []
|
||
|
deps = []
|
||
|
for r in target.resources:
|
||
|
rel_sourcefile = os.path.join(self.build_to_src, target.subdir, r)
|
||
|
if r.endswith('.resources'):
|
||
|
a = '-resource:' + rel_sourcefile
|
||
|
elif r.endswith('.txt') or r.endswith('.resx'):
|
||
|
ofilebase = os.path.splitext(os.path.basename(r))[0] + '.resources'
|
||
9 years ago
|
ofilename = os.path.join(self.get_target_private_dir(target), ofilebase)
|
||
10 years ago
|
elem = NinjaBuildElement(ofilename, "CUSTOM_COMMAND", rel_sourcefile)
|
||
|
elem.add_item('COMMAND', ['resgen', rel_sourcefile, ofilename])
|
||
|
elem.add_item('DESC', 'Compiling resource %s.' % rel_sourcefile)
|
||
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
10 years ago
|
deps.append(ofilename)
|
||
|
a = '-resource:' + ofilename
|
||
|
else:
|
||
|
raise InvalidArguments('Unknown resource file %s.' % r)
|
||
|
args.append(a)
|
||
|
return (args, deps)
|
||
|
|
||
11 years ago
|
def generate_cs_target(self, target, outfile):
|
||
9 years ago
|
buildtype = self.environment.coredata.get_builtin_option('buildtype')
|
||
11 years ago
|
fname = target.get_filename()
|
||
9 years ago
|
outname_rel = os.path.join(self.get_target_dir(target), fname)
|
||
11 years ago
|
src_list = target.get_sources()
|
||
|
compiler = self.get_compiler_for_source(src_list[0])
|
||
|
assert(compiler.get_language() == 'cs')
|
||
10 years ago
|
rel_srcs = [s.rel_to_builddir(self.build_to_src) for s in src_list]
|
||
10 years ago
|
deps = []
|
||
11 years ago
|
commands = target.extra_args.get('cs', [])
|
||
11 years ago
|
commands += compiler.get_buildtype_args(buildtype)
|
||
11 years ago
|
if isinstance(target, build.Executable):
|
||
|
commands.append('-target:exe')
|
||
|
elif isinstance(target, build.SharedLibrary):
|
||
|
commands.append('-target:library')
|
||
|
else:
|
||
|
raise MesonException('Unknown C# target type.')
|
||
10 years ago
|
(resource_args, resource_deps) = self.generate_cs_resource_tasks(target, outfile)
|
||
|
commands += resource_args
|
||
|
deps += resource_deps
|
||
11 years ago
|
commands += compiler.get_output_args(outname_rel)
|
||
11 years ago
|
for l in target.link_targets:
|
||
9 years ago
|
lname = os.path.join(self.get_target_dir(l), l.get_filename())
|
||
|
commands += compiler.get_link_args(lname)
|
||
|
deps.append(lname)
|
||
11 years ago
|
if '-g' in commands:
|
||
|
outputs = [outname_rel, outname_rel + '.mdb']
|
||
|
else:
|
||
|
outputs = [outname_rel]
|
||
|
elem = NinjaBuildElement(outputs, 'cs_COMPILER', rel_srcs)
|
||
11 years ago
|
elem.add_dep(deps)
|
||
11 years ago
|
elem.add_item('ARGS', commands)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
elem.write(outfile)
|
||
|
|
||
9 years ago
|
def generate_single_java_compile(self, src, target, compiler, outfile):
|
||
11 years ago
|
args = []
|
||
9 years ago
|
args += compiler.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
|
||
9 years ago
|
args += compiler.get_output_args(self.get_target_private_dir(target))
|
||
9 years ago
|
for i in target.include_dirs:
|
||
|
for idir in i.get_incdirs():
|
||
|
args += ['-sourcepath', os.path.join(self.build_to_src, i.curdir, idir)]
|
||
10 years ago
|
rel_src = src.rel_to_builddir(self.build_to_src)
|
||
|
plain_class_path = src.fname[:-4] + 'class'
|
||
9 years ago
|
rel_obj = os.path.join(self.get_target_private_dir(target), plain_class_path)
|
||
10 years ago
|
element = NinjaBuildElement(rel_obj, compiler.get_language() + '_COMPILER', rel_src)
|
||
11 years ago
|
element.add_item('ARGS', args)
|
||
11 years ago
|
element.write(outfile)
|
||
9 years ago
|
self.check_outputs(element)
|
||
11 years ago
|
return plain_class_path
|
||
|
|
||
|
def generate_java_link(self, outfile):
|
||
|
rule = 'rule java_LINKER\n'
|
||
11 years ago
|
command = ' command = jar $ARGS\n'
|
||
11 years ago
|
description = ' description = Creating jar $out.\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(description)
|
||
|
outfile.write('\n')
|
||
|
|
||
10 years ago
|
def split_vala_sources(self, sources):
|
||
|
src = []
|
||
|
vapi_src = []
|
||
|
for s in sources:
|
||
|
if s.endswith('.vapi'):
|
||
|
vapi_src.append(s)
|
||
|
else:
|
||
|
src.append(s)
|
||
|
return (src, vapi_src)
|
||
|
|
||
9 years ago
|
def determine_dep_vapis(self, target):
|
||
|
result = []
|
||
|
for dep in target.link_targets:
|
||
|
for i in dep.sources:
|
||
|
if hasattr(i, 'fname'):
|
||
|
i = i.fname
|
||
|
if i.endswith('vala'):
|
||
|
vapiname = os.path.splitext(os.path.split(i)[1])[0] + '.vapi'
|
||
9 years ago
|
fullname = os.path.join(self.get_target_dir(dep), vapiname)
|
||
9 years ago
|
result.append(fullname)
|
||
|
break
|
||
|
return result
|
||
|
|
||
11 years ago
|
def generate_vala_compile(self, target, outfile):
|
||
|
"""Vala is compiled into C. Set up all necessary build steps here."""
|
||
|
valac = self.environment.coredata.compilers['vala']
|
||
10 years ago
|
(src, vapi_src) = self.split_vala_sources(target.get_sources())
|
||
|
vapi_src = [x.rel_to_builddir(self.build_to_src) for x in vapi_src]
|
||
10 years ago
|
extra_dep_files = []
|
||
9 years ago
|
vala_input_files = []
|
||
10 years ago
|
for s in src:
|
||
9 years ago
|
if s.endswith('.vala'):
|
||
|
vala_input_files.append(s.rel_to_builddir(self.build_to_src))
|
||
9 years ago
|
if len(src) == 0:
|
||
|
raise InvalidArguments('Vala library has no Vala source files.')
|
||
|
namebase = os.path.splitext(os.path.split(src[0].fname)[1])[0]
|
||
9 years ago
|
base_h = namebase + '.h'
|
||
|
base_vapi = namebase + '.vapi'
|
||
|
hname = os.path.normpath(os.path.join(self.get_target_dir(target), base_h))
|
||
|
vapiname = os.path.normpath(os.path.join(self.get_target_dir(target), base_vapi))
|
||
9 years ago
|
|
||
9 years ago
|
generated_c_files = []
|
||
|
outputs = [vapiname]
|
||
9 years ago
|
args = ['-d', self.get_target_private_dir(target)]
|
||
|
args += ['-C']#, '-o', cname]
|
||
|
if not isinstance(target, build.Executable):
|
||
|
outputs.append(hname)
|
||
|
args += ['-H', hname]
|
||
9 years ago
|
args += ['--library=' + target.name]
|
||
|
args += ['--vapi=' + os.path.join('..', base_vapi)]
|
||
9 years ago
|
for src in vala_input_files:
|
||
|
namebase = os.path.splitext(os.path.split(src)[1])[0] + '.c'
|
||
9 years ago
|
full_c = os.path.join(self.get_target_private_dir(target), namebase)
|
||
|
generated_c_files.append(full_c)
|
||
|
outputs.append(full_c)
|
||
9 years ago
|
if self.environment.coredata.get_builtin_option('werror'):
|
||
|
args += valac.get_werror_args()
|
||
|
for d in target.external_deps:
|
||
|
if isinstance(d, dependencies.PkgConfigDependency):
|
||
|
if d.name == 'glib-2.0' and d.version_requirement is not None \
|
||
|
and d.version_requirement.startswith(('>=', '==')):
|
||
|
args += ['--target-glib', d.version_requirement[2:]]
|
||
|
args += ['--pkg', d.name]
|
||
|
extra_args = []
|
||
|
|
||
|
for a in target.extra_args.get('vala', []):
|
||
|
if isinstance(a, File):
|
||
|
relname = a.rel_to_builddir(self.build_to_src)
|
||
|
extra_dep_files.append(relname)
|
||
|
extra_args.append(relname)
|
||
|
else:
|
||
|
extra_args.append(a)
|
||
|
dependency_vapis = self.determine_dep_vapis(target)
|
||
|
extra_dep_files += dependency_vapis
|
||
|
args += extra_args
|
||
|
args += dependency_vapis
|
||
|
element = NinjaBuildElement(outputs,
|
||
|
valac.get_language() + '_COMPILER',
|
||
|
vala_input_files + vapi_src)
|
||
|
element.add_item('ARGS', args)
|
||
|
element.add_dep(extra_dep_files)
|
||
|
element.write(outfile)
|
||
|
self.check_outputs(element)
|
||
9 years ago
|
return generated_c_files
|
||
11 years ago
|
|
||
11 years ago
|
def generate_rust_target(self, target, outfile):
|
||
|
rustc = self.environment.coredata.compilers['rust']
|
||
|
relsrc = []
|
||
|
for i in target.get_sources():
|
||
|
if not rustc.can_compile(i):
|
||
|
raise InvalidArguments('Rust target %s contains a non-rust source file.' % target.get_basename())
|
||
9 years ago
|
relsrc.append(i.rel_to_builddir(self.build_to_src))
|
||
11 years ago
|
target_name = os.path.join(target.subdir, target.get_filename())
|
||
11 years ago
|
args = ['--crate-type']
|
||
11 years ago
|
if isinstance(target, build.Executable):
|
||
11 years ago
|
cratetype = 'bin'
|
||
11 years ago
|
elif isinstance(target, build.SharedLibrary):
|
||
9 years ago
|
cratetype = 'rlib'
|
||
11 years ago
|
elif isinstance(target, build.StaticLibrary):
|
||
9 years ago
|
cratetype = 'rlib'
|
||
11 years ago
|
else:
|
||
|
raise InvalidArguments('Unknown target type for rustc.')
|
||
11 years ago
|
args.append(cratetype)
|
||
9 years ago
|
args += rustc.get_buildtype_args(self.environment.coredata.get_builtin_option('buildtype'))
|
||
9 years ago
|
depfile = target.name + '.d'
|
||
11 years ago
|
args += ['--out-dir', target.subdir]
|
||
9 years ago
|
args += ['--emit', 'dep-info', '--emit', 'link']
|
||
11 years ago
|
orderdeps = [os.path.join(t.subdir, t.get_filename()) for t in target.link_targets]
|
||
|
linkdirs = {}
|
||
|
for d in target.link_targets:
|
||
|
linkdirs[d.subdir] = True
|
||
|
for d in linkdirs.keys():
|
||
|
if d == '':
|
||
|
d = '.'
|
||
11 years ago
|
args += ['-L', d]
|
||
11 years ago
|
element = NinjaBuildElement(target_name, 'rust_COMPILER', relsrc)
|
||
11 years ago
|
if len(orderdeps) > 0:
|
||
|
element.add_orderdep(orderdeps)
|
||
11 years ago
|
element.add_item('ARGS', args)
|
||
11 years ago
|
element.add_item('targetdep', depfile)
|
||
11 years ago
|
element.add_item('cratetype', cratetype)
|
||
11 years ago
|
element.write(outfile)
|
||
9 years ago
|
self.check_outputs(element)
|
||
11 years ago
|
|
||
9 years ago
|
def swift_module_file_name(self, target):
|
||
|
return os.path.join(self.get_target_private_dir(target),
|
||
|
self.target_swift_modulename(target) + '.swiftmodule')
|
||
|
|
||
|
def target_swift_modulename(self, target):
|
||
|
return target.name
|
||
|
|
||
9 years ago
|
def is_swift_target(self, target):
|
||
|
for s in target.sources:
|
||
|
if s.endswith('swift'):
|
||
|
return True
|
||
|
return False
|
||
|
|
||
9 years ago
|
def determine_swift_dep_modules(self, target):
|
||
|
result = []
|
||
|
for l in target.link_targets:
|
||
9 years ago
|
if self.is_swift_target(l):
|
||
|
result.append(self.swift_module_file_name(l))
|
||
9 years ago
|
return result
|
||
|
|
||
|
def determine_swift_dep_dirs(self, target):
|
||
|
result = []
|
||
|
for l in target.link_targets:
|
||
9 years ago
|
result.append(self.get_target_private_dir_abs(l))
|
||
9 years ago
|
return result
|
||
|
|
||
|
def get_swift_link_deps(self, target):
|
||
|
result = []
|
||
|
for l in target.link_targets:
|
||
|
result.append(self.get_target_filename(l))
|
||
|
return result
|
||
|
|
||
9 years ago
|
def split_swift_generated_sources(self, target):
|
||
|
all_srcs = []
|
||
|
for genlist in target.get_generated_sources():
|
||
|
if isinstance(genlist, build.CustomTarget):
|
||
|
for ifile in genlist.get_filename():
|
||
|
rel = os.path.join(self.get_target_dir(genlist), ifile)
|
||
|
all_srcs.append(rel)
|
||
|
else:
|
||
|
for ifile in genlist.get_outfilelist():
|
||
|
rel = os.path.join(self.get_target_private_dir(target), ifile)
|
||
|
all_srcs.append(rel)
|
||
|
srcs = []
|
||
|
others = []
|
||
|
for i in all_srcs:
|
||
|
if i.endswith('.swift'):
|
||
|
srcs.append(i)
|
||
|
else:
|
||
|
others.append(i)
|
||
|
return (srcs, others)
|
||
|
|
||
9 years ago
|
def generate_swift_target(self, target, outfile):
|
||
9 years ago
|
module_name = self.target_swift_modulename(target)
|
||
9 years ago
|
swiftc = self.environment.coredata.compilers['swift']
|
||
|
abssrc = []
|
||
9 years ago
|
abs_headers = []
|
||
|
header_imports = []
|
||
9 years ago
|
for i in target.get_sources():
|
||
9 years ago
|
if swiftc.can_compile(i):
|
||
|
relsrc = i.rel_to_builddir(self.build_to_src)
|
||
|
abss = os.path.normpath(os.path.join(self.environment.get_build_dir(), relsrc))
|
||
|
abssrc.append(abss)
|
||
|
elif self.environment.is_header(i):
|
||
|
relh = i.rel_to_builddir(self.build_to_src)
|
||
|
absh = os.path.normpath(os.path.join(self.environment.get_build_dir(), relh))
|
||
|
abs_headers.append(absh)
|
||
|
header_imports += swiftc.get_header_import_args(absh)
|
||
|
else:
|
||
9 years ago
|
raise InvalidArguments('Swift target %s contains a non-swift source file.' % target.get_basename())
|
||
9 years ago
|
os.makedirs(self.get_target_private_dir_abs(target), exist_ok=True)
|
||
9 years ago
|
compile_args = swiftc.get_compile_only_args()
|
||
9 years ago
|
compile_args += swiftc.get_module_args(module_name)
|
||
|
link_args = swiftc.get_output_args(os.path.join(self.environment.get_build_dir(), self.get_target_filename(target)))
|
||
9 years ago
|
rundir = self.get_target_private_dir(target)
|
||
9 years ago
|
out_module_name = self.swift_module_file_name(target)
|
||
|
in_module_files = self.determine_swift_dep_modules(target)
|
||
|
abs_module_dirs = self.determine_swift_dep_dirs(target)
|
||
|
module_includes = []
|
||
|
for x in abs_module_dirs:
|
||
|
module_includes += swiftc.get_include_args(x)
|
||
|
link_deps = self.get_swift_link_deps(target)
|
||
|
abs_link_deps = [os.path.join(self.environment.get_build_dir(), x) for x in link_deps]
|
||
9 years ago
|
(rel_generated, _) = self.split_swift_generated_sources(target)
|
||
|
abs_generated = [os.path.join(self.environment.get_build_dir(), x) for x in rel_generated]
|
||
|
# We need absolute paths because swiftc needs to be invoked in a subdir
|
||
|
# and this is the easiest way about it.
|
||
|
objects = [] # Relative to swift invocation dir
|
||
|
rel_objects = [] # Relative to build.ninja
|
||
|
for i in abssrc + abs_generated:
|
||
|
base = os.path.split(i)[1]
|
||
|
oname = os.path.splitext(base)[0] + '.o'
|
||
|
objects.append(oname)
|
||
|
rel_objects.append(os.path.join(self.get_target_private_dir(target), oname))
|
||
9 years ago
|
|
||
|
# Swiftc does not seem to be able to emit objects and module files in one go.
|
||
|
elem = NinjaBuildElement(rel_objects,
|
||
|
'swift_COMPILER',
|
||
|
abssrc)
|
||
9 years ago
|
elem.add_dep(in_module_files + rel_generated)
|
||
9 years ago
|
elem.add_dep(abs_headers)
|
||
|
elem.add_item('ARGS', compile_args + header_imports + abs_generated + module_includes)
|
||
9 years ago
|
elem.add_item('RUNDIR', rundir)
|
||
|
elem.write(outfile)
|
||
|
self.check_outputs(elem)
|
||
9 years ago
|
elem = NinjaBuildElement(out_module_name,
|
||
|
'swift_COMPILER',
|
||
|
abssrc)
|
||
9 years ago
|
elem.add_dep(in_module_files + rel_generated)
|
||
|
elem.add_item('ARGS', compile_args + abs_generated + module_includes + swiftc.get_mod_gen_args())
|
||
9 years ago
|
elem.add_item('RUNDIR', rundir)
|
||
|
elem.write(outfile)
|
||
|
self.check_outputs(elem)
|
||
9 years ago
|
if isinstance(target, build.StaticLibrary):
|
||
|
elem = self.generate_link(target, outfile, self.get_target_filename(target),
|
||
|
rel_objects, self.build.static_linker)
|
||
|
elem.write(outfile)
|
||
|
elif isinstance(target, build.Executable):
|
||
|
elem = NinjaBuildElement(self.get_target_filename(target), 'swift_COMPILER', [])
|
||
|
elem.add_dep(rel_objects)
|
||
|
elem.add_dep(link_deps)
|
||
|
elem.add_item('ARGS', link_args + swiftc.get_std_exe_link_args() + objects + abs_link_deps)
|
||
|
elem.add_item('RUNDIR', rundir)
|
||
|
elem.write(outfile)
|
||
|
self.check_outputs(elem)
|
||
|
else:
|
||
|
raise MesonException('Swift supports only executable and static library targets.')
|
||
9 years ago
|
|
||
11 years ago
|
def generate_static_link_rules(self, is_cross, outfile):
|
||
|
if self.build.has_language('java'):
|
||
|
if not is_cross:
|
||
|
self.generate_java_link(outfile)
|
||
|
if is_cross:
|
||
9 years ago
|
if self.environment.cross_info.need_cross_compiler():
|
||
|
static_linker = self.build.static_cross_linker
|
||
|
else:
|
||
|
static_linker = self.build.static_linker
|
||
11 years ago
|
crstr = '_CROSS'
|
||
|
else:
|
||
|
static_linker = self.build.static_linker
|
||
|
crstr = ''
|
||
|
if static_linker is None:
|
||
|
return
|
||
|
rule = 'rule STATIC%s_LINKER\n' % crstr
|
||
9 years ago
|
if mesonlib.is_windows():
|
||
|
command_templ = ''' command = %s @$out.rsp
|
||
|
rspfile = $out.rsp
|
||
|
rspfile_content = $LINK_ARGS %s $in
|
||
|
'''
|
||
|
else:
|
||
|
command_templ = ' command = %s $LINK_ARGS %s $in\n'
|
||
|
command = command_templ %\
|
||
11 years ago
|
(' '.join(static_linker.get_exelist()),
|
||
10 years ago
|
' '.join(static_linker.get_output_args('$out')))
|
||
11 years ago
|
description = ' description = Static linking library $out\n\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(description)
|
||
|
|
||
|
def generate_dynamic_link_rules(self, outfile):
|
||
9 years ago
|
ctypes = [(self.build.compilers, False)]
|
||
|
if self.environment.is_cross_build():
|
||
|
if self.environment.cross_info.need_cross_compiler():
|
||
|
ctypes.append((self.build.cross_compilers, True))
|
||
|
else:
|
||
|
# Native compiler masquerades as the cross compiler.
|
||
|
ctypes.append((self.build.compilers, True))
|
||
|
else:
|
||
|
ctypes.append((self.build.cross_compilers, True))
|
||
11 years ago
|
for (complist, is_cross) in ctypes:
|
||
|
for compiler in complist:
|
||
|
langname = compiler.get_language()
|
||
11 years ago
|
if langname == 'java' or langname == 'vala' or\
|
||
|
langname == 'rust' or langname == 'cs':
|
||
11 years ago
|
continue
|
||
|
crstr = ''
|
||
9 years ago
|
cross_args = []
|
||
11 years ago
|
if is_cross:
|
||
|
crstr = '_CROSS'
|
||
9 years ago
|
try:
|
||
|
cross_args = self.environment.cross_info.config['properties'][langname + '_link_args']
|
||
|
except KeyError:
|
||
|
pass
|
||
11 years ago
|
rule = 'rule %s%s_LINKER\n' % (langname, crstr)
|
||
9 years ago
|
if mesonlib.is_windows():
|
||
|
command_template = ''' command = %s @$out.rsp
|
||
|
rspfile = $out.rsp
|
||
|
rspfile_content = %s $ARGS %s $in $LINK_ARGS $aliasing
|
||
|
'''
|
||
|
else:
|
||
|
command_template = ' command = %s %s $ARGS %s $in $LINK_ARGS $aliasing\n'
|
||
|
command = command_template % \
|
||
10 years ago
|
(' '.join(compiler.get_linker_exelist()),\
|
||
9 years ago
|
' '.join(cross_args),\
|
||
11 years ago
|
' '.join(compiler.get_linker_output_args('$out')))
|
||
11 years ago
|
description = ' description = Linking target $out'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(description)
|
||
|
outfile.write('\n')
|
||
|
scriptdir = self.environment.get_script_dir()
|
||
|
outfile.write('\n')
|
||
|
symrule = 'rule SHSYM\n'
|
||
9 years ago
|
symcmd = ' command = "%s" "%s" %s %s %s %s $CROSS\n' % (ninja_quote(sys.executable),
|
||
|
self.environment.get_build_command(),
|
||
|
'--internal',
|
||
|
'symbolextractor',
|
||
|
'$in',
|
||
|
'$out')
|
||
11 years ago
|
synstat = ' restat = 1\n'
|
||
|
syndesc = ' description = Generating symbol file $out.\n'
|
||
|
outfile.write(symrule)
|
||
|
outfile.write(symcmd)
|
||
|
outfile.write(synstat)
|
||
|
outfile.write(syndesc)
|
||
|
outfile.write('\n')
|
||
|
|
||
|
def generate_java_compile_rule(self, compiler, outfile):
|
||
|
rule = 'rule %s_COMPILER\n' % compiler.get_language()
|
||
|
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
|
||
11 years ago
|
command = ' command = %s $ARGS $in\n' % invoc
|
||
11 years ago
|
description = ' description = Compiling Java object $in.\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(description)
|
||
|
outfile.write('\n')
|
||
|
|
||
11 years ago
|
def generate_cs_compile_rule(self, compiler, outfile):
|
||
|
rule = 'rule %s_COMPILER\n' % compiler.get_language()
|
||
|
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
|
||
|
command = ' command = %s $ARGS $in\n' % invoc
|
||
|
description = ' description = Compiling cs target $out.\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(description)
|
||
|
outfile.write('\n')
|
||
|
|
||
11 years ago
|
def generate_vala_compile_rules(self, compiler, outfile):
|
||
|
rule = 'rule %s_COMPILER\n' % compiler.get_language()
|
||
|
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
|
||
11 years ago
|
command = ' command = %s $ARGS $in\n' % invoc
|
||
11 years ago
|
description = ' description = Compiling Vala source $in.\n'
|
||
11 years ago
|
restat = ' restat = 1\n' # ValaC does this always to take advantage of it.
|
||
11 years ago
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(description)
|
||
11 years ago
|
outfile.write(restat)
|
||
11 years ago
|
outfile.write('\n')
|
||
|
|
||
11 years ago
|
def generate_rust_compile_rules(self, compiler, outfile):
|
||
|
rule = 'rule %s_COMPILER\n' % compiler.get_language()
|
||
|
invoc = ' '.join([ninja_quote(i) for i in compiler.get_exelist()])
|
||
9 years ago
|
command = ' command = %s $ARGS $in\n' % invoc
|
||
11 years ago
|
description = ' description = Compiling Rust source $in.\n'
|
||
9 years ago
|
depfile = ' depfile = $targetdep\n'
|
||
10 years ago
|
|
||
11 years ago
|
depstyle = ' deps = gcc\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(description)
|
||
|
outfile.write(depfile)
|
||
|
outfile.write(depstyle)
|
||
|
outfile.write('\n')
|
||
|
|
||
9 years ago
|
def generate_swift_compile_rules(self, compiler, outfile):
|
||
|
rule = 'rule %s_COMPILER\n' % compiler.get_language()
|
||
9 years ago
|
full_exe = [sys.executable,
|
||
9 years ago
|
self.environment.get_build_command(),
|
||
|
'--internal',
|
||
|
'dirchanger',
|
||
9 years ago
|
'$RUNDIR'] + compiler.get_exelist()
|
||
|
invoc = ' '.join([ninja_quote(i) for i in full_exe])
|
||
9 years ago
|
command = ' command = %s $ARGS $in\n' % invoc
|
||
|
description = ' description = Compiling Swift source $in.\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(description)
|
||
|
outfile.write('\n')
|
||
|
|
||
10 years ago
|
def generate_fortran_dep_hack(self, outfile):
|
||
10 years ago
|
if mesonlib.is_windows():
|
||
10 years ago
|
cmd = 'cmd /C ""'
|
||
|
else:
|
||
|
cmd = 'true'
|
||
|
template = '''# Workaround for these issues:
|
||
10 years ago
|
# https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8
|
||
|
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47485
|
||
|
rule FORTRAN_DEP_HACK
|
||
10 years ago
|
command = %s
|
||
10 years ago
|
description = Dep hack
|
||
|
restat = 1
|
||
|
|
||
|
'''
|
||
10 years ago
|
outfile.write(template % cmd)
|
||
10 years ago
|
|
||
11 years ago
|
def generate_compile_rule_for(self, langname, compiler, qstr, is_cross, outfile):
|
||
|
if langname == 'java':
|
||
|
if not is_cross:
|
||
|
self.generate_java_compile_rule(compiler, outfile)
|
||
|
return
|
||
11 years ago
|
if langname == 'cs':
|
||
|
if not is_cross:
|
||
|
self.generate_cs_compile_rule(compiler, outfile)
|
||
|
return
|
||
11 years ago
|
if langname == 'vala':
|
||
|
if not is_cross:
|
||
|
self.generate_vala_compile_rules(compiler, outfile)
|
||
11 years ago
|
return
|
||
11 years ago
|
if langname == 'rust':
|
||
|
if not is_cross:
|
||
|
self.generate_rust_compile_rules(compiler, outfile)
|
||
|
return
|
||
9 years ago
|
if langname == 'swift':
|
||
|
if not is_cross:
|
||
|
self.generate_swift_compile_rules(compiler, outfile)
|
||
|
return
|
||
10 years ago
|
if langname == 'fortran':
|
||
|
self.generate_fortran_dep_hack(outfile)
|
||
11 years ago
|
if is_cross:
|
||
|
crstr = '_CROSS'
|
||
|
else:
|
||
|
crstr = ''
|
||
|
rule = 'rule %s%s_COMPILER\n' % (langname, crstr)
|
||
11 years ago
|
depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE')
|
||
10 years ago
|
quoted_depargs = []
|
||
|
for d in depargs:
|
||
|
if d != '$out' and d != '$in':
|
||
|
d = qstr % d
|
||
|
quoted_depargs.append(d)
|
||
9 years ago
|
cross_args = []
|
||
|
if is_cross:
|
||
|
try:
|
||
|
cross_args = self.environment.cross_info.config['properties'][langname + '_args']
|
||
|
except KeyError:
|
||
|
pass
|
||
9 years ago
|
if mesonlib.is_windows():
|
||
|
command_template = ''' command = %s @$out.rsp
|
||
|
rspfile = $out.rsp
|
||
|
rspfile_content = %s $ARGS %s %s %s $in
|
||
|
'''
|
||
|
else:
|
||
|
command_template = ' command = %s %s $ARGS %s %s %s $in\n'
|
||
|
command = command_template % \
|
||
11 years ago
|
(' '.join(compiler.get_exelist()),\
|
||
9 years ago
|
' '.join(cross_args),
|
||
10 years ago
|
' '.join(quoted_depargs),\
|
||
11 years ago
|
' '.join(compiler.get_output_args('$out')),\
|
||
|
' '.join(compiler.get_compile_only_args()))
|
||
11 years ago
|
description = ' description = Compiling %s object $out\n' % langname
|
||
|
if compiler.get_id() == 'msvc':
|
||
|
deps = ' deps = msvc\n'
|
||
|
else:
|
||
|
deps = ' deps = gcc\n'
|
||
|
deps += ' depfile = $DEPFILE\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(deps)
|
||
|
outfile.write(description)
|
||
|
outfile.write('\n')
|
||
|
|
||
|
def generate_pch_rule_for(self, langname, compiler, qstr, is_cross, outfile):
|
||
|
if langname != 'c' and langname != 'cpp':
|
||
|
return
|
||
|
if is_cross:
|
||
|
crstr = '_CROSS'
|
||
|
else:
|
||
|
crstr = ''
|
||
|
rule = 'rule %s%s_PCH\n' % (langname, crstr)
|
||
11 years ago
|
depargs = compiler.get_dependency_gen_args('$out', '$DEPFILE')
|
||
9 years ago
|
cross_args = []
|
||
|
if is_cross:
|
||
|
try:
|
||
|
cross_args = self.environment.cross_info.config['properties'][langname + '_args']
|
||
|
except KeyError:
|
||
|
pass
|
||
|
|
||
10 years ago
|
quoted_depargs = []
|
||
|
for d in depargs:
|
||
|
if d != '$out' and d != '$in':
|
||
|
d = qstr % d
|
||
|
quoted_depargs.append(d)
|
||
11 years ago
|
if compiler.get_id() == 'msvc':
|
||
|
output = ''
|
||
|
else:
|
||
11 years ago
|
output = ' '.join(compiler.get_output_args('$out'))
|
||
9 years ago
|
command = " command = %s %s $ARGS %s %s %s $in\n" % \
|
||
11 years ago
|
(' '.join(compiler.get_exelist()),\
|
||
9 years ago
|
' '.join(cross_args),\
|
||
10 years ago
|
' '.join(quoted_depargs),\
|
||
11 years ago
|
output,\
|
||
11 years ago
|
' '.join(compiler.get_compile_only_args()))
|
||
11 years ago
|
description = ' description = Precompiling header %s\n' % '$in'
|
||
|
if compiler.get_id() == 'msvc':
|
||
|
deps = ' deps = msvc\n'
|
||
|
else:
|
||
|
deps = ' deps = gcc\n'
|
||
|
deps += ' depfile = $DEPFILE\n'
|
||
|
outfile.write(rule)
|
||
|
outfile.write(command)
|
||
|
outfile.write(deps)
|
||
|
outfile.write(description)
|
||
|
outfile.write('\n')
|
||
|
|
||
|
def generate_compile_rules(self, outfile):
|
||
|
qstr = quote_char + "%s" + quote_char
|
||
|
for compiler in self.build.compilers:
|
||
|
langname = compiler.get_language()
|
||
|
self.generate_compile_rule_for(langname, compiler, qstr, False, outfile)
|
||
|
self.generate_pch_rule_for(langname, compiler, qstr, False, outfile)
|
||
|
if self.environment.is_cross_build():
|
||
9 years ago
|
# In case we are going a target-only build, make the native compilers
|
||
|
# masquerade as cross compilers.
|
||
|
if self.environment.cross_info.need_cross_compiler():
|
||
|
cclist = self.build.cross_compilers
|
||
|
else:
|
||
|
cclist = self.build.compilers
|
||
|
for compiler in cclist:
|
||
11 years ago
|
langname = compiler.get_language()
|
||
|
self.generate_compile_rule_for(langname, compiler, qstr, True, outfile)
|
||
|
self.generate_pch_rule_for(langname, compiler, qstr, True, outfile)
|
||
|
outfile.write('\n')
|
||
|
|
||
10 years ago
|
def replace_outputs(self, args, private_dir, output_list):
|
||
|
newargs = []
|
||
|
regex = re.compile('@OUTPUT(\d+)@')
|
||
|
for arg in args:
|
||
|
m = regex.search(arg)
|
||
|
while m is not None:
|
||
|
index = int(m.group(1))
|
||
|
src = '@OUTPUT%d@' % index
|
||
|
arg = arg.replace(src, os.path.join(private_dir, output_list[index]))
|
||
|
m = regex.search(arg)
|
||
|
newargs.append(arg)
|
||
|
return newargs
|
||
|
|
||
11 years ago
|
def generate_custom_generator_rules(self, target, outfile):
|
||
|
for genlist in target.get_generated_sources():
|
||
10 years ago
|
if isinstance(genlist, build.CustomTarget):
|
||
|
continue # Customtarget has already written its output rules
|
||
11 years ago
|
generator = genlist.get_generator()
|
||
|
exe = generator.get_exe()
|
||
9 years ago
|
exe_arr = self.exe_object_to_cmd_array(exe)
|
||
11 years ago
|
infilelist = genlist.get_infilelist()
|
||
|
outfilelist = genlist.get_outfilelist()
|
||
|
base_args = generator.get_arglist()
|
||
10 years ago
|
extra_dependencies = [os.path.join(self.build_to_src, i) for i in genlist.extra_depends]
|
||
11 years ago
|
for i in range(len(infilelist)):
|
||
10 years ago
|
if len(generator.outputs) == 1:
|
||
9 years ago
|
sole_output = os.path.join(self.get_target_private_dir(target), outfilelist[i])
|
||
11 years ago
|
else:
|
||
|
sole_output = ''
|
||
|
curfile = infilelist[i]
|
||
9 years ago
|
infilename = os.path.join(self.build_to_src, curfile)
|
||
11 years ago
|
outfiles = genlist.get_outputs_for(curfile)
|
||
9 years ago
|
outfiles = [os.path.join(self.get_target_private_dir(target), of) for of in outfiles]
|
||
11 years ago
|
args = [x.replace("@INPUT@", infilename).replace('@OUTPUT@', sole_output)\
|
||
|
for x in base_args]
|
||
9 years ago
|
args = self.replace_outputs(args, self.get_target_private_dir(target), outfilelist)
|
||
9 years ago
|
# We have consumed output files, so drop them from the list of remaining outputs.
|
||
9 years ago
|
if sole_output == '':
|
||
|
outfilelist = outfilelist[len(generator.outputs):]
|
||
9 years ago
|
relout = self.get_target_private_dir(target)
|
||
9 years ago
|
args = [x.replace("@SOURCE_DIR@", self.build_to_src).replace("@BUILD_DIR@", relout)
|
||
11 years ago
|
for x in args]
|
||
9 years ago
|
final_args = []
|
||
|
for a in args:
|
||
|
if a == '@EXTRA_ARGS@':
|
||
|
final_args += genlist.get_extra_args()
|
||
|
else:
|
||
|
final_args.append(a)
|
||
|
cmdlist = exe_arr + final_args
|
||
11 years ago
|
elem = NinjaBuildElement(outfiles, 'CUSTOM_COMMAND', infilename)
|
||
10 years ago
|
if len(extra_dependencies) > 0:
|
||
|
elem.add_dep(extra_dependencies)
|
||
11 years ago
|
elem.add_item('DESC', 'Generating $out')
|
||
|
if isinstance(exe, build.BuildTarget):
|
||
|
elem.add_dep(self.get_target_filename(exe))
|
||
|
elem.add_item('COMMAND', cmdlist)
|
||
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
|
||
10 years ago
|
def scan_fortran_module_outputs(self, target):
|
||
|
compiler = None
|
||
|
for c in self.build.compilers:
|
||
|
if c.get_language() == 'fortran':
|
||
|
compiler = c
|
||
|
break
|
||
|
if compiler is None:
|
||
|
self.fortran_deps[target.get_basename()] = {}
|
||
|
return
|
||
|
modre = re.compile(r"\s*module\s+(\w+)", re.IGNORECASE)
|
||
|
module_files = {}
|
||
|
for s in target.get_sources():
|
||
|
# FIXME, does not work for generated Fortran sources,
|
||
|
# but those are really rare. I hope.
|
||
|
if not compiler.can_compile(s):
|
||
|
continue
|
||
10 years ago
|
for line in open(os.path.join(self.environment.get_source_dir(), s.subdir, s.fname)):
|
||
10 years ago
|
modmatch = modre.match(line)
|
||
|
if modmatch is not None:
|
||
|
modname = modmatch.group(1)
|
||
10 years ago
|
if modname.lower() == 'procedure': # MODULE PROCEDURE construct
|
||
|
continue
|
||
10 years ago
|
if modname in module_files:
|
||
|
raise InvalidArguments('Namespace collision: module %s defined in two files %s and %s.' %
|
||
|
(modname, module_files[modname], s))
|
||
|
module_files[modname] = s
|
||
|
self.fortran_deps[target.get_basename()] = module_files
|
||
|
|
||
10 years ago
|
def get_fortran_deps(self, compiler, src, target):
|
||
10 years ago
|
mod_files = []
|
||
10 years ago
|
usere = re.compile(r"\s*use\s+(\w+)", re.IGNORECASE)
|
||
9 years ago
|
dirname = self.get_target_private_dir(target)
|
||
10 years ago
|
tdeps= self.fortran_deps[target.get_basename()]
|
||
10 years ago
|
for line in open(src):
|
||
|
usematch = usere.match(line)
|
||
|
if usematch is not None:
|
||
10 years ago
|
usename = usematch.group(1)
|
||
|
if usename not in tdeps:
|
||
10 years ago
|
# The module is not provided by any source file. This is due to
|
||
|
# a) missing file/typo/etc
|
||
|
# b) using a module provided by the compiler, such as OpenMP
|
||
|
# There's no easy way to tell which is which (that I know of)
|
||
|
# so just ignore this and go on. Ideally we would print a
|
||
|
# warning message to the user but this is a common occurrance,
|
||
|
# which would lead to lots of distracting noise.
|
||
|
continue
|
||
10 years ago
|
mod_source_file = tdeps[usename]
|
||
10 years ago
|
# Check if a source uses a module it exports itself.
|
||
|
# Potential bug if multiple targets have a file with
|
||
|
# the same name.
|
||
10 years ago
|
if mod_source_file.fname == os.path.split(src)[1]:
|
||
10 years ago
|
continue
|
||
10 years ago
|
mod_name = compiler.module_name_to_filename(usematch.group(1))
|
||
|
mod_files.append(os.path.join(dirname, mod_name))
|
||
|
return mod_files
|
||
10 years ago
|
|
||
11 years ago
|
def generate_single_compile(self, target, outfile, src, is_generated=False, header_deps=[], order_deps=[]):
|
||
10 years ago
|
if(isinstance(src, str) and src.endswith('.h')):
|
||
|
raise RuntimeError('Fug')
|
||
|
if isinstance(src, RawFilename) and src.fname.endswith('.h'):
|
||
|
raise RuntimeError('Fug')
|
||
10 years ago
|
extra_orderdeps = []
|
||
11 years ago
|
compiler = self.get_compiler_for_source(src)
|
||
11 years ago
|
commands = self.generate_basic_compiler_args(target, compiler)
|
||
9 years ago
|
commands += compiler.get_include_args(self.get_target_private_dir(target), False)
|
||
10 years ago
|
curdir = target.get_subdir()
|
||
10 years ago
|
tmppath = os.path.normpath(os.path.join(self.build_to_src, curdir))
|
||
9 years ago
|
commands += compiler.get_include_args(tmppath, False)
|
||
10 years ago
|
if curdir == '':
|
||
|
curdir = '.'
|
||
9 years ago
|
commands += compiler.get_include_args(curdir, False)
|
||
10 years ago
|
for d in target.external_deps:
|
||
|
if d.need_threads():
|
||
|
commands += compiler.thread_flags()
|
||
|
break
|
||
10 years ago
|
if isinstance(src, RawFilename):
|
||
10 years ago
|
rel_src = src.fname
|
||
|
elif is_generated:
|
||
9 years ago
|
if self.has_dir_part(src):
|
||
11 years ago
|
rel_src = src
|
||
|
else:
|
||
9 years ago
|
rel_src = os.path.join(self.get_target_private_dir(target), src)
|
||
10 years ago
|
abs_src = os.path.join(self.environment.get_source_dir(), rel_src)
|
||
11 years ago
|
else:
|
||
10 years ago
|
if isinstance(src, File):
|
||
10 years ago
|
rel_src = src.rel_to_builddir(self.build_to_src)
|
||
|
else:
|
||
10 years ago
|
raise build.InvalidArguments('Invalid source type.')
|
||
10 years ago
|
abs_src = os.path.join(self.environment.get_build_dir(), rel_src)
|
||
10 years ago
|
if isinstance(src, RawFilename):
|
||
|
src_filename = src.fname
|
||
10 years ago
|
elif isinstance(src, File):
|
||
|
src_filename = src.fname
|
||
10 years ago
|
elif os.path.isabs(src):
|
||
11 years ago
|
src_filename = os.path.basename(src)
|
||
|
else:
|
||
|
src_filename = src
|
||
|
obj_basename = src_filename.replace('/', '_').replace('\\', '_')
|
||
9 years ago
|
rel_obj = os.path.join(self.get_target_private_dir(target), obj_basename)
|
||
11 years ago
|
rel_obj += '.' + self.environment.get_object_suffix()
|
||
9 years ago
|
dep_file = compiler.depfile_for_object(rel_obj)
|
||
9 years ago
|
if self.environment.coredata.get_builtin_option('use_pch'):
|
||
11 years ago
|
pchlist = target.get_pch(compiler.language)
|
||
|
else:
|
||
|
pchlist = []
|
||
|
if len(pchlist) == 0:
|
||
|
pch_dep = []
|
||
|
else:
|
||
|
arr = []
|
||
9 years ago
|
i = os.path.join(self.get_target_private_dir(target), compiler.get_pch_name(pchlist[0]))
|
||
11 years ago
|
arr.append(i)
|
||
|
pch_dep = arr
|
||
|
for i in target.get_include_dirs():
|
||
|
basedir = i.get_curdir()
|
||
|
for d in i.get_incdirs():
|
||
|
expdir = os.path.join(basedir, d)
|
||
9 years ago
|
srctreedir = os.path.join(self.build_to_src, expdir)
|
||
9 years ago
|
bargs = compiler.get_include_args(expdir, i.is_system)
|
||
|
sargs = compiler.get_include_args(srctreedir, i.is_system)
|
||
10 years ago
|
commands += bargs
|
||
|
commands += sargs
|
||
9 years ago
|
for d in i.get_extra_build_dirs():
|
||
9 years ago
|
commands += compiler.get_include_args(d, i.is_system)
|
||
9 years ago
|
custom_target_include_dirs = []
|
||
|
for i in target.generated:
|
||
|
if isinstance(i, build.CustomTarget):
|
||
|
idir = self.get_target_dir(i)
|
||
|
if idir not in custom_target_include_dirs:
|
||
|
custom_target_include_dirs.append(idir)
|
||
|
for i in custom_target_include_dirs:
|
||
9 years ago
|
commands+= compiler.get_include_args(i, False)
|
||
9 years ago
|
if self.environment.coredata.get_builtin_option('use_pch'):
|
||
11 years ago
|
commands += self.get_pch_include_args(compiler, target)
|
||
|
crstr = ''
|
||
|
if target.is_cross:
|
||
|
crstr = '_CROSS'
|
||
|
compiler_name = '%s%s_COMPILER' % (compiler.get_language(), crstr)
|
||
10 years ago
|
extra_deps = []
|
||
10 years ago
|
if compiler.get_language() == 'fortran':
|
||
10 years ago
|
extra_deps += self.get_fortran_deps(compiler, abs_src, target)
|
||
|
# Dependency hack. Remove once multiple outputs in Ninja is fixed:
|
||
|
# https://groups.google.com/forum/#!topic/ninja-build/j-2RfBIOd_8
|
||
|
for modname, srcfile in self.fortran_deps[target.get_basename()].items():
|
||
9 years ago
|
modfile = os.path.join(self.get_target_private_dir(target),
|
||
10 years ago
|
compiler.module_name_to_filename(modname))
|
||
|
if srcfile == src:
|
||
|
depelem = NinjaBuildElement(modfile, 'FORTRAN_DEP_HACK', rel_obj)
|
||
|
depelem.write(outfile)
|
||
9 years ago
|
self.check_outputs(depelem)
|
||
9 years ago
|
commands += compiler.get_module_outdir_args(self.get_target_private_dir(target))
|
||
11 years ago
|
|
||
10 years ago
|
element = NinjaBuildElement(rel_obj, compiler_name, rel_src)
|
||
11 years ago
|
for d in header_deps:
|
||
10 years ago
|
if isinstance(d, RawFilename):
|
||
10 years ago
|
d = d.fname
|
||
9 years ago
|
elif not self.has_dir_part(d):
|
||
9 years ago
|
d = os.path.join(self.get_target_private_dir(target), d)
|
||
11 years ago
|
element.add_dep(d)
|
||
10 years ago
|
for d in extra_deps:
|
||
|
element.add_dep(d)
|
||
11 years ago
|
for d in order_deps:
|
||
10 years ago
|
if isinstance(d, RawFilename):
|
||
10 years ago
|
d = d.fname
|
||
9 years ago
|
elif not self.has_dir_part(d):
|
||
9 years ago
|
d = os.path.join(self.get_target_private_dir(target), d)
|
||
11 years ago
|
element.add_orderdep(d)
|
||
11 years ago
|
element.add_orderdep(pch_dep)
|
||
10 years ago
|
element.add_orderdep(extra_orderdeps)
|
||
9 years ago
|
for i in self.get_fortran_orderdeps(target, compiler):
|
||
|
element.add_orderdep(i)
|
||
11 years ago
|
element.add_item('DEPFILE', dep_file)
|
||
11 years ago
|
element.add_item('ARGS', commands)
|
||
11 years ago
|
element.write(outfile)
|
||
9 years ago
|
self.check_outputs(element)
|
||
11 years ago
|
return rel_obj
|
||
|
|
||
9 years ago
|
def has_dir_part(self, fname):
|
||
|
return '/' in fname or '\\' in fname
|
||
|
|
||
9 years ago
|
# Fortran is a bit weird (again). When you link against a library, just compiling a source file
|
||
|
# requires the mod files that are output when single files are built. To do this right we would need to
|
||
|
# scan all inputs and write out explicit deps for each file. That is stoo slow and too much effort so
|
||
9 years ago
|
# instead just have an ordered dependendy on the library. This ensures all required mod files are created.
|
||
9 years ago
|
# The real deps are then detected via dep file generation from the compiler. This breaks on compilers that
|
||
|
# produce incorrect dep files but such is life.
|
||
|
def get_fortran_orderdeps(self, target, compiler):
|
||
|
if compiler.language != 'fortran':
|
||
|
return []
|
||
9 years ago
|
return [os.path.join(self.get_target_dir(lt), lt.get_filename()) for lt in target.link_targets]
|
||
9 years ago
|
|
||
11 years ago
|
def generate_msvc_pch_command(self, target, compiler, pch):
|
||
|
if len(pch) != 2:
|
||
|
raise RuntimeError('MSVC requires one header and one source to produce precompiled headers.')
|
||
|
header = pch[0]
|
||
|
source = pch[1]
|
||
|
pchname = compiler.get_pch_name(header)
|
||
9 years ago
|
dst = os.path.join(self.get_target_private_dir(target), pchname)
|
||
11 years ago
|
|
||
|
commands = []
|
||
11 years ago
|
commands += self.generate_basic_compiler_args(target, compiler)
|
||
11 years ago
|
just_name = os.path.split(header)[1]
|
||
10 years ago
|
(objname, pch_args) = compiler.gen_pch_args(just_name, source, dst)
|
||
|
commands += pch_args
|
||
11 years ago
|
dep = dst + '.' + compiler.get_depfile_suffix()
|
||
10 years ago
|
return (commands, dep, dst, [objname])
|
||
11 years ago
|
|
||
|
def generate_gcc_pch_command(self, target, compiler, pch):
|
||
|
commands = []
|
||
11 years ago
|
commands += self.generate_basic_compiler_args(target, compiler)
|
||
9 years ago
|
dst = os.path.join(self.get_target_private_dir(target),
|
||
11 years ago
|
os.path.split(pch)[-1] + '.' + compiler.get_pch_suffix())
|
||
|
dep = dst + '.' + compiler.get_depfile_suffix()
|
||
10 years ago
|
return (commands, dep, dst, []) # Gcc does not create an object file during pch generation.
|
||
11 years ago
|
|
||
|
def generate_pch(self, target, outfile):
|
||
|
cstr = ''
|
||
10 years ago
|
pch_objects = []
|
||
11 years ago
|
if target.is_cross:
|
||
|
cstr = '_CROSS'
|
||
|
for lang in ['c', 'cpp']:
|
||
|
pch = target.get_pch(lang)
|
||
|
if len(pch) == 0:
|
||
|
continue
|
||
|
if '/' not in pch[0] or '/' not in pch[-1]:
|
||
|
raise build.InvalidArguments('Precompiled header of "%s" must not be in the same directory as source, please put it in a subdirectory.' % target.get_basename())
|
||
|
compiler = self.get_compiler_for_lang(lang)
|
||
|
if compiler.id == 'msvc':
|
||
|
src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[-1])
|
||
10 years ago
|
(commands, dep, dst, objs) = self.generate_msvc_pch_command(target, compiler, pch)
|
||
11 years ago
|
extradep = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0])
|
||
|
else:
|
||
|
src = os.path.join(self.build_to_src, target.get_source_subdir(), pch[0])
|
||
10 years ago
|
(commands, dep, dst, objs) = self.generate_gcc_pch_command(target, compiler, pch[0])
|
||
11 years ago
|
extradep = None
|
||
10 years ago
|
pch_objects += objs
|
||
11 years ago
|
rulename = compiler.get_language() + cstr + '_PCH'
|
||
|
elem = NinjaBuildElement(dst, rulename, src)
|
||
|
if extradep is not None:
|
||
|
elem.add_dep(extradep)
|
||
11 years ago
|
elem.add_item('ARGS', commands)
|
||
11 years ago
|
elem.add_item('DEPFILE', dep)
|
||
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
10 years ago
|
return pch_objects
|
||
11 years ago
|
|
||
|
def generate_shsym(self, outfile, target):
|
||
|
target_name = self.get_target_filename(target)
|
||
9 years ago
|
targetdir = self.get_target_private_dir(target)
|
||
11 years ago
|
symname = os.path.join(targetdir, target_name + '.symbols')
|
||
|
elem = NinjaBuildElement(symname, 'SHSYM', target_name)
|
||
9 years ago
|
if self.environment.is_cross_build() and self.environment.cross_info.need_cross_compiler():
|
||
9 years ago
|
elem.add_item('CROSS', '--cross-host=' + self.environment.cross_info.config['host_machine']['system'])
|
||
11 years ago
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
|
||
10 years ago
|
def generate_link(self, target, outfile, outname, obj_list, linker, extra_args=[]):
|
||
11 years ago
|
if isinstance(target, build.StaticLibrary):
|
||
|
linker_base = 'STATIC'
|
||
|
else:
|
||
|
linker_base = linker.get_language() # Fixme.
|
||
|
if isinstance(target, build.SharedLibrary):
|
||
|
self.generate_shsym(outfile, target)
|
||
|
crstr = ''
|
||
|
if target.is_cross:
|
||
|
crstr = '_CROSS'
|
||
|
linker_rule = linker_base + crstr + '_LINKER'
|
||
|
abspath = os.path.join(self.environment.get_build_dir(), target.subdir)
|
||
|
commands = []
|
||
11 years ago
|
commands += linker.get_linker_always_args()
|
||
9 years ago
|
commands += linker.get_buildtype_linker_args(self.environment.coredata.get_builtin_option('buildtype'))
|
||
9 years ago
|
commands += linker.get_option_link_args(self.environment.coredata.compiler_options)
|
||
11 years ago
|
if not(isinstance(target, build.StaticLibrary)):
|
||
11 years ago
|
commands += self.environment.coredata.external_link_args[linker.get_language()]
|
||
11 years ago
|
if isinstance(target, build.Executable):
|
||
11 years ago
|
commands += linker.get_std_exe_link_args()
|
||
11 years ago
|
elif isinstance(target, build.SharedLibrary):
|
||
11 years ago
|
commands += linker.get_std_shared_lib_link_args()
|
||
|
commands += linker.get_pic_args()
|
||
11 years ago
|
if hasattr(target, 'soversion'):
|
||
|
soversion = target.soversion
|
||
|
else:
|
||
|
soversion = None
|
||
|
commands += linker.get_soname_args(target.name, abspath, soversion)
|
||
11 years ago
|
elif isinstance(target, build.StaticLibrary):
|
||
11 years ago
|
commands += linker.get_std_link_args()
|
||
11 years ago
|
else:
|
||
|
raise RuntimeError('Unknown build target type.')
|
||
10 years ago
|
# Link arguments of static libraries are not put in the command line of
|
||
|
# the library. They are instead appended to the command line where
|
||
|
# the static library is used.
|
||
|
if linker_base == 'STATIC':
|
||
|
dependencies = []
|
||
|
else:
|
||
|
dependencies = target.get_dependencies()
|
||
11 years ago
|
commands += self.build_target_link_arguments(linker, dependencies)
|
||
10 years ago
|
for d in target.external_deps:
|
||
|
if d.need_threads():
|
||
|
commands += linker.thread_link_flags()
|
||
9 years ago
|
if not isinstance(target, build.StaticLibrary):
|
||
|
commands += target.link_args
|
||
11 years ago
|
# External deps must be last because target link libraries may depend on them.
|
||
11 years ago
|
if not(isinstance(target, build.StaticLibrary)):
|
||
|
for dep in target.get_external_deps():
|
||
11 years ago
|
commands += dep.get_link_args()
|
||
10 years ago
|
for d in target.get_dependencies():
|
||
|
if isinstance(d, build.StaticLibrary):
|
||
|
for dep in d.get_external_deps():
|
||
|
commands += dep.get_link_args()
|
||
11 years ago
|
commands += linker.build_rpath_args(self.environment.get_build_dir(),\
|
||
9 years ago
|
self.determine_rpath_dirs(target), target.install_rpath)
|
||
9 years ago
|
if self.environment.coredata.get_builtin_option('coverage'):
|
||
11 years ago
|
commands += linker.get_coverage_link_args()
|
||
9 years ago
|
custom_target_libraries = self.get_custom_target_provided_libraries(target)
|
||
10 years ago
|
commands += extra_args
|
||
9 years ago
|
commands += custom_target_libraries
|
||
9 years ago
|
commands = linker.unixtype_flags_to_native(commands)
|
||
11 years ago
|
dep_targets = [self.get_dependency_filename(t) for t in dependencies]
|
||
|
dep_targets += [os.path.join(self.environment.source_dir,
|
||
|
target.subdir, t) for t in target.link_depends]
|
||
|
elem = NinjaBuildElement(outname, linker_rule, obj_list)
|
||
9 years ago
|
elem.add_dep(dep_targets + custom_target_libraries)
|
||
11 years ago
|
elem.add_item('LINK_ARGS', commands)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
return elem
|
||
|
|
||
9 years ago
|
def get_custom_target_provided_libraries(self, target):
|
||
|
libs = []
|
||
|
for t in target.get_generated_sources():
|
||
|
if not isinstance(t, build.CustomTarget):
|
||
|
continue
|
||
|
for f in t.output:
|
||
|
if self.environment.is_library(f):
|
||
9 years ago
|
libs.append(os.path.join(self.get_target_dir(t), f))
|
||
9 years ago
|
return libs
|
||
|
|
||
9 years ago
|
def determine_rpath_dirs(self, target):
|
||
|
link_deps = target.get_all_link_deps()
|
||
|
result = []
|
||
|
for ld in link_deps:
|
||
|
prospective = self.get_target_dir(ld)
|
||
|
if not prospective in result:
|
||
|
result.append(prospective)
|
||
|
return result
|
||
|
|
||
11 years ago
|
def get_dependency_filename(self, t):
|
||
|
if isinstance(t, build.SharedLibrary):
|
||
9 years ago
|
return os.path.join(self.get_target_private_dir(t), self.get_target_filename(t) + '.symbols')
|
||
11 years ago
|
return self.get_target_filename(t)
|
||
|
|
||
9 years ago
|
def generate_shlib_aliases(self, target, outdir):
|
||
11 years ago
|
basename = target.get_filename()
|
||
|
aliases = target.get_aliaslist()
|
||
9 years ago
|
if not mesonlib.is_windows():
|
||
11 years ago
|
for alias in aliases:
|
||
9 years ago
|
aliasfile = os.path.join(self.environment.get_build_dir(), outdir, alias)
|
||
|
try:
|
||
|
os.remove(aliasfile)
|
||
|
except Exception:
|
||
|
pass
|
||
|
os.symlink(basename, aliasfile)
|
||
11 years ago
|
else:
|
||
9 years ago
|
mlog.debug("Library versioning disabled because host does not support symlinks.")
|
||
11 years ago
|
|
||
|
def generate_gcov_clean(self, outfile):
|
||
10 years ago
|
gcno_elem = NinjaBuildElement('clean-gcno', 'CUSTOM_COMMAND', 'PHONY')
|
||
11 years ago
|
script_root = self.environment.get_script_dir()
|
||
|
clean_script = os.path.join(script_root, 'delwithsuffix.py')
|
||
9 years ago
|
gcno_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcno'])
|
||
11 years ago
|
gcno_elem.add_item('description', 'Deleting gcno files')
|
||
|
gcno_elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(gcno_elem)
|
||
11 years ago
|
|
||
10 years ago
|
gcda_elem = NinjaBuildElement('clean-gcda', 'CUSTOM_COMMAND', 'PHONY')
|
||
11 years ago
|
script_root = self.environment.get_script_dir()
|
||
|
clean_script = os.path.join(script_root, 'delwithsuffix.py')
|
||
9 years ago
|
gcda_elem.add_item('COMMAND', [sys.executable, clean_script, '.', 'gcda'])
|
||
11 years ago
|
gcda_elem.add_item('description', 'Deleting gcda files')
|
||
|
gcda_elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(gcda_elem)
|
||
11 years ago
|
|
||
|
def is_compilable_file(self, filename):
|
||
|
if filename.endswith('.cpp') or\
|
||
|
filename.endswith('.c') or\
|
||
|
filename.endswith('.cxx') or\
|
||
|
filename.endswith('.cc') or\
|
||
|
filename.endswith('.C'):
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
def process_dep_gens(self, outfile, target):
|
||
|
src_deps = []
|
||
|
other_deps = []
|
||
|
for rule in self.dep_rules.values():
|
||
|
srcs = target.get_original_kwargs().get(rule.src_keyword, [])
|
||
|
if isinstance(srcs, str):
|
||
|
srcs = [srcs]
|
||
|
for src in srcs:
|
||
|
plainname = os.path.split(src)[1]
|
||
|
basename = plainname.split('.')[0]
|
||
|
outname = rule.name_templ.replace('@BASENAME@', basename).replace('@PLAINNAME@', plainname)
|
||
9 years ago
|
outfilename = os.path.join(self.get_target_private_dir(target), outname)
|
||
11 years ago
|
infilename = os.path.join(self.build_to_src, target.get_source_subdir(), src)
|
||
11 years ago
|
elem = NinjaBuildElement(outfilename, rule.name, infilename)
|
||
11 years ago
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
if self.is_compilable_file(outfilename):
|
||
10 years ago
|
src_deps.append(outfilename)
|
||
11 years ago
|
else:
|
||
|
other_deps.append(outfilename)
|
||
|
return (src_deps, other_deps)
|
||
|
|
||
|
def generate_ending(self, outfile):
|
||
11 years ago
|
targetlist = [self.get_target_filename(t) for t in self.build.get_targets().values()\
|
||
|
if not isinstance(t, build.RunTarget)]
|
||
|
|
||
11 years ago
|
elem = NinjaBuildElement('all', 'phony', targetlist)
|
||
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
|
||
|
default = 'default all\n\n'
|
||
|
outfile.write(default)
|
||
|
|
||
|
ninja_command = environment.detect_ninja()
|
||
|
if ninja_command is None:
|
||
10 years ago
|
raise MesonException('Could not detect ninja command')
|
||
10 years ago
|
elem = NinjaBuildElement('clean', 'CUSTOM_COMMAND', 'PHONY')
|
||
11 years ago
|
elem.add_item('COMMAND', [ninja_command, '-t', 'clean'])
|
||
|
elem.add_item('description', 'Cleaning')
|
||
9 years ago
|
if self.environment.coredata.get_builtin_option('coverage'):
|
||
11 years ago
|
self.generate_gcov_clean(outfile)
|
||
|
elem.add_dep('clean-gcda')
|
||
|
elem.add_dep('clean-gcno')
|
||
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|
||
11 years ago
|
|
||
9 years ago
|
deps = self.get_regen_filelist()
|
||
11 years ago
|
elem = NinjaBuildElement('build.ninja', 'REGENERATE_BUILD', deps)
|
||
10 years ago
|
elem.add_item('pool', 'console')
|
||
11 years ago
|
elem.write(outfile)
|
||
|
|
||
|
elem = NinjaBuildElement(deps, 'phony', '')
|
||
|
elem.write(outfile)
|
||
9 years ago
|
self.check_outputs(elem)
|