Autodetect runnable commands on unix (where chmod values might be wrong) and Windows (where files with weird suffixes are unrunnable.
This commit is contained in:
parent
dbb72bfd12
commit
77c14525c3
2
build.py
2
build.py
|
@ -710,7 +710,7 @@ class CustomTarget:
|
||||||
if isinstance(c, str):
|
if isinstance(c, str):
|
||||||
final_cmd.append(c)
|
final_cmd.append(c)
|
||||||
elif isinstance(c, dependencies.ExternalProgram):
|
elif isinstance(c, dependencies.ExternalProgram):
|
||||||
final_cmd.append(c.get_command())
|
final_cmd += c.get_command()
|
||||||
elif isinstance(c, BuildTarget) or isinstance(c, CustomTarget):
|
elif isinstance(c, BuildTarget) or isinstance(c, CustomTarget):
|
||||||
self.dependencies.append(c)
|
self.dependencies.append(c)
|
||||||
# GIR scanner will attempt to execute this binary but
|
# GIR scanner will attempt to execute this binary but
|
||||||
|
|
|
@ -25,6 +25,7 @@ import os, stat, glob, subprocess, shutil
|
||||||
from coredata import MesonException
|
from coredata import MesonException
|
||||||
import environment
|
import environment
|
||||||
import mlog
|
import mlog
|
||||||
|
from environment import is_windows
|
||||||
|
|
||||||
class DependencyException(MesonException):
|
class DependencyException(MesonException):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -131,21 +132,32 @@ class ExternalProgram():
|
||||||
def __init__(self, name, fullpath=None, silent=False, search_dir=None):
|
def __init__(self, name, fullpath=None, silent=False, search_dir=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
if fullpath is not None:
|
if fullpath is not None:
|
||||||
self.fullpath = fullpath
|
self.fullpath = [fullpath]
|
||||||
else:
|
else:
|
||||||
self.fullpath = shutil.which(name)
|
self.fullpath = [shutil.which(name)]
|
||||||
if self.fullpath is None and search_dir is not None:
|
if self.fullpath[0] is None and search_dir is not None:
|
||||||
trial = os.path.join(search_dir, name)
|
trial = os.path.join(search_dir, name)
|
||||||
if os.access(trial, os.X_OK):
|
if os.access(trial, os.X_OK):
|
||||||
self.fullpath = trial
|
self.fullpath = [trial]
|
||||||
|
# Now getting desperate. Maybe it is a script file that is a) not chmodded
|
||||||
|
# executable or b) we are on windows so they can't be directly executed.
|
||||||
|
try:
|
||||||
|
first_line = open(trial).readline().strip()
|
||||||
|
if first_line.startswith('#!'):
|
||||||
|
commands = first_line[2:].split('#')[0].strip().split()
|
||||||
|
if environment.is_windows():
|
||||||
|
commands[0] = commands[0].split('/')[-1] # Windows does not have /usr/bin.
|
||||||
|
self.fullpath = commands + [trial]
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
if not silent:
|
if not silent:
|
||||||
if self.found():
|
if self.found():
|
||||||
mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'), '(%s)' % self.fullpath)
|
mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'), '(%s)' % ' '.join(self.fullpath))
|
||||||
else:
|
else:
|
||||||
mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))
|
mlog.log('Program', mlog.bold(name), 'found:', mlog.red('NO'))
|
||||||
|
|
||||||
def found(self):
|
def found(self):
|
||||||
return self.fullpath is not None
|
return self.fullpath[0] is not None
|
||||||
|
|
||||||
def get_command(self):
|
def get_command(self):
|
||||||
return self.fullpath
|
return self.fullpath
|
||||||
|
@ -445,7 +457,7 @@ class Qt5Dependency(Dependency):
|
||||||
# Moc and rcc return a non-zero result when doing so.
|
# Moc and rcc return a non-zero result when doing so.
|
||||||
# What kind of an idiot thought that was a good idea?
|
# What kind of an idiot thought that was a good idea?
|
||||||
if self.moc.found():
|
if self.moc.found():
|
||||||
mp = subprocess.Popen([self.moc.get_command(), '-v'],
|
mp = subprocess.Popen(self.moc.get_command() + ['-v'],
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
(stdout, stderr) = mp.communicate()
|
(stdout, stderr) = mp.communicate()
|
||||||
stdout = stdout.decode().strip()
|
stdout = stdout.decode().strip()
|
||||||
|
@ -458,13 +470,13 @@ class Qt5Dependency(Dependency):
|
||||||
raise DependencyException('Moc preprocessor is not for Qt 5. Output:\n%s\n%s' %
|
raise DependencyException('Moc preprocessor is not for Qt 5. Output:\n%s\n%s' %
|
||||||
(stdout, stderr))
|
(stdout, stderr))
|
||||||
if not qt5toolinfo_printed:
|
if not qt5toolinfo_printed:
|
||||||
mlog.log(' moc:', mlog.green('YES'), '(%s %s)' % \
|
mlog.log(' moc:', mlog.green('YES'), '(%s, %s)' % \
|
||||||
(self.moc.fullpath, moc_ver.split()[-1]))
|
(' '.join(self.moc.fullpath), moc_ver.split()[-1]))
|
||||||
else:
|
else:
|
||||||
if not qt5toolinfo_printed:
|
if not qt5toolinfo_printed:
|
||||||
mlog.log(' moc:', mlog.red('NO'))
|
mlog.log(' moc:', mlog.red('NO'))
|
||||||
if self.uic.found():
|
if self.uic.found():
|
||||||
up = subprocess.Popen([self.uic.get_command(), '-v'],
|
up = subprocess.Popen(self.uic.get_command() + ['-v'],
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
(stdout, stderr) = up.communicate()
|
(stdout, stderr) = up.communicate()
|
||||||
stdout = stdout.decode().strip()
|
stdout = stdout.decode().strip()
|
||||||
|
@ -477,13 +489,13 @@ class Qt5Dependency(Dependency):
|
||||||
raise DependencyException('Uic compiler is not for Qt 5. Output:\n%s\n%s' %
|
raise DependencyException('Uic compiler is not for Qt 5. Output:\n%s\n%s' %
|
||||||
(stdout, stderr))
|
(stdout, stderr))
|
||||||
if not qt5toolinfo_printed:
|
if not qt5toolinfo_printed:
|
||||||
mlog.log(' uic:', mlog.green('YES'), '(%s %s)' % \
|
mlog.log(' uic:', mlog.green('YES'), '(%s, %s)' % \
|
||||||
(self.uic.fullpath, uic_ver.split()[-1]))
|
(' '.join(self.uic.fullpath), uic_ver.split()[-1]))
|
||||||
else:
|
else:
|
||||||
if not qt5toolinfo_printed:
|
if not qt5toolinfo_printed:
|
||||||
mlog.log(' uic:', mlog.red('NO'))
|
mlog.log(' uic:', mlog.red('NO'))
|
||||||
if self.rcc.found():
|
if self.rcc.found():
|
||||||
rp = subprocess.Popen([self.rcc.get_command(), '-v'],
|
rp = subprocess.Popen(self.rcc.get_command() + ['-v'],
|
||||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
(stdout, stderr) = rp.communicate()
|
(stdout, stderr) = rp.communicate()
|
||||||
stdout = stdout.decode().strip()
|
stdout = stdout.decode().strip()
|
||||||
|
@ -496,8 +508,8 @@ class Qt5Dependency(Dependency):
|
||||||
raise DependencyException('Rcc compiler is not for Qt 5. Output:\n%s\n%s' %
|
raise DependencyException('Rcc compiler is not for Qt 5. Output:\n%s\n%s' %
|
||||||
(stdout, stderr))
|
(stdout, stderr))
|
||||||
if not qt5toolinfo_printed:
|
if not qt5toolinfo_printed:
|
||||||
mlog.log(' rcc:', mlog.green('YES'), '(%s %s)'\
|
mlog.log(' rcc:', mlog.green('YES'), '(%s, %s)'\
|
||||||
% (self.rcc.fullpath, rcc_ver.split()[-1]))
|
% (' '.join(self.rcc.fullpath), rcc_ver.split()[-1]))
|
||||||
else:
|
else:
|
||||||
if not qt5toolinfo_printed:
|
if not qt5toolinfo_printed:
|
||||||
mlog.log(' rcc:', mlog.red('NO'))
|
mlog.log(' rcc:', mlog.red('NO'))
|
||||||
|
@ -534,16 +546,16 @@ class Qt5Dependency(Dependency):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def get_generate_rules(self):
|
def get_generate_rules(self):
|
||||||
moc_rule = CustomRule([self.moc.get_command(), '$mocargs', '@INFILE@', '-o', '@OUTFILE@'],
|
moc_rule = CustomRule(self.moc.get_command() + ['$mocargs', '@INFILE@', '-o', '@OUTFILE@'],
|
||||||
'moc_@BASENAME@.cpp', 'moc_headers', 'moc_hdr_compile',
|
'moc_@BASENAME@.cpp', 'moc_headers', 'moc_hdr_compile',
|
||||||
'Compiling header @INFILE@ with the moc preprocessor')
|
'Compiling header @INFILE@ with the moc preprocessor')
|
||||||
mocsrc_rule = CustomRule([self.moc.get_command(), '$mocargs', '@INFILE@', '-o', '@OUTFILE@'],
|
mocsrc_rule = CustomRule(self.moc.get_command() + ['$mocargs', '@INFILE@', '-o', '@OUTFILE@'],
|
||||||
'@BASENAME@.moc', 'moc_sources', 'moc_src_compile',
|
'@BASENAME@.moc', 'moc_sources', 'moc_src_compile',
|
||||||
'Compiling source @INFILE@ with the moc preprocessor')
|
'Compiling source @INFILE@ with the moc preprocessor')
|
||||||
ui_rule = CustomRule([self.uic.get_command(), '@INFILE@', '-o', '@OUTFILE@'],
|
ui_rule = CustomRule(self.uic.get_command() + ['@INFILE@', '-o', '@OUTFILE@'],
|
||||||
'ui_@BASENAME@.h', 'ui_files', 'ui_compile',
|
'ui_@BASENAME@.h', 'ui_files', 'ui_compile',
|
||||||
'Compiling @INFILE@ with the ui compiler')
|
'Compiling @INFILE@ with the ui compiler')
|
||||||
rrc_rule = CustomRule([self.rcc.get_command(), '@INFILE@', '-o', '@OUTFILE@',
|
rrc_rule = CustomRule(self.rcc.get_command() + ['@INFILE@', '-o', '@OUTFILE@',
|
||||||
'${rcc_args}'], '@BASENAME@.cpp','qresources',
|
'${rcc_args}'], '@BASENAME@.cpp','qresources',
|
||||||
'rc_compile', 'Compiling @INFILE@ with the rrc compiler')
|
'rc_compile', 'Compiling @INFILE@ with the rrc compiler')
|
||||||
return [moc_rule, mocsrc_rule, ui_rule, rrc_rule]
|
return [moc_rule, mocsrc_rule, ui_rule, rrc_rule]
|
||||||
|
|
|
@ -811,7 +811,9 @@ class Interpreter():
|
||||||
for i in cargs:
|
for i in cargs:
|
||||||
if not isinstance(i, str):
|
if not isinstance(i, str):
|
||||||
raise InterpreterException('Run_command arguments must be strings.')
|
raise InterpreterException('Run_command arguments must be strings.')
|
||||||
args = [cmd] + cargs
|
if not isinstance(cmd, list):
|
||||||
|
cmd = [cmd]
|
||||||
|
args = cmd + cargs
|
||||||
in_builddir = kwargs.get('in_builddir', False)
|
in_builddir = kwargs.get('in_builddir', False)
|
||||||
if not isinstance(in_builddir, bool):
|
if not isinstance(in_builddir, bool):
|
||||||
raise InterpreterException('in_builddir must be boolean.')
|
raise InterpreterException('in_builddir must be boolean.')
|
||||||
|
|
|
@ -200,8 +200,6 @@ class NinjaBackend(backends.Backend):
|
||||||
if isinstance(gensource, build.CustomTarget):
|
if isinstance(gensource, build.CustomTarget):
|
||||||
for src in gensource.output:
|
for src in gensource.output:
|
||||||
src = os.path.join(gensource.subdir, src)
|
src = os.path.join(gensource.subdir, src)
|
||||||
if self.environment.is_header(src):
|
|
||||||
header_deps.append(RawFilename(src))
|
|
||||||
if self.environment.is_source(src) and not self.environment.is_header(src):
|
if self.environment.is_source(src) and not self.environment.is_header(src):
|
||||||
if is_unity:
|
if is_unity:
|
||||||
unity_deps.append(os.path.join(self.environment.get_build_dir(), RawFilename(src)))
|
unity_deps.append(os.path.join(self.environment.get_build_dir(), RawFilename(src)))
|
||||||
|
@ -209,7 +207,10 @@ class NinjaBackend(backends.Backend):
|
||||||
obj_list.append(self.generate_single_compile(target, outfile, RawFilename(src), True,
|
obj_list.append(self.generate_single_compile(target, outfile, RawFilename(src), True,
|
||||||
header_deps))
|
header_deps))
|
||||||
else:
|
else:
|
||||||
pass # perhaps print warning about the unknown file?
|
# 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))
|
||||||
break # just to cut down on indentation size
|
break # just to cut down on indentation size
|
||||||
for src in gensource.get_outfilelist():
|
for src in gensource.get_outfilelist():
|
||||||
if self.environment.is_object(src):
|
if self.environment.is_object(src):
|
||||||
|
@ -275,7 +276,7 @@ class NinjaBackend(backends.Backend):
|
||||||
ofilenames = [os.path.join(target.subdir, i) for i in target.output]
|
ofilenames = [os.path.join(target.subdir, i) for i in target.output]
|
||||||
# FIXME, should not grab element at zero but rather expand all.
|
# FIXME, should not grab element at zero but rather expand all.
|
||||||
deps = [os.path.join(i.get_subdir(), self.hackety_hack(i.get_filename())) for i in target.get_dependencies()]
|
deps = [os.path.join(i.get_subdir(), self.hackety_hack(i.get_filename())) for i in target.get_dependencies()]
|
||||||
srcs = [os.path.join(self.build_to_src, target.subdir, i) for i in target.sources]
|
srcs = [os.path.join(self.build_to_src, target.subdir, i) for i in target.sources]
|
||||||
deps += srcs
|
deps += srcs
|
||||||
elem = NinjaBuildElement(ofilenames, 'CUSTOM_COMMAND', deps)
|
elem = NinjaBuildElement(ofilenames, 'CUSTOM_COMMAND', deps)
|
||||||
cmd = []
|
cmd = []
|
||||||
|
@ -976,9 +977,9 @@ rule FORTRAN_DEP_HACK
|
||||||
infilelist = genlist.get_infilelist()
|
infilelist = genlist.get_infilelist()
|
||||||
outfilelist = genlist.get_outfilelist()
|
outfilelist = genlist.get_outfilelist()
|
||||||
if isinstance(exe, build.BuildTarget):
|
if isinstance(exe, build.BuildTarget):
|
||||||
exe_file = os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))
|
exe_arr = [os.path.join(self.environment.get_build_dir(), self.get_target_filename(exe))]
|
||||||
else:
|
else:
|
||||||
exe_file = exe.get_command()
|
exe_arr = exe.get_command()
|
||||||
base_args = generator.get_arglist()
|
base_args = generator.get_arglist()
|
||||||
for i in range(len(infilelist)):
|
for i in range(len(infilelist)):
|
||||||
if len(generator.outputs) == 1:
|
if len(generator.outputs) == 1:
|
||||||
|
@ -994,7 +995,7 @@ rule FORTRAN_DEP_HACK
|
||||||
args = self.replace_outputs(args, self.get_target_private_dir(target), outfilelist)
|
args = self.replace_outputs(args, self.get_target_private_dir(target), outfilelist)
|
||||||
args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", self.get_target_private_dir(target))
|
args = [x.replace("@SOURCE_DIR@", self.environment.get_source_dir()).replace("@BUILD_DIR@", self.get_target_private_dir(target))
|
||||||
for x in args]
|
for x in args]
|
||||||
cmdlist = [exe_file] + args
|
cmdlist = exe_arr + args
|
||||||
elem = NinjaBuildElement(outfiles, 'CUSTOM_COMMAND', infilename)
|
elem = NinjaBuildElement(outfiles, 'CUSTOM_COMMAND', infilename)
|
||||||
elem.add_item('DESC', 'Generating $out')
|
elem.add_item('DESC', 'Generating $out')
|
||||||
if isinstance(exe, build.BuildTarget):
|
if isinstance(exe, build.BuildTarget):
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
0
|
|
@ -0,0 +1,10 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
# NOTE: this file does not have the executable bit set. This tests that
|
||||||
|
# Meson can automatically parse shebang lines.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
template = '#define RET_VAL %s\n'
|
||||||
|
output = template % (open(sys.argv[1]).readline().strip())
|
||||||
|
open(sys.argv[2], 'w').write(output)
|
|
@ -0,0 +1,12 @@
|
||||||
|
project('custom header generator', 'c')
|
||||||
|
|
||||||
|
gen = find_program('makeheader.py')
|
||||||
|
|
||||||
|
generated_h = custom_target('makeheader.py',
|
||||||
|
output : 'myheader.lh', # Suffix not .h to ensure this works with custom suffixes, too.
|
||||||
|
input : 'input.def',
|
||||||
|
command : [gen, '@INPUT0@', '@OUTPUT0@'])
|
||||||
|
|
||||||
|
prog = executable('prog', 'prog.c', generated_h,
|
||||||
|
include_directories : include_directories('.'))
|
||||||
|
test('gentest', prog)
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include"myheader.lh"
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
return RET_VAL;
|
||||||
|
}
|
Loading…
Reference in New Issue