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

[AutotoolsToolchain] Added self.xxxx_options #12645

Closed
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
79 changes: 61 additions & 18 deletions conan/tools/gnu/autotoolstoolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,43 @@
from conan.tools.env import Environment
from conan.tools.files.files import save_toolchain_args
from conan.tools.gnu.get_gnu_triplet import _get_gnu_triplet
from conan.tools.microsoft import VCVars, is_msvc, msvc_runtime_flag
from conan.tools.microsoft import VCVars, msvc_runtime_flag
from conans.errors import ConanException
from conans.tools import args_to_string


# FIXME: Remove this whenever self.xxx_args disappear
def _args_to_dict(args):
"""
Given a list of arguments as GNU options, it'll return the same content but as a
dict-like Python object, e.g., {"--flag_name": "flag_value"}
"""
ret = {}
for flag in args:
# Only splitting if "=" is there. No need to check if it starts by "--" or "-"
option = flag.split("=")
if len(option) == 2:
ret[option[0]] = option[1]
else:
ret[option[0]] = ""
return ret


def _options_to_string(options):
opts = []
for k, v in options.items():
# If value, it's assumed the flag will be flag=value, else keeping flag only
# For instance: {"--opt1": "whatever", "-abc": ""} --> ["--opt1=whatever", "-abc"]
opts.append(f"{k}={v}" if v else k)
return args_to_string(opts)


class AutotoolsToolchain:
def __init__(self, conanfile, namespace=None, prefix="/"):
self._conanfile = conanfile
self._namespace = namespace
self._prefix = prefix

self.configure_args = self._default_configure_shared_flags() + self._default_configure_install_flags()
self.autoreconf_args = self._default_autoreconf_flags()
self.make_args = []

# Flags
self.extra_cxxflags = []
self.extra_cflags = []
Expand Down Expand Up @@ -55,12 +77,13 @@ def __init__(self, conanfile, namespace=None, prefix="/"):
self.sysroot_flag = None

if cross_building(self._conanfile):
# Host triplet
os_build, arch_build, os_host, arch_host = get_cross_building_settings(self._conanfile)
compiler = self._conanfile.settings.get_safe("compiler")
if not self._host:
self._host = _get_gnu_triplet(os_host, arch_host, compiler=compiler)
# Build triplet
self._build = _get_gnu_triplet(os_build, arch_build, compiler=compiler)

# Apple Stuff
if os_build == "Macos":
sdk_path = apple_sdk_path(conanfile)
Expand All @@ -73,6 +96,18 @@ def __init__(self, conanfile, namespace=None, prefix="/"):
sysroot = self._conanfile.conf.get("tools.build:sysroot")
sysroot = sysroot.replace("\\", "/") if sysroot is not None else None
self.sysroot_flag = "--sysroot {}".format(sysroot) if sysroot else None
# DEPRECATED: self.xxxx_args attributes in favor of self.xxxxx_options ones since Conan 1.57
self.configure_args = self._default_configure_shared_flags() + \
self._default_configure_install_flags() + \
self._get_triplets()
self.autoreconf_args = self._default_autoreconf_flags()
self.make_args = []
# FIXME: Remove this whenever self.xxx_args are not used anymore
self.use_new_options = False
# New dict-like attributes since Conan 1.57
self.configure_options = _args_to_dict(self.configure_args)
self.autoreconf_options = _args_to_dict(self.autoreconf_args)
self.make_options = _args_to_dict(self.make_args)

check_using_build_profile(self._conanfile)

Expand Down Expand Up @@ -178,19 +213,27 @@ def _get_argument(argument_name, cppinfo_name):
_get_argument("datarootdir", "resdirs")])
return [el for el in configure_install_flags if el]

def _default_autoreconf_flags(self):
@staticmethod
def _default_autoreconf_flags():
return ["--force", "--install"]

def generate_args(self):
configure_args = []
configure_args.extend(self.configure_args)
user_args_str = args_to_string(self.configure_args)
for flag, var in (("host", self._host), ("build", self._build), ("target", self._target)):
if var and flag not in user_args_str:
configure_args.append('--{}={}'.format(flag, var))

args = {"configure_args": args_to_string(configure_args),
"make_args": args_to_string(self.make_args),
"autoreconf_args": args_to_string(self.autoreconf_args)}
def _get_triplets(self):
triplets = []
for flag, value in (("--host=", self._host), ("--build=", self._build),
("--target=", self._target)):
if value:
franramirez688 marked this conversation as resolved.
Show resolved Hide resolved
triplets.append(f'{flag}{value}')
return triplets

def generate_args(self):
# FIXME: Remove this whenever self.xxx_args disappear
if self.use_new_options is False:
# Copying again the legacy args just in case recipes add/remove new ones
self.configure_options = _args_to_dict(self.configure_args)
self.make_options = _args_to_dict(self.make_args)
self.autoreconf_options = _args_to_dict(self.autoreconf_args)

args = {"configure_args": _options_to_string(self.configure_options),
"make_args": _options_to_string(self.make_options),
"autoreconf_args": _options_to_string(self.autoreconf_options)}
save_toolchain_args(args, namespace=self._namespace)
63 changes: 63 additions & 0 deletions conans/test/unittests/tools/gnu/autotoolschain_test.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
from unittest.mock import patch

import pytest

from conan.tools.gnu import AutotoolsToolchain
from conan.tools.gnu.autotoolstoolchain import _options_to_string
from conans.errors import ConanException
from conans.model.conf import Conf
from conans.test.utils.mocks import ConanFileMock, MockSettings


@pytest.fixture()
def cross_building_conanfile():
settings_build = MockSettings({"os": "Linux",
"arch": "x86_64",
"compiler": "gcc",
"compiler.version": "11",
"compiler.libcxx": "libstdc++",
"build_type": "Release"})
settings_target = MockSettings({"os": "Android", "arch": "armv8"})
settings = MockSettings({"os": "Emscripten", "arch": "wasm"})
conanfile = ConanFileMock()
conanfile.settings = settings
conanfile.settings_build = settings_build
conanfile.settings_target = settings_target
return conanfile


def test_get_gnu_triplet_for_cross_building():
"""
Testing AutotoolsToolchain and _get_gnu_triplet() function in case of
Expand Down Expand Up @@ -125,3 +145,46 @@ def test_compilers_mapping():
env = autotoolschain.environment().vars(conanfile)
for compiler, env_var in autotools_mapping.items():
assert env[env_var] == f"path_to_{compiler}"


@patch("conan.tools.gnu.autotoolstoolchain.save_toolchain_args")
def test_check_configure_args_overwriting_and_deletion(save_args, cross_building_conanfile):
# Issue: https://github.com/conan-io/conan/issues/12642
at = AutotoolsToolchain(cross_building_conanfile)
at.configure_args.extend([
"--with-cross-build=my_path",
"--something-host=my_host"
])
at.generate_args()
configure_args = save_args.call_args[0][0]['configure_args']
assert "--build=x86_64-linux-gnu" in configure_args
assert "--host=wasm32-local-emscripten" in configure_args
assert "--with-cross-build=my_path" in configure_args
assert "--something-host=my_host" in configure_args
# https://github.com/conan-io/conan/issues/12431
at.configure_args.remove("--build=x86_64-linux-gnu")
at.configure_args.remove("--host=wasm32-local-emscripten")
at.generate_args()
configure_args = save_args.call_args[0][0]['configure_args']
assert "--build=x86_64-linux-gnu" not in configure_args # removed
assert "--host=wasm32-local-emscripten" not in configure_args # removed
assert "--with-cross-build=my_path" in configure_args
assert "--something-host=my_host" in configure_args


def test_update_or_prune_any_args(cross_building_conanfile):
at = AutotoolsToolchain(cross_building_conanfile)
at.use_new_options = True
at.configure_options["--prefix"] = "/my/other/prefix"
at.configure_options.pop("--build")
at.configure_options.pop("--host")
configure_options = _options_to_string(at.configure_options)
assert "--prefix=/my/other/prefix" in configure_options
assert "--host=" not in configure_options
assert "--build=" not in configure_options
at.autoreconf_options.pop("--force")
autoreconf_options = _options_to_string(at.autoreconf_options)
assert "--force" not in autoreconf_options
at.make_options["--complex-flag"] = "new-value"
make_options = _options_to_string(at.make_options)
assert "--complex-flag=new-value" in make_options