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

[MesonToolchain] Added native mechanism when cross-building #15919

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
24 changes: 11 additions & 13 deletions conan/tools/meson/meson.py
Expand Up @@ -29,24 +29,22 @@ def configure(self, reconfigure=False):
" Removing in Conan 2.x.", warn_tag="deprecated")
source_folder = self._conanfile.source_folder
build_folder = self._conanfile.build_folder
cmd = "meson setup"
generators_folder = self._conanfile.generators_folder
cross = os.path.join(generators_folder, MesonToolchain.cross_filename)
native = os.path.join(generators_folder, MesonToolchain.native_filename)
meson_filenames = []
if os.path.exists(cross):
cmd_param = " --cross-file"
meson_filenames.append(cross)
else:
cmd_param = " --native-file"
meson_filenames.append(native)

is_cross_build = os.path.exists(cross)
machine_files = self._conanfile.conf.get("tools.meson.mesontoolchain:extra_machine_files",
default=[], check_type=list)
if machine_files:
meson_filenames.extend(machine_files)

cmd += "".join([f'{cmd_param} "{meson_option}"' for meson_option in meson_filenames])
cmd = "meson setup "
if is_cross_build:
machine_files.insert(0, cross)
cmd += "".join([f'--cross-file "{file}"' for file in machine_files])
if os.path.exists(native):
if not is_cross_build: # machine files are only appended to the cross or the native one
machine_files.insert(0, native)
cmd += "".join([f'--native-file "{file}"' for file in machine_files])
else: # extra native file for cross-building scenarios
cmd += f' --native-file "{native}"'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm keeping the old behavior.

cmd += ' "{}" "{}"'.format(build_folder, source_folder)
# Issue related: https://github.com/mesonbuild/meson/issues/12880
cmd += ' --prefix=/' # this must be an absolute path, otherwise, meson complains
Expand Down
147 changes: 102 additions & 45 deletions conan/tools/meson/toolchain.py
@@ -1,7 +1,7 @@
import os
import textwrap

from jinja2 import Template
from jinja2 import Template, StrictUndefined

from conan.errors import ConanException
from conan.internal import check_duplicated_generator
Expand All @@ -20,11 +20,10 @@ class MesonToolchain(object):
"""
MesonToolchain generator
"""

native_filename = "conan_meson_native.ini"
cross_filename = "conan_meson_cross.ini"

_meson_file_template = textwrap.dedent("""
_meson_file_template = textwrap.dedent("""\
[properties]
{% for it, value in properties.items() -%}
{{it}} = {{value}}
Expand All @@ -49,33 +48,76 @@ class MesonToolchain(object):
{% endfor %}

[binaries]
{% if c %}c = {{c}}{% endif %}
{% if cpp %}cpp = {{cpp}}{% endif %}
{% if ld %}ld = {{ld}}{% endif %}
{% if c %}
c = {{c}}
{% endif %}
{% if cpp %}
cpp = {{cpp}}
memsharded marked this conversation as resolved.
Show resolved Hide resolved
{% endif %}
{% if ld %}
ld = {{ld}}
{% endif %}
{% if is_apple_system %}
{% if objc %}objc = '{{objc}}'{% endif %}
{% if objcpp %}objcpp = '{{objcpp}}'{% endif %}
{% if objc %}
objc = '{{objc}}'
{% endif %}
{% if objcpp %}
objcpp = '{{objcpp}}'
{% endif %}
{% endif %}
{% if c_ld %}
c_ld = '{{c_ld}}'
{% endif %}
{% if cpp_ld %}
cpp_ld = '{{cpp_ld}}'
{% endif %}
{% if ar %}
ar = '{{ar}}'
{% endif %}
{% if strip %}
strip = '{{strip}}'
{% endif %}
{% if as %}
as = '{{as}}'
{% endif %}
{% if windres %}
windres = '{{windres}}'
{% endif %}
{% if pkgconfig %}
pkgconfig = '{{pkgconfig}}'
{% endif %}
{% if pkgconfig %}
pkg-config = '{{pkgconfig}}'
{% endif %}
{% if c_ld %}c_ld = '{{c_ld}}'{% endif %}
{% if cpp_ld %}cpp_ld = '{{cpp_ld}}'{% endif %}
{% if ar %}ar = '{{ar}}'{% endif %}
{% if strip %}strip = '{{strip}}'{% endif %}
{% if as %}as = '{{as}}'{% endif %}
{% if windres %}windres = '{{windres}}'{% endif %}
{% if pkgconfig %}pkgconfig = '{{pkgconfig}}'{% endif %}
{% if pkgconfig %}pkg-config = '{{pkgconfig}}'{% endif %}

[built-in options]
{% if buildtype %}buildtype = '{{buildtype}}'{% endif %}
{% if debug %}debug = {{debug}}{% endif %}
{% if default_library %}default_library = '{{default_library}}'{% endif %}
{% if b_vscrt %}b_vscrt = '{{b_vscrt}}' {% endif %}
{% if b_ndebug %}b_ndebug = {{b_ndebug}}{% endif %}
{% if b_staticpic %}b_staticpic = {{b_staticpic}}{% endif %}
{% if cpp_std %}cpp_std = '{{cpp_std}}' {% endif %}
{% if backend %}backend = '{{backend}}' {% endif %}
{% if pkg_config_path %}pkg_config_path = '{{pkg_config_path}}'{% endif %}
{% if build_pkg_config_path %}build.pkg_config_path = '{{build_pkg_config_path}}'{% endif %}
{% if buildtype %}
buildtype = '{{buildtype}}'
{% endif %}
{% if default_library %}
default_library = '{{default_library}}'
{% endif %}
{% if b_vscrt %}
b_vscrt = '{{b_vscrt}}'
{% endif %}
{% if b_ndebug %}
b_ndebug = {{b_ndebug}}
{% endif %}
{% if b_staticpic %}
b_staticpic = {{b_staticpic}}
{% endif %}
{% if cpp_std %}
cpp_std = '{{cpp_std}}'
{% endif %}
{% if backend %}
backend = '{{backend}}'
{% endif %}
{% if pkg_config_path %}
pkg_config_path = '{{pkg_config_path}}'
{% endif %}
{% if build_pkg_config_path %}
build.pkg_config_path = '{{build_pkg_config_path}}'
{% endif %}
# C/C++ arguments
c_args = {{c_args}} + preprocessor_definitions
c_link_args = {{c_link_args}}
Expand All @@ -98,16 +140,20 @@ class MesonToolchain(object):
{% endfor %}
""")

def __init__(self, conanfile, backend=None):
def __init__(self, conanfile, backend=None, native=False):
"""
:param conanfile: ``< ConanFile object >`` The current recipe object. Always use ``self``.
:param backend: ``str`` ``backend`` Meson variable value. By default, ``ninja``.
"""
raise_on_universal_arch(conanfile)
self._conanfile = conanfile
self._os = self._conanfile.settings.get_safe("os")
self._native = native
self._is_cross_building = cross_building(conanfile, skip_x64_x86=True)
if not self._is_cross_building and native:
raise ConanException("You can only pass native=True if you're cross-building, "
"otherwise, it could cause unexpected results.")
self._is_apple_system = is_apple_os(self._conanfile)

self._conanfile_conf = self._conanfile.conf_build if native else self._conanfile.conf
# Values are kept as Python built-ins so users can modify them more easily, and they are
# only converted to Meson file syntax for rendering
# priority: first user conf, then recipe, last one is default "ninja"
Expand Down Expand Up @@ -168,7 +214,7 @@ def __init__(self, conanfile, backend=None):
self.cross_build = {}
default_comp = ""
default_comp_cpp = ""
if cross_building(conanfile, skip_x64_x86=True):
if native is False and self._is_cross_building:
os_host = conanfile.settings.get_safe("os")
arch_host = conanfile.settings.get_safe("arch")
os_build = conanfile.settings_build.get_safe('os')
Expand Down Expand Up @@ -197,10 +243,11 @@ def __init__(self, conanfile, backend=None):
default_comp_cpp = "cl"

# Read configuration for compilers
compilers_by_conf = self._conanfile.conf.get("tools.build:compiler_executables", default={},
compilers_by_conf = self._conanfile_conf.get("tools.build:compiler_executables", default={},
check_type=dict)
# Read the VirtualBuildEnv to update the variables
build_env = VirtualBuildEnv(self._conanfile, auto_generate=True).vars()
build_env = self._conanfile.buildenv_build.vars(self._conanfile) if native else (
VirtualBuildEnv(self._conanfile, auto_generate=True).vars())
#: Sets the Meson ``c`` variable, defaulting to the ``CC`` build environment value.
#: If provided as a blank-separated string, it will be transformed into a list.
#: Otherwise, it remains a single string.
Expand Down Expand Up @@ -232,7 +279,7 @@ def __init__(self, conanfile, backend=None):
self.windres = build_env.get("WINDRES")
#: Defines the Meson ``pkgconfig`` variable. Defaulted to ``PKG_CONFIG``
#: build environment value
self.pkgconfig = (self._conanfile.conf.get("tools.gnu:pkg_config", check_type=str) or
self.pkgconfig = (self._conanfile_conf.get("tools.gnu:pkg_config", check_type=str) or
build_env.get("PKG_CONFIG"))
#: Defines the Meson ``c_args`` variable. Defaulted to ``CFLAGS`` build environment value
self.c_args = self._get_env_list(build_env.get("CFLAGS", []))
Expand Down Expand Up @@ -266,7 +313,8 @@ def __init__(self, conanfile, backend=None):
self.objcpp_link_args = []

self._resolve_apple_flags_and_variables(build_env, compilers_by_conf)
self._resolve_android_cross_compilation()
if native is False:
self._resolve_android_cross_compilation()

def _get_default_dirs(self):
"""
Expand Down Expand Up @@ -309,7 +357,7 @@ def _resolve_apple_flags_and_variables(self, build_env, compilers_by_conf):
return
# Calculating the main Apple flags
min_flag, arch_flag, isysroot_flag = (
resolve_apple_flags(self._conanfile, is_cross_building=bool(self.cross_build)))
resolve_apple_flags(self._conanfile, is_cross_building=self._is_cross_building))
franramirez688 marked this conversation as resolved.
Show resolved Hide resolved
self.apple_arch_flag = arch_flag.split() if arch_flag else []
self.apple_isysroot_flag = isysroot_flag.split() if isysroot_flag else []
self.apple_min_version_flag = [apple_min_version_flag(self._conanfile)]
Expand All @@ -322,10 +370,10 @@ def _resolve_apple_flags_and_variables(self, build_env, compilers_by_conf):
self.objcpp_link_args = self._get_env_list(build_env.get('LDFLAGS', []))

def _resolve_android_cross_compilation(self):
if not self.cross_build or not self.cross_build["host"]["system"] == "android":
if not self._is_cross_building or not self.cross_build["host"]["system"] == "android":
return

ndk_path = self._conanfile.conf.get("tools.android:ndk_path")
ndk_path = self._conanfile_conf.get("tools.android:ndk_path")
if not ndk_path:
raise ConanException("You must provide a NDK path. Use 'tools.android:ndk_path' "
"configuration field.")
Expand All @@ -346,11 +394,11 @@ def _resolve_android_cross_compilation(self):

def _get_extra_flags(self):
# Now, it's time to get all the flags defined by the user
cxxflags = self._conanfile.conf.get("tools.build:cxxflags", default=[], check_type=list)
cflags = self._conanfile.conf.get("tools.build:cflags", default=[], check_type=list)
sharedlinkflags = self._conanfile.conf.get("tools.build:sharedlinkflags", default=[], check_type=list)
exelinkflags = self._conanfile.conf.get("tools.build:exelinkflags", default=[], check_type=list)
linker_scripts = self._conanfile.conf.get("tools.build:linker_scripts", default=[], check_type=list)
cxxflags = self._conanfile_conf.get("tools.build:cxxflags", default=[], check_type=list)
cflags = self._conanfile_conf.get("tools.build:cflags", default=[], check_type=list)
sharedlinkflags = self._conanfile_conf.get("tools.build:sharedlinkflags", default=[], check_type=list)
exelinkflags = self._conanfile_conf.get("tools.build:exelinkflags", default=[], check_type=list)
linker_scripts = self._conanfile_conf.get("tools.build:linker_scripts", default=[], check_type=list)
linker_script_flags = ['-T"' + linker_script + '"' for linker_script in linker_scripts]
defines = [f"-D{d}" for d in self._conanfile.conf.get("tools.build:defines", default=[], check_type=list)]
return {
Expand Down Expand Up @@ -450,6 +498,15 @@ def _sanitize_format(v):
"is_apple_system": self._is_apple_system
}

@property
def _filename(self):
if self._is_cross_building and self._native:
franramirez688 marked this conversation as resolved.
Show resolved Hide resolved
return self.native_filename
elif self._is_cross_building:
return self.cross_filename
else:
return self.native_filename

@property
def _content(self):
"""
Expand All @@ -458,7 +515,8 @@ def _content(self):
:return: ``str`` whole Meson context content.
"""
context = self._context()
content = Template(self._meson_file_template).render(context)
content = Template(self._meson_file_template, trim_blocks=True, lstrip_blocks=True,
undefined=StrictUndefined).render(context)
return content

def generate(self):
Expand All @@ -468,7 +526,6 @@ def generate(self):
If Windows OS, it will be created a ``conanvcvars.bat`` as well.
"""
check_duplicated_generator(self, self._conanfile)
filename = self.native_filename if not self.cross_build else self.cross_filename
save(filename, self._content)
save(self._filename, self._content)
# FIXME: Should we check the OS and compiler to call VCVars?
VCVars(self._conanfile).generate()
5 changes: 5 additions & 0 deletions conans/client/graph/profile_node_definer.py
Expand Up @@ -26,8 +26,13 @@ def initialize_conanfile_profile(conanfile, profile_build, profile_host, base_co
settings_build = _per_package_settings(conanfile, profile_build, ref)
if is_build_require or base_context == CONTEXT_BUILD:
_initialize_conanfile(conanfile, profile_build, settings_build.copy(), ref)
conanfile.buildenv_build = None
conanfile.conf_build = None
memsharded marked this conversation as resolved.
Show resolved Hide resolved
else:
_initialize_conanfile(conanfile, profile_host, settings_host, ref)
# Host profile with some build profile information
conanfile.buildenv_build = profile_build.buildenv.get_profile_env(ref, conanfile._conan_is_consumer)
conanfile.conf_build = profile_build.conf.get_conanfile_conf(ref, conanfile._conan_is_consumer)
conanfile.settings_build = settings_build
conanfile.settings_target = None

Expand Down
1 change: 0 additions & 1 deletion conans/model/conan_file.py
Expand Up @@ -9,7 +9,6 @@
from conans.model.dependencies import ConanFileDependencies
from conans.model.layout import Folders, Infos, Layouts
from conans.model.options import Options

from conans.model.requires import Requirements
from conans.model.settings import Settings

Expand Down