Merge pull request #8264 from xclaesse/ep-misc

external_project: misc improvements
pull/8273/head
Jussi Pakkanen 4 years ago committed by GitHub
commit c67e0a8a67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      docs/markdown/External-Project-module.md
  2. 11
      docs/markdown/snippets/external_project.md
  3. 8
      mesonbuild/mesonlib/universal.py
  4. 33
      mesonbuild/modules/unstable_external_project.py
  5. 25
      mesonbuild/scripts/externalproject.py

@ -54,8 +54,10 @@ build system. Usually in a `meson.build` file placed in the top directory of a
subproject, but could be also in any subdir.
Its first positional argument is the name of the configure script to be
executed (e.g. `configure` or `autogen.sh`), that file must be in the current
directory and executable.
executed (e.g. `configure`), that file must be in the current directory and
executable. Note that if a bootstrap script is required (e.g. `autogen.sh` when
building from git instead of tarball), it can be done using `run_command()`
before calling `add_project()` method.
Keyword arguments:
- `configure_options`: An array of strings to be passed as arguments to the
@ -63,7 +65,11 @@ Keyword arguments:
them to the configure script: `@PREFIX@`, `@LIBDIR@` and `@INCLUDEDIR@`.
Note that `libdir` and `includedir` paths are relative to `prefix` in Meson
but some configure scripts requires absolute path, in that case they can be
passed as `'--libdir=@PREFIX@/@LIBDIR@'`.
passed as `'--libdir=@PREFIX@/@LIBDIR@'`. *Since 0.57.0* default arguments are
added in case some tags are not found in `configure_options`:
`'--prefix=@PREFIX@'`, `'--libdir=@PREFIX@/@LIBDIR@'`, and
`'--includedir=@PREFIX@/@INCLUDEDIR@'`. It was previously considered a fatal
error to not specify them.
- `cross_configure_options`: Extra options appended to `configure_options` only
when cross compiling. special tag `@HOST@` will be replaced by
`'{}-{}-{}'.format(host_machine.cpu_family(), build_machine.system(), host_machine.system()`.

@ -0,0 +1,11 @@
## `unstable_external_project` improvements
- Default arguments are added to `add_project()` in case some tags are not found
in `configure_options`: `'--prefix=@PREFIX@'`, `'--libdir=@PREFIX@/@LIBDIR@'`,
and `'--includedir=@PREFIX@/@INCLUDEDIR@'`. It was previously considered a fatal
error to not specify them.
- When `verbose` keyword argument is not specified, or is false, command outputs
are written on file in `<builddir>/meson-logs/`.
- `LD` environment variable is not passed any more when running the configure
script. It caused issues because Meson uses CC as linker wrapper but autotools
expects to real linker (e.g. `/usr/bin/ld`).

@ -1305,8 +1305,8 @@ def partition(pred: T.Callable[[_T], object], iterable: T.Iterator[_T]) -> T.Tup
def Popen_safe(args: T.List[str], write: T.Optional[str] = None,
stdout: T.Union[T.BinaryIO, int] = subprocess.PIPE,
stderr: T.Union[T.BinaryIO, int] = subprocess.PIPE,
stdout: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.PIPE,
stderr: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.PIPE,
**kwargs: T.Any) -> T.Tuple[subprocess.Popen, str, str]:
import locale
encoding = locale.getpreferredencoding()
@ -1328,8 +1328,8 @@ def Popen_safe(args: T.List[str], write: T.Optional[str] = None,
def Popen_safe_legacy(args: T.List[str], write: T.Optional[str] = None,
stdout: T.Union[T.BinaryIO, int] = subprocess.PIPE,
stderr: T.Union[T.BinaryIO, int] = subprocess.PIPE,
stdout: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.PIPE,
stderr: T.Union[T.TextIO, T.BinaryIO, int] = subprocess.PIPE,
**kwargs: T.Any) -> T.Tuple[subprocess.Popen, str, str]:
p = subprocess.Popen(args, universal_newlines=False, close_fds=False,
stdout=stdout, stderr=stderr, **kwargs)

@ -90,11 +90,11 @@ class ExternalProject(InterpreterObject):
configure_prog = self.interpreter.find_program_impl(configure_path.as_posix())
configure_cmd = configure_prog.get_command()
d = {'PREFIX': self.prefix.as_posix(),
'LIBDIR': self.libdir.as_posix(),
'INCLUDEDIR': self.includedir.as_posix(),
}
self._validate_configure_options(d.keys())
d = [('PREFIX', '--prefix=@PREFIX@', self.prefix.as_posix()),
('LIBDIR', '--libdir=@PREFIX@/@LIBDIR@', self.libdir.as_posix()),
('INCLUDEDIR', '--includedir=@PREFIX@/@INCLUDEDIR@', self.includedir.as_posix()),
]
self._validate_configure_options(d)
configure_cmd += self._format_options(self.configure_options, d)
@ -102,7 +102,7 @@ class ExternalProject(InterpreterObject):
host = '{}-{}-{}'.format(self.host_machine.cpu_family,
self.build_machine.system,
self.host_machine.system)
d = {'HOST': host}
d = [('HOST', None, host)]
configure_cmd += self._format_options(self.cross_configure_options, d)
# Set common env variables like CFLAGS, CC, etc.
@ -119,7 +119,10 @@ class ExternalProject(InterpreterObject):
link_exelist = compiler.get_linker_exelist()
link_args = self.env.coredata.get_external_link_args(MachineChoice.HOST, lang)
if link_exelist:
self.run_env['LD'] = self._quote_and_join(link_exelist)
# FIXME: Do not pass linker because Meson uses CC as linker wrapper,
# but autotools often expects the real linker (e.h. GNU ld).
# self.run_env['LD'] = self._quote_and_join(link_exelist)
pass
self.run_env['LDFLAGS'] = self._quote_and_join(link_args)
self.run_env = self.user_env.get_env(self.run_env)
@ -133,23 +136,23 @@ class ExternalProject(InterpreterObject):
def _quote_and_join(self, array: T.List[str]) -> str:
return ' '.join([shlex.quote(i) for i in array])
def _validate_configure_options(self, required_keys: T.List[str]):
def _validate_configure_options(self, variables: T.List[T.Tuple[str, str, str]]):
# Ensure the user at least try to pass basic info to the build system,
# like the prefix, libdir, etc.
for key in required_keys:
for key, default, val in variables:
key_format = '@{}@'.format(key)
for option in self.configure_options:
if key_format in option:
break
else:
m = 'At least one configure option must contain "{}" key'
raise InterpreterException(m.format(key_format))
FeatureNew('Default configure_option', '0.57.0').use(self.subproject)
self.configure_options.append(default)
def _format_options(self, options: T.List[str], variables: T.Dict[str, str]) -> T.List[str]:
def _format_options(self, options: T.List[str], variables: T.List[T.Tuple[str, str, str]]) -> T.List[str]:
out = []
missing = set()
regex = get_variable_regex('meson')
confdata = {k: (v, None) for k, v in variables.items()}
confdata = {k: (v, None) for k, d, v in variables}
for o in options:
arg, missing_vars = do_replacement(regex, o, 'meson', confdata)
missing.update(missing_vars)
@ -162,12 +165,13 @@ class ExternalProject(InterpreterObject):
def _run(self, step: str, command: T.List[str]):
mlog.log('External project {}:'.format(self.name), mlog.bold(step))
m = 'Running command: ' + str(command)
m = 'Running command ' + str(command) + ' in directory ' + str(self.build_dir) + '\n'
log_filename = Path(mlog.log_dir, '{}-{}.log'.format(self.name, step))
output = None
if not self.verbose:
output = open(log_filename, 'w')
output.write(m + '\n')
output.flush()
else:
mlog.log(m)
p, o, e = Popen_safe(command, cwd=str(self.build_dir), env=self.run_env,
@ -186,6 +190,7 @@ class ExternalProject(InterpreterObject):
'--srcdir', self.src_dir.as_posix(),
'--builddir', self.build_dir.as_posix(),
'--installdir', self.install_dir.as_posix(),
'--logdir', mlog.log_dir,
'--make', self.make,
]
if self.verbose:

@ -27,6 +27,7 @@ class ExternalProject:
self.src_dir = options.srcdir
self.build_dir = options.builddir
self.install_dir = options.installdir
self.log_dir = options.logdir
self.verbose = options.verbose
self.stampfile = options.stampfile
self.depfile = options.depfile
@ -55,17 +56,15 @@ class ExternalProject:
def build(self) -> int:
make_cmd = [self.make]
if not self.verbose:
make_cmd.append('--quiet')
if self.gnu_make():
make_cmd.append('-j' + str(multiprocessing.cpu_count()))
rc = self._run(make_cmd)
rc = self._run('build', make_cmd)
if rc != 0:
return rc
install_cmd = make_cmd + ['DESTDIR= ' + self.install_dir, 'install']
rc = self._run(install_cmd)
rc = self._run('install', install_cmd)
if rc != 0:
return rc
@ -74,10 +73,23 @@ class ExternalProject:
return 0
def _run(self, command: T.List[str]) -> int:
output = None if self.verbose else subprocess.DEVNULL
def _run(self, step: str, command: T.List[str]) -> int:
m = 'Running command ' + str(command) + ' in directory ' + str(self.build_dir) + '\n'
log_filename = Path(self.log_dir, '{}-{}.log'.format(self.name, step))
output = None
if not self.verbose:
output = open(log_filename, 'w')
output.write(m + '\n')
output.flush()
else:
print(m)
p, o, e = Popen_safe(command, stderr=subprocess.STDOUT, stdout=output,
cwd=self.build_dir)
if p.returncode != 0:
m = '{} step returned error code {}.'.format(step, p.returncode)
if not self.verbose:
m += '\nSee logs: ' + str(log_filename)
print(m)
return p.returncode
def run(args: T.List[str]) -> int:
@ -86,6 +98,7 @@ def run(args: T.List[str]) -> int:
parser.add_argument('--srcdir')
parser.add_argument('--builddir')
parser.add_argument('--installdir')
parser.add_argument('--logdir')
parser.add_argument('--make')
parser.add_argument('--verbose', action='store_true')
parser.add_argument('stampfile')

Loading…
Cancel
Save