Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend native files to store install path information #4743

Merged
merged 6 commits into from
Feb 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion docs/markdown/Cross-compilation.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ binaries are not actually compatible. In such cases you may use the
needs_exe_wrapper = true
```

The last bit is the definition of host and target machines. Every
The next bit is the definition of host and target machines. Every
cross build definition must have one or both of them. If it had
neither, the build would not be a cross build but a native build. You
do not need to define the build machine, as all necessary information
Expand Down Expand Up @@ -186,6 +186,20 @@ If you do not define your host machine, it is assumed to be the build
machine. Similarly if you do not specify target machine, it is assumed
to be the host machine.

Additionally, you can define the paths that you want to install to in your
cross file. This may be especially useful when cross compiling an entire
operating system, or for operating systems to use internally for consistency.

```ini
[paths]
prefix = '/my/prefix'
libdir = 'lib/i386-linux-gnu'
bindir = 'bin'
```

This will be overwritten by any options passed on the command line.


## Starting a cross build


Expand Down
17 changes: 17 additions & 0 deletions docs/markdown/Native-environments.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ rust = '/usr/local/bin/rust'
llvm-config = '/usr/local/llvm-svn/bin/llvm-config'
```

### Paths and Directories

As of 0.50.0 paths and directories such as libdir can be defined in the native
file in a paths section

```ini
[paths]
libdir = 'mylibdir'
prefix = '/my prefix'
```

These values will only be loaded when not cross compiling. Any arguments on the
command line will override any options in the native file. For example, passing
`--libdir=otherlibdir` would result in a prefix of `/my prefix` and a libdir of
`otherlibdir`.


## Loading multiple native files

Unlike cross file, native files allow layering. More than one native file can be
Expand Down
4 changes: 4 additions & 0 deletions docs/markdown/snippets/native-file-paths.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## Native and Cross File Paths and Directories

A new `[paths]` section has been added to native and cross files. This
can be used to set paths such a prefix and libdir in a persistent way.
2 changes: 1 addition & 1 deletion mesonbuild/ast/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def func_project(self, node, args, kwargs):
self.project_default_options = mesonlib.stringlistify(def_opts)
self.project_default_options = cdata.create_options_dict(self.project_default_options)
self.default_options.update(self.project_default_options)
self.coredata.set_default_options(self.default_options, self.subproject, self.environment.cmd_line_options)
self.coredata.set_default_options(self.default_options, self.subproject, self.environment)

if not self.is_subproject() and 'subproject_dir' in kwargs:
spdirname = kwargs['subproject_dir']
Expand Down
12 changes: 9 additions & 3 deletions mesonbuild/coredata.py
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,13 @@ def set_options(self, options, subproject='', warn_unknown=True):
sub = 'In subproject {}: '.format(subproject) if subproject else ''
mlog.warning('{}Unknown options: "{}"'.format(sub, unknown_options))

def set_default_options(self, default_options, subproject, cmd_line_options):
def set_default_options(self, default_options, subproject, env):
# Set defaults first from conf files (cross or native), then
# override them as nec as necessary.
for k, v in env.paths.host:
if v is not None:
env.cmd_line_options.setdefault(k, v)

# Set default options as if they were passed to the command line.
# Subprojects can only define default for user options.
from . import optinterpreter
Expand All @@ -534,15 +540,15 @@ def set_default_options(self, default_options, subproject, cmd_line_options):
if optinterpreter.is_invalid_name(k):
continue
k = subproject + ':' + k
cmd_line_options.setdefault(k, v)
env.cmd_line_options.setdefault(k, v)

# Create a subset of cmd_line_options, keeping only options for this
# subproject. Also take builtin options if it's the main project.
# Language and backend specific options will be set later when adding
# languages and setting the backend (builtin options must be set first
# to know which backend we'll use).
options = {}
for k, v in cmd_line_options.items():
for k, v in env.cmd_line_options.items():
if subproject:
if not k.startswith(subproject + ':'):
continue
Expand Down
73 changes: 61 additions & 12 deletions mesonbuild/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import configparser, os, platform, re, sys, shlex, shutil, subprocess, typing
import configparser, os, platform, re, sys, shlex, shutil, subprocess
import typing

from . import coredata
from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker
Expand Down Expand Up @@ -371,17 +372,24 @@ def __init__(self, source_dir, build_dir, options):
# Similar to coredata.compilers and build.compilers, but lower level in
# that there is no meta data, only names/paths.
self.binaries = PerMachineDefaultable()

# Just uses hard-coded defaults and environment variables. Might be
# overwritten by a native file.
self.binaries.build = BinaryTable({})

# Misc other properties about each machine.
self.properties = PerMachine(Properties(), Properties(), Properties())

# Store paths for native and cross build files. There is no target
# machine information here because nothing is installed for the target
# architecture, just the build and host architectures
self.paths = PerMachineDefaultable()

if self.coredata.config_files is not None:
config = MesonConfigFile.from_config_parser(
coredata.load_configs(self.coredata.config_files))
self.binaries.build = BinaryTable(config.get('binaries', {}))
self.paths.build = Directories(**config.get('paths', {}))

if self.coredata.cross_file is not None:
config = MesonConfigFile.parse_datafile(self.coredata.cross_file)
Expand All @@ -391,9 +399,11 @@ def __init__(self, source_dir, build_dir, options):
self.machines.host = MachineInfo.from_literal(config['host_machine'])
if 'target_machine' in config:
self.machines.target = MachineInfo.from_literal(config['target_machine'])
self.paths.host = Directories(**config.get('paths', {}))

self.machines.default_missing()
self.binaries.default_missing()
dcbaker marked this conversation as resolved.
Show resolved Hide resolved
self.paths.default_missing()

exe_wrapper = self.binaries.host.lookup_entry('exe_wrapper')
if exe_wrapper is not None:
Expand Down Expand Up @@ -1172,46 +1182,46 @@ def get_build_dir(self):
def get_exe_suffix(self):
return self.exe_suffix

def get_import_lib_dir(self):
def get_import_lib_dir(self) -> str:
"Install dir for the import library (library used for linking)"
return self.get_libdir()

def get_shared_module_dir(self):
def get_shared_module_dir(self) -> str:
"Install dir for shared modules that are loaded at runtime"
return self.get_libdir()

def get_shared_lib_dir(self):
def get_shared_lib_dir(self) -> str:
"Install dir for the shared library"
if self.win_libdir_layout:
return self.get_bindir()
return self.get_libdir()

def get_static_lib_dir(self):
def get_static_lib_dir(self) -> str:
"Install dir for the static library"
return self.get_libdir()

def get_object_suffix(self):
return self.object_suffix

def get_prefix(self):
def get_prefix(self) -> str:
return self.coredata.get_builtin_option('prefix')

def get_libdir(self):
def get_libdir(self) -> str:
return self.coredata.get_builtin_option('libdir')

def get_libexecdir(self):
def get_libexecdir(self) -> str:
return self.coredata.get_builtin_option('libexecdir')

def get_bindir(self):
def get_bindir(self) -> str:
return self.coredata.get_builtin_option('bindir')

def get_includedir(self):
def get_includedir(self) -> str:
return self.coredata.get_builtin_option('includedir')

def get_mandir(self):
def get_mandir(self) -> str:
return self.coredata.get_builtin_option('mandir')

def get_datadir(self):
def get_datadir(self) -> str:
return self.coredata.get_builtin_option('datadir')

def get_compiler_system_dirs(self):
Expand Down Expand Up @@ -1581,3 +1591,42 @@ def lookup_entry(self, name):
if command is not None:
command = shlex.split(command)
return command

class Directories:

"""Data class that holds information about directories for native and cross
builds.
"""

def __init__(self, bindir: typing.Optional[str] = None, datadir: typing.Optional[str] = None,
includedir: typing.Optional[str] = None, infodir: typing.Optional[str] = None,
libdir: typing.Optional[str] = None, libexecdir: typing.Optional[str] = None,
localedir: typing.Optional[str] = None, localstatedir: typing.Optional[str] = None,
mandir: typing.Optional[str] = None, prefix: typing.Optional[str] = None,
sbindir: typing.Optional[str] = None, sharedstatedir: typing.Optional[str] = None,
sysconfdir: typing.Optional[str] = None):
self.bindir = bindir
self.datadir = datadir
self.includedir = includedir
self.infodir = infodir
self.libdir = libdir
self.libexecdir = libexecdir
self.localedir = localedir
self.localstatedir = localstatedir
self.mandir = mandir
self.prefix = prefix
self.sbindir = sbindir
self.sharedstatedir = sharedstatedir
self.sysconfdir = sysconfdir

def __contains__(self, key: str) -> str:
return hasattr(self, key)

def __getitem__(self, key: str) -> str:
return getattr(self, key)

def __setitem__(self, key: str, value: typing.Optional[str]) -> None:
setattr(self, key, value)

def __iter__(self) -> typing.Iterator[typing.Tuple[str, str]]:
return iter(self.__dict__.items())
4 changes: 1 addition & 3 deletions mesonbuild/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2458,8 +2458,6 @@ def do_subproject(self, dirname, kwargs):
return self.subprojects[dirname]

def get_option_internal(self, optname):
# Some base options are not defined in some environments, return the
# default value from compilers.base_options in that case.
for d in chain(
[self.coredata.base_options, compilers.base_options, self.coredata.builtins],
self.coredata.get_all_compiler_options()):
Expand Down Expand Up @@ -2576,7 +2574,7 @@ def func_project(self, node, args, kwargs):
default_options.update(self.default_project_options)
else:
default_options = {}
self.coredata.set_default_options(default_options, self.subproject, self.environment.cmd_line_options)
self.coredata.set_default_options(default_options, self.subproject, self.environment)
self.set_backend()

if not self.is_subproject():
Expand Down
3 changes: 1 addition & 2 deletions mesonbuild/mconf.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,7 @@ def print_options(self, title, options):
if not options:
print(' No {}\n'.format(title.lower()))
arr = []
for k in sorted(options):
o = options[k]
for k, o in sorted(options.items()):
d = o.description
v = o.printable_value()
c = o.choices
Expand Down
10 changes: 9 additions & 1 deletion mesonbuild/mesonlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,15 @@ def __lt__(self, other):
return self.value < other.value
return NotImplemented

MachineChoice = OrderedEnum('MachineChoice', ['BUILD', 'HOST', 'TARGET'])
class MachineChoice(OrderedEnum):

"""Enum class representing one of the three possible values for binaries,
the build, host, and target machines.
"""

BUILD = 0
HOST = 1
TARGET = 2

class PerMachine:
def __init__(self, build, host, target):
Expand Down
6 changes: 6 additions & 0 deletions run_project_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,12 @@ def _run_test(testdir, test_build_dir, install_dir, extra_args, compiler, backen
if pass_libdir_to_test(testdir):
gen_args += ['--libdir', 'lib']
gen_args += [testdir, test_build_dir] + flags + test_args + extra_args
nativefile = os.path.join(testdir, 'nativefile.ini')
if os.path.exists(nativefile):
gen_args.extend(['--native-file', nativefile])
crossfile = os.path.join(testdir, 'crossfile.ini')
dcbaker marked this conversation as resolved.
Show resolved Hide resolved
if os.path.exists(crossfile):
gen_args.extend(['--cross-file', crossfile])
(returncode, stdo, stde) = run_configure(gen_args)
try:
logfile = Path(test_build_dir, 'meson-logs', 'meson-log.txt')
Expand Down
58 changes: 57 additions & 1 deletion run_unittests.py
Original file line number Diff line number Diff line change
Expand Up @@ -5438,6 +5438,62 @@ def test_swift_compiler(self):
compiler = env.detect_swift_compiler()
self.assertEqual(compiler.version, '1.2345')

def test_native_file_dirs(self):
testcase = os.path.join(self.unit_test_dir, '54 native file override')
self.init(testcase, default_args=False,
extra_args=['--native-file', os.path.join(testcase, 'nativefile')])

def test_native_file_dirs_overriden(self):
testcase = os.path.join(self.unit_test_dir, '54 native file override')
self.init(testcase, default_args=False,
extra_args=['--native-file', os.path.join(testcase, 'nativefile'),
'-Ddef_libdir=liblib', '-Dlibdir=liblib'])


class CrossFileTests(BasePlatformTests):

"""Tests for cross file functioality not directly related to
cross compiling.

This is mainly aimed to testing overrides from cross files.
"""

def test_cross_file_dirs(self):
testcase = os.path.join(self.unit_test_dir, '54 native file override')
self.init(testcase, default_args=False,
extra_args=['--native-file', os.path.join(testcase, 'nativefile'),
'--cross-file', os.path.join(testcase, 'crossfile'),
'-Ddef_bindir=binbar',
'-Ddef_datadir=databar',
'-Ddef_includedir=includebar',
'-Ddef_infodir=infobar',
'-Ddef_libdir=libbar',
'-Ddef_libexecdir=libexecbar',
'-Ddef_localedir=localebar',
'-Ddef_localstatedir=localstatebar',
'-Ddef_mandir=manbar',
'-Ddef_sbindir=sbinbar',
'-Ddef_sharedstatedir=sharedstatebar',
'-Ddef_sysconfdir=sysconfbar'])

def test_cross_file_dirs_overriden(self):
testcase = os.path.join(self.unit_test_dir, '54 native file override')
self.init(testcase, default_args=False,
extra_args=['--native-file', os.path.join(testcase, 'nativefile'),
'--cross-file', os.path.join(testcase, 'crossfile'),
'-Ddef_libdir=liblib', '-Dlibdir=liblib',
'-Ddef_bindir=binbar',
'-Ddef_datadir=databar',
'-Ddef_includedir=includebar',
'-Ddef_infodir=infobar',
'-Ddef_libexecdir=libexecbar',
'-Ddef_localedir=localebar',
'-Ddef_localstatedir=localstatebar',
'-Ddef_mandir=manbar',
'-Ddef_sbindir=sbinbar',
'-Ddef_sharedstatedir=sharedstatebar',
'-Ddef_sysconfdir=sysconfbar'])


def unset_envs():
# For unit tests we must fully control all command lines
Expand All @@ -5457,7 +5513,7 @@ def should_run_cross_mingw_tests():
def main():
unset_envs()
cases = ['InternalTests', 'DataTests', 'AllPlatformTests', 'FailureTests',
'PythonTests', 'NativeFileTests', 'RewriterTests']
'PythonTests', 'NativeFileTests', 'RewriterTests', 'CrossFileTests']
if not is_windows():
cases += ['LinuxlikeTests']
if should_run_cross_arm_tests():
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
usr/custom_bindir/main?exe
?msvc:usr/custom_bindir/main.pdb
5 changes: 5 additions & 0 deletions test cases/common/212 native file path override/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#include <iostream>

int main() {
std::cout << "Hello world!" << std::endl;
}
7 changes: 7 additions & 0 deletions test cases/common/212 native file path override/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
project('native file install dir override', 'cpp')

if meson.is_cross_build()
error('MESON_SKIP_TEST cannot test native build rules in cross build')
endif

executable('main', 'main.cpp', install : true)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[paths]
bindir = 'custom_bindir'
Loading