From 59168337f2bc2e957e93ba0ee171a8a20374a288 Mon Sep 17 00:00:00 2001 From: Francisco Ramirez de Anton Date: Thu, 30 Jun 2022 14:12:34 +0200 Subject: [PATCH] Added get_gnu_deps_flags. Added functional test --- conan/tools/gnu/__init__.py | 2 +- conan/tools/gnu/autotoolsdeps.py | 115 ++++++++++-------- .../meson/test_meson_and_gnu_deps_flags.py | 65 ++++++++++ 3 files changed, 130 insertions(+), 52 deletions(-) create mode 100644 conans/test/functional/toolchains/meson/test_meson_and_gnu_deps_flags.py diff --git a/conan/tools/gnu/__init__.py b/conan/tools/gnu/__init__.py index a7c75b32404..ad196253be6 100644 --- a/conan/tools/gnu/__init__.py +++ b/conan/tools/gnu/__init__.py @@ -1,5 +1,5 @@ from conan.tools.gnu.autotools import Autotools from conan.tools.gnu.autotoolstoolchain import AutotoolsToolchain -from conan.tools.gnu.autotoolsdeps import AutotoolsDeps +from conan.tools.gnu.autotoolsdeps import AutotoolsDeps, get_gnu_deps_flags from conan.tools.gnu.pkgconfig import PkgConfig from conan.tools.gnu.pkgconfigdeps import PkgConfigDeps diff --git a/conan/tools/gnu/autotoolsdeps.py b/conan/tools/gnu/autotoolsdeps.py index 8fc992c250b..3f89f548c5e 100644 --- a/conan/tools/gnu/autotoolsdeps.py +++ b/conan/tools/gnu/autotoolsdeps.py @@ -4,66 +4,79 @@ from conans.model.new_build_info import NewCppInfo +def _get_cpp_info(deps): + ret = NewCppInfo() + for dep in deps: + dep_cppinfo = dep.cpp_info.aggregated_components() + # In case we have components, aggregate them, we do not support isolated + # "targets" with autotools + ret.merge(dep_cppinfo) + return ret + + +def _rpaths_flags(deps): + flags = [] + for dep in deps: + flags.extend(["-Wl,-rpath -Wl,{}".format(libdir) for libdir in dep.cpp_info.libdirs + if dep.options.get_safe("shared", False)]) + return flags + + +def ordered_deps(conanfile): + deps = conanfile.dependencies.host.topological_sort + return[dep for dep in reversed(deps.values())] + + +def get_gnu_deps_flags(conanfile): + """ + Given a ConanFile object, this function returns all the GNU flags from all the + dependencies. + + :param conanfile: The current recipe object. Always use ``self``. + :return: ``tuple`` of all the GNU flags. + """ + deps = ordered_deps(conanfile) + flags = GnuDepsFlags(conanfile, _get_cpp_info(deps)) + + # cpp_flags + cpp_flags = [] + cpp_flags.extend(flags.include_paths) + cpp_flags.extend(flags.defines) + + # Ldflags + ldflags = flags.sharedlinkflags + ldflags.extend(flags.exelinkflags) + ldflags.extend(flags.frameworks) + ldflags.extend(flags.framework_paths) + ldflags.extend(flags.lib_paths) + + # set the rpath in Macos so that the library are found in the configure step + if conanfile.settings.get_safe("os") == "Macos": + ldflags.extend(_rpaths_flags(deps)) + + # libs + libs = flags.libs + libs.extend(flags.system_libs) + + # cflags + cflags = flags.cflags + cxxflags = flags.cxxflags + return cflags, cxxflags, cpp_flags, libs, ldflags + + class AutotoolsDeps: def __init__(self, conanfile): self._conanfile = conanfile self._environment = None - self._ordered_deps = [] check_using_build_profile(self._conanfile) - @property - def ordered_deps(self): - if not self._ordered_deps: - deps = self._conanfile.dependencies.host.topological_sort - self._ordered_deps = [dep for dep in reversed(deps.values())] - return self._ordered_deps - - def _get_cpp_info(self): - ret = NewCppInfo() - for dep in self.ordered_deps: - dep_cppinfo = dep.cpp_info.aggregated_components() - # In case we have components, aggregate them, we do not support isolated - # "targets" with autotools - ret.merge(dep_cppinfo) - return ret - - def _rpaths_flags(self): - flags = [] - for dep in self.ordered_deps: - flags.extend(["-Wl,-rpath -Wl,{}".format(libdir) for libdir in dep.cpp_info.libdirs - if dep.options.get_safe("shared", False)]) - return flags - @property def environment(self): # TODO: Seems we want to make this uniform, equal to other generators if self._environment is None: - flags = GnuDepsFlags(self._conanfile, self._get_cpp_info()) - - # cpp_flags - cpp_flags = [] - cpp_flags.extend(flags.include_paths) - cpp_flags.extend(flags.defines) - - # Ldflags - ldflags = flags.sharedlinkflags - ldflags.extend(flags.exelinkflags) - ldflags.extend(flags.frameworks) - ldflags.extend(flags.framework_paths) - ldflags.extend(flags.lib_paths) - - ## set the rpath in Macos so that the library are found in the configure step - if self._conanfile.settings.get_safe("os") == "Macos": - ldflags.extend(self._rpaths_flags()) - - # libs - libs = flags.libs - libs.extend(flags.system_libs) - - # cflags - cflags = flags.cflags - cxxflags = flags.cxxflags - + # Get all the GNU flags from all the dependencies + cflags, cxxflags, cpp_flags, libs, ldflags = get_gnu_deps_flags(self._conanfile) + # Create the environment env = Environment() env.append("CPPFLAGS", cpp_flags) env.append("LIBS", libs) @@ -76,5 +89,5 @@ def environment(self): def vars(self, scope="build"): return self.environment.vars(self._conanfile, scope=scope) - def generate(self, scope="build"): + def generate(self, scope="build"): self.vars(scope).save_script("conanautotoolsdeps") diff --git a/conans/test/functional/toolchains/meson/test_meson_and_gnu_deps_flags.py b/conans/test/functional/toolchains/meson/test_meson_and_gnu_deps_flags.py new file mode 100644 index 00000000000..4a13bd756d3 --- /dev/null +++ b/conans/test/functional/toolchains/meson/test_meson_and_gnu_deps_flags.py @@ -0,0 +1,65 @@ +import textwrap +import platform + +import pytest + +from conans.test.assets.sources import gen_function_cpp +from conans.test.functional.toolchains.meson._base import TestMesonBase +from conans.test.utils.tools import TestClient + + +class TestMesonToolchainAndGnuFlags(TestMesonBase): + + @pytest.mark.skipif(platform.system() == "Windows", reason="Unix only") + def test_mesontoolchain_using_gnu_deps_flags(self): + client = TestClient(path_with_spaces=False) + client.run("new hello/0.1 -s") + client.run("create . hello/0.1@ %s" % self._settings_str) + app = gen_function_cpp(name="main", includes=["hello"], calls=["hello"]) + + conanfile_py = textwrap.dedent(""" + from conan import ConanFile + from conan.tools.meson import Meson, MesonToolchain + from conan.tools.gnu import get_gnu_deps_flags + + + class App(ConanFile): + settings = "os", "arch", "compiler", "build_type" + requires = "hello/0.1" + + def layout(self): + self.folders.build = "build" + + def generate(self): + # Get GNU flags from all the dependencies + cflags, cxxflags, cpp_flags, libs, ldflags = get_gnu_deps_flags(self) + + tc = MesonToolchain(self) + # Extend flags to MesonToolchain + tc.c_args.extend(cpp_flags) + tc.cpp_args.extend(cpp_flags) + tc.c_link_args.extend(ldflags) + tc.cpp_link_args.extend(ldflags) + tc.generate() + + def build(self): + meson = Meson(self) + meson.configure() + meson.build() + """) + + meson_build = textwrap.dedent(""" + project('tutorial', 'cpp') + cxx = meson.get_compiler('cpp') + hello = cxx.find_library('hello', required: true) + executable('demo', 'main.cpp', dependencies: hello) + """) + + client.save({"conanfile.py": conanfile_py, + "meson.build": meson_build, + "main.cpp": app}, + clean_first=True) + + client.run("install . %s" % self._settings_str) + client.run("build .") + assert "[2/2] Linking target demo" in client.out