diff --git a/conan/tools/meson/__init__.py b/conan/tools/meson/__init__.py index f748b3735fe..786057b639f 100644 --- a/conan/tools/meson/__init__.py +++ b/conan/tools/meson/__init__.py @@ -1,2 +1,3 @@ # noinspection PyUnresolvedReferences -from .meson import MesonToolchain +from conan.tools.meson.toolchain import MesonToolchain +from conan.tools.meson.meson import Meson diff --git a/conan/tools/meson/meson.py b/conan/tools/meson/meson.py index d2cd841fdec..caceda23add 100644 --- a/conan/tools/meson/meson.py +++ b/conan/tools/meson/meson.py @@ -1,272 +1,52 @@ import os -from conans.client.build.cppstd_flags import cppstd_from_settings -from conans.client.tools.oss import cross_building, get_cross_building_settings -from conans.util.files import save +from conan.tools.meson import MesonToolchain +from conan.tools.microsoft.visual import vcvars_command, vcvars_arch +from conans.client.tools.oss import cross_building -import textwrap -from jinja2 import Template - -class MesonToolchain(object): - _native_filename = "conan_meson_native.ini" - _cross_filename = "conan_meson_cross.ini" - - _native_file_template = textwrap.dedent(""" - [project options] - {{project_options}} - - [binaries] - {% if c %}c = {{c}}{% endif %} - {% if cpp %}cpp = {{cpp}}{% 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 %} - - [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 c_args %}c_args = {{c_args}}{% endif %} - {% if c_link_args %}c_link_args = {{c_link_args}}{% endif %} - {% if cpp_args %}cpp_args = {{cpp_args}}{% endif %} - {% if cpp_link_args %}cpp_link_args = {{cpp_link_args}}{% endif %} - {% if pkg_config_path %}pkg_config_path = {{pkg_config_path}}{% endif %} - """) - - _cross_file_template = _native_file_template + textwrap.dedent(""" - [build_machine] - {{build_machine}} - - [host_machine] - {{host_machine}} - - [target_machine] - {{target_machine}} - """) - - _machine_template = textwrap.dedent(""" - system = {{system}} - cpu_family = {{cpu_family}} - cpu = {{cpu}} - endian = {{endian}} - """) - - def __init__(self, conanfile, env=os.environ): +class Meson(object): + def __init__(self, conanfile, build_folder='build'): self._conanfile = conanfile - self._build_type = self._conanfile.settings.get_safe("build_type") - self._base_compiler = self._conanfile.settings.get_safe("compiler.base") or \ - self._conanfile.settings.get_safe("compiler") - self._vscrt = self._conanfile.settings.get_safe("compiler.base.runtime") or \ - self._conanfile.settings.get_safe("compiler.runtime") - self._cppstd = cppstd_from_settings(self._conanfile.settings) - self._shared = self._conanfile.options.get_safe("shared") - self._fpic = self._conanfile.options.get_safe("fPIC") - self.definitions = dict() - self._env = env - - @staticmethod - def _to_meson_value(value): - # https://mesonbuild.com/Machine-files.html#data-types - import six - - try: - from collections.abc import Iterable - except ImportError: - from collections import Iterable - - if isinstance(value, six.string_types): - return "'%s'" % value - elif isinstance(value, bool): - return 'true' if value else "false" - elif isinstance(value, six.integer_types): - return value - elif isinstance(value, Iterable): - return '[%s]' % ', '.join([str(MesonToolchain._to_meson_value(v)) for v in value]) - return value - - @staticmethod - def _to_meson_build_type(build_type): - return {"Debug": "'debug'", - "Release": "'release'", - "MinSizeRel": "'minsize'", - "RelWithDebInfo": "'debugoptimized'"}.get(build_type, "'%s'" % build_type) - # FIXME : use 'custom' otherwise? or use just None? - - @property - def _debug(self): - return self._build_type == "Debug" - - @property - def _ndebug(self): - # ERROR: Value "True" (of type "boolean") for combo option "Disable asserts" is not one of - # the choices. Possible choices are (as string): "true", "false", "if-release". - return "true" if self._build_type != "Debug" else "false" - - @staticmethod - def _to_meson_vscrt(vscrt): - return {"MD": "'md'", - "MDd": "'mdd'", - "MT": "'mt'", - "MTd": "'mtd'"}.get(vscrt, "'none'") - - @staticmethod - def _to_meson_shared(shared): - return "'shared'" if shared else "'static'" - - def _to_meson_cppstd(self, cppstd): - if self._base_compiler == "Visual Studio": - return {'14': "'vc++14'", - '17': "'vc++17'", - '20': "'vc++latest'"}.get(cppstd, "'none'") - return {'98': "'c++03'", 'gnu98': "'gnu++03'", - '11': "'c++11'", 'gnu11': "'gnu++11'", - '14': "'c++14'", 'gnu14': "'gnu++14'", - '17': "'c++17'", 'gnu17': "'gnu++17'", - '20': "'c++1z'", 'gnu20': "'gnu++1z'"}.get(cppstd, "'none'") - - @staticmethod - def _none_if_empty(value): - return "'%s'" % value if value.strip() else None - - @property - def _context(self): - project_options = [] - for k, v in self.definitions.items(): - project_options.append("%s = %s" % (k, self._to_meson_value(v))) - project_options = "\n".join(project_options) - - context = { - # https://mesonbuild.com/Machine-files.html#project-specific-options - "project_options": project_options, - # https://mesonbuild.com/Builtin-options.html#directories - # TODO : we don't manage paths like libdir here (yet?) - # https://mesonbuild.com/Machine-files.html#binaries - "c": self._to_meson_value(self._env.get("CC", None)), - "cpp": self._to_meson_value(self._env.get("CXX", None)), - "c_ld": self._to_meson_value(self._env.get("LD", None)), - "cpp_ld": self._to_meson_value(self._env.get("LD", None)), - "ar": self._to_meson_value(self._env.get("AR", None)), - "strip": self._to_meson_value(self._env.get("STRIP", None)), - "as": self._to_meson_value(self._env.get("AS", None)), - "windres": self._to_meson_value(self._env.get("WINDRES", None)), - "pkgconfig": self._to_meson_value(self._env.get("PKG_CONFIG", None)), - # https://mesonbuild.com/Builtin-options.html#core-options - "buildtype": self._to_meson_build_type(self._build_type) if self._build_type else None, - "debug": self._to_meson_value(self._debug) if self._build_type else None, - "default_library": self._to_meson_shared( - self._shared) if self._shared is not None else None, - # https://mesonbuild.com/Builtin-options.html#base-options - "b_vscrt": self._to_meson_vscrt(self._vscrt), - "b_staticpic": self._to_meson_value(self._fpic) if (self._shared is False and self._fpic - is not None) else None, - "b_ndebug": self._to_meson_value(self._ndebug) if self._build_type else None, - # https://mesonbuild.com/Builtin-options.html#compiler-options - "cpp_std": self._to_meson_cppstd(self._cppstd) if self._cppstd else None, - "c_args": self._none_if_empty(self._env.get("CPPFLAGS", '') + - self._env.get("CFLAGS", '')), - "c_link_args": self._env.get("LDFLAGS", None), - "cpp_args": self._none_if_empty(self._env.get("CPPFLAGS", '') + - self._env.get("CXXFLAGS", '')), - "cpp_link_args": self._env.get("LDFLAGS", None), - "pkg_config_path": self._env.get("PKG_CONFIG_PATH", None) - } - return context + self._build_folder = build_folder - @staticmethod - def _render(template, context): - t = Template(template) - return t.render(context) + def _run(self, cmd): + if self._conanfile.settings.get_safe("compiler") == "Visual Studio": + vcvars = vcvars_command(self._conanfile.settings.get_safe("compiler.version"), + vcvars_arch(self._conanfile)) + cmd = '%s && %s' % (vcvars, cmd) + self._conanfile.run(cmd) @property - def _native_content(self): - return self._render(self._native_file_template, self._context) - - def _to_meson_machine(self, machine_os, machine_arch): - # https://mesonbuild.com/Reference-tables.html#operating-system-names - system_map = {'Android': 'android', - 'Macos': 'darwin', - 'iOS': 'darwin', - 'watchOS': 'darwin', - 'tvOS': 'darwin', - 'FreeBSD': 'freebsd', - 'Emscripten': 'emscripten', - 'Linux': 'linux', - 'SunOS': 'sunos', - 'Windows': 'windows', - 'WindowsCE': 'windows', - 'WindowsStore': 'windows'} - # https://mesonbuild.com/Reference-tables.html#cpu-families - cpu_family_map = {'armv4': ('arm', 'armv4', 'little'), - 'armv4i': ('arm', 'armv4i', 'little'), - 'armv5el': ('arm', 'armv5el', 'little'), - 'armv5hf': ('arm', 'armv5hf', 'little'), - 'armv6': ('arm', 'armv6', 'little'), - 'armv7': ('arm', 'armv7', 'little'), - 'armv7hf': ('arm', 'armv7hf', 'little'), - 'armv7s': ('arm', 'armv7s', 'little'), - 'armv7k':('arm', 'armv7k', 'little'), - 'armv8': ('aarch64', 'armv8', 'little'), - 'armv8_32': ('aarch64', 'armv8_32', 'little'), - 'armv8.3': ('aarch64', 'armv8.3', 'little'), - 'avr': ('avr', 'avr', 'little'), - 'mips': ('mips', 'mips', 'big'), - 'mips64': ('mips64', 'mips64', 'big'), - 'ppc32be': ('ppc', 'ppc', 'big'), - 'ppc32': ('ppc', 'ppc', 'little'), - 'ppc64le': ('ppc64', 'ppc64', 'little'), - 'ppc64': ('ppc64', 'ppc64', 'big'), - 's390': ('s390', 's390', 'big'), - 's390x': ('s390x', 's390x', 'big'), - 'sh4le': ('sh4', 'sh4', 'little'), - 'sparc': ('sparc', 'sparc', 'big'), - 'sparcv9': ('sparc64', 'sparc64', 'big'), - 'wasm': ('wasm32', 'wasm32', 'little'), - 'x86': ('x86', 'x86', 'little'), - 'x86_64': ('x86_64', 'x86_64', 'little')} - system = system_map.get(machine_os, machine_os.lower()) - default_cpu_tuple = (machine_arch.lower(), machine_arch.lower(), 'little') - cpu_tuple = cpu_family_map.get(machine_arch, default_cpu_tuple) - cpu_family, cpu, endian = cpu_tuple[0], cpu_tuple[1], cpu_tuple[2] - context = { - 'system': self._to_meson_value(system), - 'cpu_family': self._to_meson_value(cpu_family), - 'cpu': self._to_meson_value(cpu), - 'endian': self._to_meson_value(endian), - } - return self._render(self._machine_template, context) - - @property - def _cross_content(self): - os_build, arch_build, os_host, arch_host = get_cross_building_settings(self._conanfile) - os_target, arch_target = os_host, arch_host # TODO: assume target the same as a host for now? - - build_machine = self._to_meson_machine(os_build, arch_build) - host_machine = self._to_meson_machine(os_host, arch_host) - target_machine = self._to_meson_machine(os_target, arch_target) - - context = self._context - context['build_machine'] = build_machine - context['host_machine'] = host_machine - context['target_machine'] = target_machine - return self._render(self._cross_file_template, context) - - def _write_native_file(self): - save(self._native_filename, self._native_content) - - def _write_cross_file(self): - save(self._cross_filename, self._cross_content) - - def generate(self): + def _build_dir(self): + build = self._conanfile.build_folder + if self._build_folder: + build = os.path.join(self._conanfile.build_folder, self._build_folder) + return build + + def configure(self, source_folder=None): + source = self._conanfile.source_folder + if source_folder: + source = os.path.join(self._conanfile.source_folder, source_folder) + + cmd = "meson setup" if cross_building(self._conanfile): - self._write_cross_file() + cmd += ' --cross-file "{}"'.format(MesonToolchain.cross_filename) else: - self._write_native_file() + cmd += ' --native-file "{}"'. format(MesonToolchain.native_filename) + cmd += ' "{}" "{}"'.format(self._build_dir, source) + if self._conanfile.package_folder: + cmd += ' -Dprefix="{}"'.format(self._conanfile.package_folder) + self._run(cmd) + + def build(self): + cmd = 'meson compile -C "{}"'.format(self._build_dir) + self._run(cmd) + + def install(self): + cmd = 'meson install -C "{}"'.format(self._build_dir) + self._run(cmd) + + def test(self): + cmd = 'meson test -v -C "{}"'.format(self._build_dir) + self._run(cmd) diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py new file mode 100644 index 00000000000..40c7bd8203a --- /dev/null +++ b/conan/tools/meson/toolchain.py @@ -0,0 +1,272 @@ +import os + +from conans.client.build.cppstd_flags import cppstd_from_settings +from conans.client.tools.oss import cross_building, get_cross_building_settings +from conans.util.files import save + +import textwrap +from jinja2 import Template + + +class MesonToolchain(object): + native_filename = "conan_meson_native.ini" + cross_filename = "conan_meson_cross.ini" + + _native_file_template = textwrap.dedent(""" + [project options] + {{project_options}} + + [binaries] + {% if c %}c = {{c}}{% endif %} + {% if cpp %}cpp = {{cpp}}{% 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 %} + + [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 c_args %}c_args = {{c_args}}{% endif %} + {% if c_link_args %}c_link_args = {{c_link_args}}{% endif %} + {% if cpp_args %}cpp_args = {{cpp_args}}{% endif %} + {% if cpp_link_args %}cpp_link_args = {{cpp_link_args}}{% endif %} + {% if pkg_config_path %}pkg_config_path = {{pkg_config_path}}{% endif %} + """) + + _cross_file_template = _native_file_template + textwrap.dedent(""" + [build_machine] + {{build_machine}} + + [host_machine] + {{host_machine}} + + [target_machine] + {{target_machine}} + """) + + _machine_template = textwrap.dedent(""" + system = {{system}} + cpu_family = {{cpu_family}} + cpu = {{cpu}} + endian = {{endian}} + """) + + def __init__(self, conanfile, env=os.environ): + self._conanfile = conanfile + self._build_type = self._conanfile.settings.get_safe("build_type") + self._base_compiler = self._conanfile.settings.get_safe("compiler.base") or \ + self._conanfile.settings.get_safe("compiler") + self._vscrt = self._conanfile.settings.get_safe("compiler.base.runtime") or \ + self._conanfile.settings.get_safe("compiler.runtime") + self._cppstd = cppstd_from_settings(self._conanfile.settings) + self._shared = self._conanfile.options.get_safe("shared") + self._fpic = self._conanfile.options.get_safe("fPIC") + self.definitions = dict() + self._env = env + + @staticmethod + def _to_meson_value(value): + # https://mesonbuild.com/Machine-files.html#data-types + import six + + try: + from collections.abc import Iterable + except ImportError: + from collections import Iterable + + if isinstance(value, six.string_types): + return "'%s'" % value + elif isinstance(value, bool): + return 'true' if value else "false" + elif isinstance(value, six.integer_types): + return value + elif isinstance(value, Iterable): + return '[%s]' % ', '.join([str(MesonToolchain._to_meson_value(v)) for v in value]) + return value + + @staticmethod + def _to_meson_build_type(build_type): + return {"Debug": "'debug'", + "Release": "'release'", + "MinSizeRel": "'minsize'", + "RelWithDebInfo": "'debugoptimized'"}.get(build_type, "'%s'" % build_type) + # FIXME : use 'custom' otherwise? or use just None? + + @property + def _debug(self): + return self._build_type == "Debug" + + @property + def _ndebug(self): + # ERROR: Value "True" (of type "boolean") for combo option "Disable asserts" is not one of + # the choices. Possible choices are (as string): "true", "false", "if-release". + return "true" if self._build_type != "Debug" else "false" + + @staticmethod + def _to_meson_vscrt(vscrt): + return {"MD": "'md'", + "MDd": "'mdd'", + "MT": "'mt'", + "MTd": "'mtd'"}.get(vscrt, "'none'") + + @staticmethod + def _to_meson_shared(shared): + return "'shared'" if shared else "'static'" + + def _to_meson_cppstd(self, cppstd): + if self._base_compiler == "Visual Studio": + return {'14': "'vc++14'", + '17': "'vc++17'", + '20': "'vc++latest'"}.get(cppstd, "'none'") + return {'98': "'c++03'", 'gnu98': "'gnu++03'", + '11': "'c++11'", 'gnu11': "'gnu++11'", + '14': "'c++14'", 'gnu14': "'gnu++14'", + '17': "'c++17'", 'gnu17': "'gnu++17'", + '20': "'c++1z'", 'gnu20': "'gnu++1z'"}.get(cppstd, "'none'") + + @staticmethod + def _none_if_empty(value): + return "'%s'" % value if value.strip() else None + + @property + def _context(self): + project_options = [] + for k, v in self.definitions.items(): + project_options.append("%s = %s" % (k, self._to_meson_value(v))) + project_options = "\n".join(project_options) + + context = { + # https://mesonbuild.com/Machine-files.html#project-specific-options + "project_options": project_options, + # https://mesonbuild.com/Builtin-options.html#directories + # TODO : we don't manage paths like libdir here (yet?) + # https://mesonbuild.com/Machine-files.html#binaries + "c": self._to_meson_value(self._env.get("CC", None)), + "cpp": self._to_meson_value(self._env.get("CXX", None)), + "c_ld": self._to_meson_value(self._env.get("LD", None)), + "cpp_ld": self._to_meson_value(self._env.get("LD", None)), + "ar": self._to_meson_value(self._env.get("AR", None)), + "strip": self._to_meson_value(self._env.get("STRIP", None)), + "as": self._to_meson_value(self._env.get("AS", None)), + "windres": self._to_meson_value(self._env.get("WINDRES", None)), + "pkgconfig": self._to_meson_value(self._env.get("PKG_CONFIG", None)), + # https://mesonbuild.com/Builtin-options.html#core-options + "buildtype": self._to_meson_build_type(self._build_type) if self._build_type else None, + "debug": self._to_meson_value(self._debug) if self._build_type else None, + "default_library": self._to_meson_shared( + self._shared) if self._shared is not None else None, + # https://mesonbuild.com/Builtin-options.html#base-options + "b_vscrt": self._to_meson_vscrt(self._vscrt), + "b_staticpic": self._to_meson_value(self._fpic) if (self._shared is False and self._fpic + is not None) else None, + "b_ndebug": self._to_meson_value(self._ndebug) if self._build_type else None, + # https://mesonbuild.com/Builtin-options.html#compiler-options + "cpp_std": self._to_meson_cppstd(self._cppstd) if self._cppstd else None, + "c_args": self._none_if_empty(self._env.get("CPPFLAGS", '') + + self._env.get("CFLAGS", '')), + "c_link_args": self._env.get("LDFLAGS", None), + "cpp_args": self._none_if_empty(self._env.get("CPPFLAGS", '') + + self._env.get("CXXFLAGS", '')), + "cpp_link_args": self._env.get("LDFLAGS", None), + "pkg_config_path": "'%s'" % os.getcwd() + } + return context + + @staticmethod + def _render(template, context): + t = Template(template) + return t.render(context) + + @property + def _native_content(self): + return self._render(self._native_file_template, self._context) + + def _to_meson_machine(self, machine_os, machine_arch): + # https://mesonbuild.com/Reference-tables.html#operating-system-names + system_map = {'Android': 'android', + 'Macos': 'darwin', + 'iOS': 'darwin', + 'watchOS': 'darwin', + 'tvOS': 'darwin', + 'FreeBSD': 'freebsd', + 'Emscripten': 'emscripten', + 'Linux': 'linux', + 'SunOS': 'sunos', + 'Windows': 'windows', + 'WindowsCE': 'windows', + 'WindowsStore': 'windows'} + # https://mesonbuild.com/Reference-tables.html#cpu-families + cpu_family_map = {'armv4': ('arm', 'armv4', 'little'), + 'armv4i': ('arm', 'armv4i', 'little'), + 'armv5el': ('arm', 'armv5el', 'little'), + 'armv5hf': ('arm', 'armv5hf', 'little'), + 'armv6': ('arm', 'armv6', 'little'), + 'armv7': ('arm', 'armv7', 'little'), + 'armv7hf': ('arm', 'armv7hf', 'little'), + 'armv7s': ('arm', 'armv7s', 'little'), + 'armv7k':('arm', 'armv7k', 'little'), + 'armv8': ('aarch64', 'armv8', 'little'), + 'armv8_32': ('aarch64', 'armv8_32', 'little'), + 'armv8.3': ('aarch64', 'armv8.3', 'little'), + 'avr': ('avr', 'avr', 'little'), + 'mips': ('mips', 'mips', 'big'), + 'mips64': ('mips64', 'mips64', 'big'), + 'ppc32be': ('ppc', 'ppc', 'big'), + 'ppc32': ('ppc', 'ppc', 'little'), + 'ppc64le': ('ppc64', 'ppc64', 'little'), + 'ppc64': ('ppc64', 'ppc64', 'big'), + 's390': ('s390', 's390', 'big'), + 's390x': ('s390x', 's390x', 'big'), + 'sh4le': ('sh4', 'sh4', 'little'), + 'sparc': ('sparc', 'sparc', 'big'), + 'sparcv9': ('sparc64', 'sparc64', 'big'), + 'wasm': ('wasm32', 'wasm32', 'little'), + 'x86': ('x86', 'x86', 'little'), + 'x86_64': ('x86_64', 'x86_64', 'little')} + system = system_map.get(machine_os, machine_os.lower()) + default_cpu_tuple = (machine_arch.lower(), machine_arch.lower(), 'little') + cpu_tuple = cpu_family_map.get(machine_arch, default_cpu_tuple) + cpu_family, cpu, endian = cpu_tuple[0], cpu_tuple[1], cpu_tuple[2] + context = { + 'system': self._to_meson_value(system), + 'cpu_family': self._to_meson_value(cpu_family), + 'cpu': self._to_meson_value(cpu), + 'endian': self._to_meson_value(endian), + } + return self._render(self._machine_template, context) + + @property + def _cross_content(self): + os_build, arch_build, os_host, arch_host = get_cross_building_settings(self._conanfile) + os_target, arch_target = os_host, arch_host # TODO: assume target the same as a host for now? + + build_machine = self._to_meson_machine(os_build, arch_build) + host_machine = self._to_meson_machine(os_host, arch_host) + target_machine = self._to_meson_machine(os_target, arch_target) + + context = self._context + context['build_machine'] = build_machine + context['host_machine'] = host_machine + context['target_machine'] = target_machine + return self._render(self._cross_file_template, context) + + def _write_native_file(self): + save(self.native_filename, self._native_content) + + def _write_cross_file(self): + save(self.cross_filename, self._cross_content) + + def generate(self): + if cross_building(self._conanfile): + self._write_cross_file() + else: + self._write_native_file() diff --git a/conans/client/generators/pkg_config.py b/conans/client/generators/pkg_config.py index ec902b92c4f..079d354d09e 100644 --- a/conans/client/generators/pkg_config.py +++ b/conans/client/generators/pkg_config.py @@ -86,7 +86,7 @@ def _pc_file_content(self, name, cpp_info, requires_gennames): description = cpp_info.description or "Conan package: %s" % name lines.append("Description: %s" % description) lines.append("Version: %s" % cpp_info.version) - libdirs_flags = ["-L${%s}" % name for name in libdir_vars] + libdirs_flags = ['-L"${%s}"' % name for name in libdir_vars] libnames_flags = ["-l%s " % name for name in (cpp_info.libs + cpp_info.system_libs)] shared_flags = cpp_info.sharedlinkflags + cpp_info.exelinkflags @@ -105,7 +105,7 @@ def _pc_file_content(self, name, cpp_info, requires_gennames): rpaths, frameworks, framework_paths])) - include_dirs_flags = ["-I${%s}" % name for name in includedir_vars] + include_dirs_flags = ['-I"${%s}"' % name for name in includedir_vars] lines.append("Cflags: %s" % _concat_if_not_empty( [include_dirs_flags, diff --git a/conans/test/functional/generators/pkg_config_test.py b/conans/test/functional/generators/pkg_config_test.py index ca79d291267..1a9a459fb05 100644 --- a/conans/test/functional/generators/pkg_config_test.py +++ b/conans/test/functional/generators/pkg_config_test.py @@ -55,8 +55,9 @@ def package_info(self): Name: MyLib Description: Conan package: MyLib Version: 0.1 -Libs: -L${libdir} -L${libdir2}%s -Cflags: -I${includedir}""" % expected_rpaths +Libs: -L"${libdir}" -L"${libdir2}"%s +Cflags: -I"${includedir}"\ +""" % expected_rpaths self.assertEqual("\n".join(pc_content.splitlines()[1:]), expected_content) def assert_is_abs(path): @@ -162,7 +163,7 @@ def package_info(self): client.run("install MyLib/0.1@ -g pkg_config") pc_content = client.load("MyLib.pc") - self.assertIn("Libs: -L${libdir} -lmylib1 -lmylib2 -lsystem_lib1 -lsystem_lib2 ", + self.assertIn('Libs: -L"${libdir}" -lmylib1 -lmylib2 -lsystem_lib1 -lsystem_lib2 ', pc_content) def test_multiple_include(self): @@ -192,8 +193,8 @@ def package_info(self): self.assertIn("includedir3=${prefix}/inc3/foo", pc_content) self.assertIn("libdir=${prefix}/lib1", pc_content) self.assertIn("libdir2=${prefix}/lib2", pc_content) - self.assertIn("Libs: -L${libdir} -L${libdir2}", pc_content) - self.assertIn("Cflags: -I${includedir} -I${includedir2} -I${includedir3}", pc_content) + self.assertIn('Libs: -L"${libdir}" -L"${libdir2}"', pc_content) + self.assertIn('Cflags: -I"${includedir}" -I"${includedir2}" -I"${includedir3}"', pc_content) def test_empty_include(self): client = TestClient() diff --git a/conans/test/integration/toolchains/meson/__init__.py b/conans/test/integration/toolchains/meson/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/conans/test/integration/toolchains/meson/_base.py b/conans/test/integration/toolchains/meson/_base.py new file mode 100644 index 00000000000..0a2f18b2cc1 --- /dev/null +++ b/conans/test/integration/toolchains/meson/_base.py @@ -0,0 +1,69 @@ +import platform +import pytest +import unittest + +from conans.model.version import Version +from conans.test.utils.tools import TestClient +from conans.util.files import decode_text +from conans.util.runners import version_runner + +def get_meson_version(): + try: + out = version_runner(["meson", "--version"]) + version_line = decode_text(out).split('\n', 1)[0] + version_str = version_line.rsplit(' ', 1)[-1] + return Version(version_str) + except Exception: + return Version("0.0.0") + + +@pytest.mark.toolchain +@pytest.mark.tool_meson +@unittest.skipUnless(get_meson_version() >= "0.56.0", "requires meson >= 0.56.0") +class TestMesonBase(unittest.TestCase): + def setUp(self): + self.t = TestClient() + + @property + def _settings(self): + settings_macosx = {"compiler": "apple-clang", + "compiler.libcxx": "libc++", + "compiler.version": "12.0", + "arch": "x86_64", + "build_type": "Release"} + + settings_windows = {"compiler": "Visual Studio", + "compiler.version": "15", + "compiler.runtime": "MD", + "arch": "x86_64", + "build_type": "Release"} + + settings_linux = {"compiler": "gcc", + "compiler.version": "5", + "compiler.libcxx": "libstdc++", + "arch": "x86_64", + "build_type": "Release"} + + return {"Darwin": settings_macosx, + "Windows": settings_windows, + "Linux": settings_linux}.get(platform.system()) + + @property + def _settings_str(self): + return " ".join('-s %s="%s"' % (k, v) for k, v in self._settings.items() if v) + + def _check_binary(self): + if platform.system() == "Darwin": + self.assertIn("main __x86_64__ defined", self.t.out) + self.assertIn("main __apple_build_version__", self.t.out) + self.assertIn("main __clang_major__12", self.t.out) + # TODO: check why __clang_minor__ seems to be not defined in XCode 12 + # commented while migrating to XCode12 CI + # self.assertIn("main __clang_minor__0", self.t.out) + elif platform.system() == "Windows": + self.assertIn("main _M_X64 defined", self.t.out) + self.assertIn("main _MSC_VER19", self.t.out) + self.assertIn("main _MSVC_LANG2014", self.t.out) + elif platform.system() == "Linux": + self.assertIn("main __x86_64__ defined", self.t.out) + self.assertIn("main __GNUC__5", self.t.out) diff --git a/conans/test/integration/toolchains/android/test_using_meson.py b/conans/test/integration/toolchains/meson/test_android.py similarity index 92% rename from conans/test/integration/toolchains/android/test_using_meson.py rename to conans/test/integration/toolchains/meson/test_android.py index 62399706340..c756e8375d6 100644 --- a/conans/test/integration/toolchains/android/test_using_meson.py +++ b/conans/test/integration/toolchains/meson/test_android.py @@ -7,10 +7,9 @@ from parameterized import parameterized from conans.test.assets.sources import gen_function_cpp, gen_function_h +from conans.test.integration.toolchains.meson._base import get_meson_version from conans.test.utils.tools import TestClient -from conans.test.integration.toolchains.test_meson import get_meson_version - @pytest.mark.toolchain @pytest.mark.tool_meson @@ -19,7 +18,7 @@ class AndroidToolchainMesonTestCase(unittest.TestCase): _conanfile_py = textwrap.dedent(""" from conans import ConanFile, tools - from conan.tools.meson import MesonToolchain + from conan.tools.meson import Meson, MesonToolchain class App(ConanFile): @@ -31,15 +30,14 @@ def config_options(self): if self.settings.os == "Windows": del self.options.fPIC - def toolchain(self): + def generate(self): tc = MesonToolchain(self) tc.generate() def build(self): - # this will be moved to build helper eventually - with tools.vcvars(self) if self.settings.compiler == "Visual Studio" else tools.no_op(): - self.run("meson setup --cross-file conan_meson_cross.ini build .") - self.run("meson compile -C build") + meson = Meson(self) + meson.configure() + meson.build() """) _meson_build = textwrap.dedent(""" diff --git a/conans/test/integration/toolchains/meson/test_install.py b/conans/test/integration/toolchains/meson/test_install.py new file mode 100644 index 00000000000..db37eac1cd1 --- /dev/null +++ b/conans/test/integration/toolchains/meson/test_install.py @@ -0,0 +1,102 @@ +import os +import textwrap + +from conans.test.assets.sources import gen_function_cpp, gen_function_h +from conans.test.integration.toolchains.meson._base import TestMesonBase + + +class MesonInstall(TestMesonBase): + _conanfile_py = textwrap.dedent(""" + import os + import shutil + from conans import ConanFile, tools + from conan.tools.meson import Meson, MesonToolchain + + + class App(ConanFile): + settings = "os", "arch", "compiler", "build_type" + options = {"shared": [True, False], "fPIC": [True, False]} + default_options = {"shared": False, "fPIC": True} + exports_sources = "meson.build", "hello.cpp", "hello.h" + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def generate(self): + tc = MesonToolchain(self) + # https://mesonbuild.com/Release-notes-for-0-50-0.html#libdir-defaults-to-lib-when-cross-compiling + tc.definitions["libdir"] = "lib" + tc.generate() + + def build(self): + meson = Meson(self) + meson.configure() + meson.build() + + def package(self): + meson = Meson(self) + meson.configure() + meson.install() + + # https://mesonbuild.com/FAQ.html#why-does-building-my-project-with-msvc-output-static-libraries-called-libfooa + if self.settings.compiler == 'Visual Studio' and not self.options.shared: + shutil.move(os.path.join(self.package_folder, "lib", "libhello.a"), + os.path.join(self.package_folder, "lib", "hello.lib")) + + def package_info(self): + self.cpp_info.libs = ['hello'] + """) + + _meson_build = textwrap.dedent(""" + project('tutorial', 'cpp') + library('hello', 'hello.cpp', install: true) + install_headers('hello.h') + """) + + _test_package_conanfile_py = textwrap.dedent(""" + import os + from conans import ConanFile, CMake, tools + + + class TestConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "cmake" + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def test(self): + if not tools.cross_building(self): + self.run(os.path.join("bin", "test_package"), run_environment=True) + """) + + _test_package_cmake_lists = textwrap.dedent(""" + cmake_minimum_required(VERSION 3.1) + project(test_package CXX) + + include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) + conan_basic_setup() + + add_executable(${PROJECT_NAME} test_package.cpp) + target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS}) + """) + + def test_install(self): + hello_cpp = gen_function_cpp(name="hello") + hello_h = gen_function_h(name="hello") + test_package_cpp = gen_function_cpp(name="main", includes=["hello"], calls=["hello"]) + + self.t.save({"conanfile.py": self._conanfile_py, + "meson.build": self._meson_build, + "hello.cpp": hello_cpp, + "hello.h": hello_h, + os.path.join("test_package", "conanfile.py"): self._test_package_conanfile_py, + os.path.join("test_package", "CMakeLists.txt"): self._test_package_cmake_lists, + os.path.join("test_package", "test_package.cpp"): test_package_cpp}) + + self.t.run("create . hello/0.1@ %s" % self._settings_str) + + self._check_binary() diff --git a/conans/test/integration/toolchains/ios/test_using_meson.py b/conans/test/integration/toolchains/meson/test_ios.py similarity index 90% rename from conans/test/integration/toolchains/ios/test_using_meson.py rename to conans/test/integration/toolchains/meson/test_ios.py index 81a602cf012..540b4615b2a 100644 --- a/conans/test/integration/toolchains/ios/test_using_meson.py +++ b/conans/test/integration/toolchains/meson/test_ios.py @@ -8,10 +8,9 @@ from conans.client.tools.apple import XCRun, apple_deployment_target_flag, to_apple_arch from conans.test.assets.sources import gen_function_cpp, gen_function_h +from conans.test.integration.toolchains.meson._base import get_meson_version from conans.test.utils.tools import TestClient -from conans.test.integration.toolchains.test_meson import get_meson_version - @pytest.mark.toolchain @pytest.mark.tool_meson @@ -21,7 +20,7 @@ class IOSMesonTestCase(unittest.TestCase): _conanfile_py = textwrap.dedent(""" from conans import ConanFile, tools - from conan.tools.meson import MesonToolchain + from conan.tools.meson import Meson, MesonToolchain class App(ConanFile): @@ -33,15 +32,14 @@ def config_options(self): if self.settings.os == "Windows": del self.options.fPIC - def toolchain(self): + def generate(self): tc = MesonToolchain(self) tc.generate() def build(self): - # this will be moved to build helper eventually - with tools.vcvars(self) if self.settings.compiler == "Visual Studio" else tools.no_op(): - self.run("meson setup --cross-file conan_meson_cross.ini build .") - self.run("meson compile -C build") + meson = Meson(self) + meson.configure() + meson.build() """) _meson_build = textwrap.dedent(""" diff --git a/conans/test/integration/toolchains/test_meson.py b/conans/test/integration/toolchains/meson/test_meson.py similarity index 50% rename from conans/test/integration/toolchains/test_meson.py rename to conans/test/integration/toolchains/meson/test_meson.py index f13e43e7345..18601fd5641 100644 --- a/conans/test/integration/toolchains/test_meson.py +++ b/conans/test/integration/toolchains/meson/test_meson.py @@ -1,33 +1,14 @@ import os -import platform -import pytest import textwrap -import unittest -from conans.model.version import Version from conans.test.assets.sources import gen_function_cpp, gen_function_h -from conans.test.utils.tools import TestClient -from conans.util.files import decode_text -from conans.util.runners import version_runner +from conans.test.integration.toolchains.meson._base import TestMesonBase -def get_meson_version(): - try: - out = version_runner(["meson", "--version"]) - version_line = decode_text(out).split('\n', 1)[0] - version_str = version_line.rsplit(' ', 1)[-1] - return Version(version_str) - except Exception: - return Version("0.0.0") - - -@pytest.mark.toolchain -@pytest.mark.tool_meson -@unittest.skipUnless(get_meson_version() >= "0.56.0", "requires meson >= 0.56.0") -class MesonToolchainTest(unittest.TestCase): +class MesonToolchainTest(TestMesonBase): _conanfile_py = textwrap.dedent(""" from conans import ConanFile, tools - from conan.tools.meson import MesonToolchain + from conan.tools.meson import Meson, MesonToolchain class App(ConanFile): @@ -39,7 +20,7 @@ def config_options(self): if self.settings.os == "Windows": del self.options.fPIC - def toolchain(self): + def generate(self): tc = MesonToolchain(self) tc.definitions["STRING_DEFINITION"] = "Text" tc.definitions["TRUE_DEFINITION"] = True @@ -49,10 +30,9 @@ def toolchain(self): tc.generate() def build(self): - # this will be moved to build helper eventually - with tools.vcvars(self) if self.settings.compiler == "Visual Studio" else tools.no_op(): - self.run("meson setup --native-file conan_meson_native.ini build .") - self.run("meson compile -C build") + meson = Meson(self) + meson.configure() + meson.build() """) _meson_options_txt = textwrap.dedent(""" @@ -73,52 +53,7 @@ def build(self): executable('demo', 'main.cpp', link_with: hello) """) - @unittest.skipUnless(platform.system() == "Darwin", "Only for Apple") - def test_macosx(self): - settings = {"compiler": "apple-clang", - "compiler.libcxx": "libc++", - "compiler.version": "12.0", - "arch": "x86_64", - "build_type": "Release"} - self._build(settings) - - self.assertIn("main __x86_64__ defined", self.t.out) - self.assertIn("main __apple_build_version__", self.t.out) - self.assertIn("main __clang_major__12", self.t.out) - # TODO: check why __clang_minor__ seems to be not defined in XCode 12 - # commented while migrating to XCode12 CI - #self.assertIn("main __clang_minor__0", self.t.out) - - @unittest.skipUnless(platform.system() == "Windows", "Only for windows") - def test_win32(self): - settings = {"compiler": "Visual Studio", - "compiler.version": "15", - "compiler.runtime": "MD", - "arch": "x86_64", - "build_type": "Release"} - self._build(settings) - - self.assertIn("main _M_X64 defined", self.t.out) - self.assertIn("main _MSC_VER19", self.t.out) - self.assertIn("main _MSVC_LANG2014", self.t.out) - - @unittest.skipUnless(platform.system() == "Linux", "Only for Linux") - def test_linux(self): - setttings = {"compiler": "gcc", - "compiler.version": "5", - "compiler.libcxx": "libstdc++", - "arch": "x86_64", - "build_type": "Release"} - self._build(setttings) - - self.assertIn("main __x86_64__ defined", self.t.out) - self.assertIn("main __GNUC__5", self.t.out) - - def _build(self, settings): - self.t = TestClient() - - settings_str = " ".join('-s %s="%s"' % (k, v) for k, v in settings.items() if v) - + def test_build(self): hello_h = gen_function_h(name="hello") hello_cpp = gen_function_cpp(name="hello", preprocessor=["STRING_DEFINITION"]) app = gen_function_cpp(name="main", includes=["hello"], calls=["hello"]) @@ -130,7 +65,7 @@ def _build(self, settings): "hello.cpp": hello_cpp, "main.cpp": app}) - self.t.run("install . %s" % settings_str) + self.t.run("install . %s" % self._settings_str) content = self.t.load("conan_meson_native.ini") @@ -149,3 +84,5 @@ def _build(self, settings): self.assertIn("hello: Release!", self.t.out) self.assertIn("STRING_DEFINITION: Text", self.t.out) + + self._check_binary() diff --git a/conans/test/integration/toolchains/meson/test_pkg_config_reuse.py b/conans/test/integration/toolchains/meson/test_pkg_config_reuse.py new file mode 100644 index 00000000000..7fe9d9381ea --- /dev/null +++ b/conans/test/integration/toolchains/meson/test_pkg_config_reuse.py @@ -0,0 +1,58 @@ +import os +import pytest +import textwrap + +from conans.test.assets.sources import gen_function_cpp +from conans.test.integration.toolchains.meson._base import TestMesonBase + + +@pytest.mark.tool_pkg_config +class MesonPkgConfigTest(TestMesonBase): + _conanfile_py = textwrap.dedent(""" + from conans import ConanFile, tools + from conan.tools.meson import Meson, MesonToolchain + + + class App(ConanFile): + settings = "os", "arch", "compiler", "build_type" + generators = "pkg_config" + requires = "hello/0.1" + + def generate(self): + tc = MesonToolchain(self) + tc.generate() + + def build(self): + meson = Meson(self) + meson.configure() + meson.build() + """) + + _meson_build = textwrap.dedent(""" + project('tutorial', 'cpp') + hello = dependency('hello', version : '>=0.1') + executable('demo', 'main.cpp', dependencies: hello) + """) + + def test_reuse(self): + self.t.run("new hello/0.1 -s") + self.t.run("create . hello/0.1@ %s" % self._settings_str) + + app = gen_function_cpp(name="main", includes=["hello"], calls=["hello"]) + + # Prepare the actual consumer package + self.t.save({"conanfile.py": self._conanfile_py, + "meson.build": self._meson_build, + "main.cpp": app}, + clean_first=True) + + # Build in the cache + self.t.run("install . %s" % self._settings_str) + self.assertIn("conanfile.py: Generator pkg_config created hello.pc", self.t.out) + + self.t.run("build .") + self.t.run_command(os.path.join("build", "demo")) + + self.assertIn("Hello World Release!", self.t.out) + + self._check_binary() diff --git a/conans/test/integration/toolchains/meson/test_test.py b/conans/test/integration/toolchains/meson/test_test.py new file mode 100644 index 00000000000..59c9f72ea93 --- /dev/null +++ b/conans/test/integration/toolchains/meson/test_test.py @@ -0,0 +1,54 @@ +import os +import pytest +import textwrap + +from conans.test.assets.sources import gen_function_cpp +from conans.test.integration.toolchains.meson._base import TestMesonBase + + +@pytest.mark.tool_pkg_config +class MesonTest(TestMesonBase): + _test_package_meson_build = textwrap.dedent(""" + project('test_package', 'cpp') + hello = dependency('hello', version : '>=0.1') + test_package = executable('test_package', 'test_package.cpp', dependencies: hello) + test('test package', test_package) + """) + + _test_package_conanfile_py = textwrap.dedent(""" + import os + from conans import ConanFile + from conan.tools.meson import Meson, MesonToolchain + + + class TestConan(ConanFile): + settings = "os", "compiler", "build_type", "arch" + generators = "pkg_config" + + def generate(self): + tc = MesonToolchain(self) + tc.generate() + + def build(self): + meson = Meson(self) + meson.configure() + meson.build() + + def test(self): + meson = Meson(self) + meson.configure() + meson.test() + """) + + def test_reuse(self): + self.t.run("new hello/0.1 -s") + + test_package_cpp = gen_function_cpp(name="main", includes=["hello"], calls=["hello"]) + + self.t.save({os.path.join("test_package", "conanfile.py"): self._test_package_conanfile_py, + os.path.join("test_package", "meson.build"): self._test_package_meson_build, + os.path.join("test_package", "test_package.cpp"): test_package_cpp}) + + self.t.run("create . hello/0.1@ %s" % self._settings_str) + + self._check_binary() diff --git a/conans/test/unittests/client/generators/pkg_config_test.py b/conans/test/unittests/client/generators/pkg_config_test.py index cc21c677a69..77e59a061da 100644 --- a/conans/test/unittests/client/generators/pkg_config_test.py +++ b/conans/test/unittests/client/generators/pkg_config_test.py @@ -56,8 +56,8 @@ def test_variables_setup(self): Name: MyPkg2 Description: Conan package: MyPkg2 Version: 2.3 -Libs: -L${libdir} -sharedlinkflag -exelinkflag -Cflags: -I${includedir} -cxxflag -DMYDEFINE2 +Libs: -L"${libdir}" -sharedlinkflag -exelinkflag +Cflags: -I"${includedir}" -cxxflag -DMYDEFINE2 Requires: my_pkg """) @@ -68,8 +68,8 @@ def test_variables_setup(self): Name: mypkg1 Description: My other cool description Version: 1.7 -Libs: -L${libdir} -Cflags: -I${includedir} -Flag1=21 -DMYDEFINE11 +Libs: -L"${libdir}" +Cflags: -I"${includedir}" -Flag1=21 -DMYDEFINE11 Requires: my_pkg """) @@ -80,8 +80,8 @@ def test_variables_setup(self): Name: my_pkg Description: My cool description Version: 1.3 -Libs: -L${libdir} -Cflags: -I${includedir} -Flag1=23 -DMYDEFINE1 +Libs: -L"${libdir}" +Cflags: -I"${includedir}" -Flag1=23 -DMYDEFINE1 """) def test_pkg_config_custom_names(self): @@ -152,8 +152,8 @@ def test_pkg_config_custom_names(self): Name: my_pkg2_custom_name Description: Conan package: my_pkg2_custom_name Version: 2.3 -Libs: -L${libdir} -sharedlinkflag -exelinkflag -Cflags: -I${includedir} -cxxflag -DMYDEFINE2 +Libs: -L"${libdir}" -sharedlinkflag -exelinkflag +Cflags: -I"${includedir}" -cxxflag -DMYDEFINE2 Requires: my_pkg_custom_name my_pkg1_custom_name """) self.assertEqual(files["my_pkg1_custom_name.pc"], """prefix=/dummy_root_folder1 @@ -163,8 +163,8 @@ def test_pkg_config_custom_names(self): Name: my_pkg1_custom_name Description: My other cool description Version: 1.7 -Libs: -L${libdir} -Cflags: -I${includedir} -Flag1=21 -DMYDEFINE11 +Libs: -L"${libdir}" +Cflags: -I"${includedir}" -Flag1=21 -DMYDEFINE11 """) self.assertEqual(files["my_pkg_custom_name.pc"], """prefix=/dummy_root_folder1 libdir=${prefix}/lib @@ -173,8 +173,8 @@ def test_pkg_config_custom_names(self): Name: my_pkg_custom_name Description: My cool description Version: 1.3 -Libs: -L${libdir} -Cflags: -I${includedir} -Flag1=23 -DMYDEFINE1 +Libs: -L"${libdir}" +Cflags: -I"${includedir}" -Flag1=23 -DMYDEFINE1 """) self.assertEqual(files["BZip2.pc"], """prefix=/dummy_root_folder2 libdir=${prefix}/lib @@ -183,8 +183,8 @@ def test_pkg_config_custom_names(self): Name: BZip2 Description: Conan package: BZip2 Version: 2.3 -Libs: -L${libdir} -sharedlinkflag -exelinkflag -Cflags: -I${includedir} -cxxflag -DMYDEFINE2 +Libs: -L"${libdir}" -sharedlinkflag -exelinkflag +Cflags: -I"${includedir}" -cxxflag -DMYDEFINE2 Requires: my_pkg_custom_name my_pkg1_custom_name zlib """) @@ -213,6 +213,6 @@ def test_apple_frameworks(self): Name: MyPkg Description: My cool description Version: 1.3 -Libs: -L${libdir} -Wl,-rpath,"${libdir}" -framework AudioUnit -framework AudioToolbox -F /dummy_root_folder1/Frameworks -Cflags: -I${includedir} +Libs: -L"${libdir}" -Wl,-rpath,"${libdir}" -framework AudioUnit -framework AudioToolbox -F /dummy_root_folder1/Frameworks +Cflags: -I"${includedir}" """)