Skip to content

Commit

Permalink
[MesonToolchain] Added Objective-C/C++ arguments (#11632)
Browse files Browse the repository at this point in the history
* Added Objective-C/C++ arguments and simple test

* Initializing variables only if apple. Added new native test one
  • Loading branch information
franramirez688 committed Jul 14, 2022
1 parent b0c993a commit d5f2e29
Show file tree
Hide file tree
Showing 2 changed files with 187 additions and 7 deletions.
53 changes: 46 additions & 7 deletions conan/tools/meson/toolchain.py
Expand Up @@ -40,6 +40,10 @@ class MesonToolchain(object):
[binaries]
{% if c %}c = '{{c}}'{% endif %}
{% if cpp %}cpp = '{{cpp}}'{% endif %}
{% if is_apple_system %}
{% 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 %}
Expand All @@ -57,11 +61,19 @@ class MesonToolchain(object):
{% 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 %}
# C/C++ arguments
c_args = {{c_args}} + preprocessor_definitions + deps_c_args
c_link_args = {{c_link_args}} + deps_c_link_args
cpp_args = {{cpp_args}} + preprocessor_definitions + deps_cpp_args
cpp_link_args = {{cpp_link_args}} + deps_cpp_link_args
{% if pkg_config_path %}pkg_config_path = '{{pkg_config_path}}'{% endif %}
{% if is_apple_system %}
# Objective-C/C++ arguments
objc_args = {{objc_args}} + preprocessor_definitions + deps_c_args
objc_link_args = {{objc_link_args}} + deps_c_link_args
objcpp_args = {{objcpp_args}} + preprocessor_definitions + deps_cpp_args
objcpp_link_args = {{objcpp_link_args}} + deps_cpp_link_args
{% endif %}
{% for context, values in cross_build.items() %}
[{{context}}_machine]
Expand All @@ -75,6 +87,7 @@ class MesonToolchain(object):
def __init__(self, conanfile, backend=None):
self._conanfile = conanfile
self._os = self._conanfile.settings.get_safe("os")
self._is_apple_system = is_apple_os(self._os)

# 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
Expand Down Expand Up @@ -161,16 +174,22 @@ def __init__(self, conanfile, backend=None):
self.cpp_args = self._get_env_list(build_env.get("CXXFLAGS", []))
self.cpp_link_args = self._get_env_list(build_env.get("LDFLAGS", []))

# Apple flags
# Apple flags and variables
self.apple_arch_flag = []
self.apple_isysroot_flag = []
self.apple_min_version_flag = []

self._resolve_apple_flags()
self.objc = None
self.objcpp = None
self.objc_args = []
self.objc_link_args = []
self.objcpp_args = []
self.objcpp_link_args = []

self._resolve_apple_flags_and_variables(build_env)
self._resolve_android_cross_compilation()

def _resolve_apple_flags(self):
if not is_apple_os(self._os):
def _resolve_apple_flags_and_variables(self, build_env):
if not self._is_apple_system:
return
# SDK path is mandatory for cross-building
sdk_path = self._conanfile.conf.get("tools.apple:sdk_path")
Expand All @@ -187,6 +206,13 @@ def _resolve_apple_flags(self):
self.apple_arch_flag = ["-arch", arch] if arch else []
self.apple_isysroot_flag = ["-isysroot", sdk_path] if sdk_path else []
self.apple_min_version_flag = [apple_min_version_flag(self._conanfile)]
# Objective C/C++ ones
self.objc = "clang"
self.objcpp = "clang++"
self.objc_args = self._get_env_list(build_env.get('OBJCFLAGS', []))
self.objc_link_args = self._get_env_list(build_env.get('LDFLAGS', []))
self.objcpp_args = self._get_env_list(build_env.get('OBJCXXFLAGS', []))
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":
Expand Down Expand Up @@ -238,6 +264,12 @@ def _context(self):
self.cpp_args.extend(apple_flags + extra_flags["cxxflags"])
self.c_link_args.extend(apple_flags + extra_flags["ldflags"])
self.cpp_link_args.extend(apple_flags + extra_flags["ldflags"])
# Objective C/C++
self.objc_args.extend(self.c_args)
self.objcpp_args.extend(self.cpp_args)
# These link_args have already the LDFLAGS env value so let's add only the new possible ones
self.objc_link_args.extend(apple_flags + extra_flags["ldflags"])
self.objcpp_link_args.extend(apple_flags + extra_flags["ldflags"])

return {
# https://mesonbuild.com/Machine-files.html#properties
Expand All @@ -250,6 +282,8 @@ def _context(self):
# https://mesonbuild.com/Reference-tables.html#compiler-and-linker-selection-variables
"c": self.c,
"cpp": self.cpp,
"objc": self.objc,
"objcpp": self.objcpp,
"c_ld": self.c_ld,
"cpp_ld": self.cpp_ld,
"ar": self.ar,
Expand All @@ -271,9 +305,14 @@ def _context(self):
"c_link_args": to_meson_value(self._filter_list_empty_fields(self.c_link_args)),
"cpp_args": to_meson_value(self._filter_list_empty_fields(self.cpp_args)),
"cpp_link_args": to_meson_value(self._filter_list_empty_fields(self.cpp_link_args)),
"objc_args": to_meson_value(self._filter_list_empty_fields(self.objc_args)),
"objc_link_args": to_meson_value(self._filter_list_empty_fields(self.objc_link_args)),
"objcpp_args": to_meson_value(self._filter_list_empty_fields(self.objcpp_args)),
"objcpp_link_args": to_meson_value(self._filter_list_empty_fields(self.objcpp_link_args)),
"pkg_config_path": self.pkg_config_path,
"preprocessor_definitions": self.preprocessor_definitions,
"cross_build": self.cross_build
"cross_build": self.cross_build,
"is_apple_system": self._is_apple_system
}

@property
Expand Down
141 changes: 141 additions & 0 deletions conans/test/functional/toolchains/meson/test_meson_and_objc.py
@@ -0,0 +1,141 @@
import os
import platform
import sys
import textwrap

import pytest

from conans.client.tools.apple import XCRun, to_apple_arch
from conans.test.utils.tools import TestClient

_conanfile_py = textwrap.dedent("""
from conan import ConanFile
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}
def layout(self):
self.folders.build = "build"
def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC
def generate(self):
tc = MesonToolchain(self)
tc.generate()
def build(self):
meson = Meson(self)
meson.configure()
meson.build()
""")

_meson_build_objc = textwrap.dedent("""
project('tutorial', 'objc')
executable('demo', 'main.m', link_args: ['-framework', 'Foundation'])
""")


@pytest.mark.tool_meson
@pytest.mark.skipif(sys.version_info.major == 2, reason="Meson not supported in Py2")
@pytest.mark.skipif(platform.system() != "Darwin", reason="requires Xcode")
def test_apple_meson_toolchain_native_compilation_objective_c():
profile = textwrap.dedent("""
[settings]
os = Macos
arch = x86_64
compiler = apple-clang
compiler.version = 12.0
compiler.libcxx = libc++
""")
app = textwrap.dedent("""
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
""")
t = TestClient()
t.save({"conanfile.py": _conanfile_py,
"meson.build": _meson_build_objc,
"main.m": app,
"macos_pr": profile})

t.run("install . -pr macos_pr")
t.run("build .")
t.run_command("./demo", cwd=os.path.join(t.current_folder, "build"))
assert "Hello, World!" in t.out


@pytest.mark.parametrize("arch, os_, os_version, sdk", [
('armv8', 'iOS', '10.0', 'iphoneos'),
('armv7', 'iOS', '10.0', 'iphoneos'),
('x86', 'iOS', '10.0', 'iphonesimulator'),
('x86_64', 'iOS', '10.0', 'iphonesimulator'),
('armv8', 'Macos', None, None) # MacOS M1
])
@pytest.mark.tool_meson
@pytest.mark.skipif(sys.version_info.major == 2, reason="Meson not supported in Py2")
@pytest.mark.skipif(platform.system() != "Darwin", reason="requires Xcode")
def test_apple_meson_toolchain_cross_compiling_and_objective_c(arch, os_, os_version, sdk):
profile = textwrap.dedent("""
include(default)
[settings]
os = {os}
os.version = {os_version}
os.sdk = {os_sdk}
arch = {arch}
compiler = apple-clang
compiler.version = 12.0
compiler.libcxx = libc++
[conf]
tools.apple:sdk_path={sdk_path}
""")

xcrun = XCRun(None, sdk)
sdk_path = xcrun.sdk_path
app = textwrap.dedent("""
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSLog(@"Hello, World!");
}
return 0;
}
""")
profile = profile.format(
os=os_,
os_version=os_version,
os_sdk=sdk,
arch=arch,
sdk_path=sdk_path)

t = TestClient()
t.save({"conanfile.py": _conanfile_py,
"meson.build": _meson_build_objc,
"main.m": app,
"profile_host": profile})

t.run("install . --profile:build=default --profile:host=profile_host")
t.run("build .")
assert "Objective-C compiler for the host machine: clang" in t.out

demo = os.path.join(t.current_folder, "build", "demo")
assert os.path.isfile(demo) is True

lipo = xcrun.find('lipo')
t.run_command('"%s" -info "%s"' % (lipo, demo))
assert "architecture: %s" % to_apple_arch(arch) in t.out

0 comments on commit d5f2e29

Please sign in to comment.