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

Feature/toolchain cmake cross #9115

Merged
merged 9 commits into from
Jun 21, 2021
Merged
63 changes: 61 additions & 2 deletions conan/tools/cmake/toolchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def context(self):
if lib:
lib = "-library={}".format(lib)
elif compiler == "gcc":
# we might want to remove this "1", it is the default in most distros
if libcxx == "libstdc++11":
glib = "1"
elif libcxx == "libstdc++":
Expand Down Expand Up @@ -453,6 +454,18 @@ class TryCompileBlock(Block):

class GenericSystemBlock(Block):
template = textwrap.dedent("""
{% if cmake_system_name %}
# Cross building
set(CMAKE_SYSTEM_NAME {{ cmake_system_name }})
{% endif %}
{% if cmake_system_version %}
# Cross building
set(CMAKE_SYSTEM_VERSION {{ cmake_system_version }})
{% endif %}
{% if cmake_system_processor %}
set(CMAKE_SYSTEM_PROCESSOR {{ cmake_system_processor }})
{% endif %}

{% if generator_platform %}
set(CMAKE_GENERATOR_PLATFORM "{{ generator_platform }}" CACHE STRING "" FORCE)
{% endif %}
Expand Down Expand Up @@ -513,25 +526,71 @@ def _get_generator_platform(self, generator):
"armv8": "ARM64"}.get(arch)
return None

def _get_cross_build(self):
user_toolchain = self._conanfile.conf["tools.cmake.cmaketoolchain:user_toolchain"]
if user_toolchain is not None:
return None, None, None # Will be provided by user_toolchain

system_name = self._conanfile.conf["tools.cmake.cmaketoolchain:system_name"]
system_version = self._conanfile.conf["tools.cmake.cmaketoolchain:system_version"]
system_processor = self._conanfile.conf["tools.cmake.cmaketoolchain:system_processor"]

settings = self._conanfile.settings
if hasattr(self._conanfile, "settings_build"):
os_ = settings.get_safe("os")
arch = settings.get_safe("arch")
settings_build = self._conanfile.settings_build
os_build = settings_build.get_safe("os")
arch_build = settings_build.get_safe("arch")

if system_name is None: # Try to deduce
if os_ not in ('Macos', 'iOS', 'watchOS', 'tvOS'): # Handled by AppleBlock
cmake_system_name_map = {"Neutrino": "QNX",
"": "Generic",
None: "Generic"}
if os_ != os_build:
system_name = cmake_system_name_map.get(os_, os_)
elif arch is not None and arch != arch_build:
if not ((arch_build == "x86_64") and (arch == "x86") or
(arch_build == "sparcv9") and (arch == "sparc") or
(arch_build == "ppc64") and (arch == "ppc32")):
system_name = cmake_system_name_map.get(os_, os_)

if system_name is not None and system_version is None:
os_ver_str = "os.api_level" if os_ == "Android" else "os.version"
system_version = settings.get_safe(os_ver_str)

if system_name is not None and system_processor is None:
if arch != arch_build:
system_processor = arch

return system_name, system_version, system_processor

def context(self):
# build_type (Release, Debug, etc) is only defined for single-config generators
generator = self._toolchain.generator
generator_platform = self._get_generator_platform(generator)
toolset = self._get_toolset(generator)
compiler = self._conanfile.settings.get_safe("compiler")
# TODO: Check if really necessary now that conanvcvars is used
if (generator is not None and "Ninja" in generator
and "Visual" in self._conanfile.settings.compiler):
and ("Visual" in compiler or compiler == "msvc")):
compiler = "cl"
else:
compiler = None # compiler defined by default

build_type = self._conanfile.settings.get_safe("build_type")
build_type = build_type if not is_multi_configuration(generator) else None

system_name, system_version, system_processor = self._get_cross_build()

return {"compiler": compiler,
"toolset": toolset,
"generator_platform": generator_platform,
"build_type": build_type}
"build_type": build_type,
"cmake_system_name": system_name,
"cmake_system_version": system_version,
"cmake_system_processor": system_processor}


class ToolchainBlocks:
Expand Down
97 changes: 70 additions & 27 deletions conans/client/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,15 @@ def test(self, *args):
self._check_lockfile_args(args)

profile_build = ProfileData(profiles=args.profile_build, settings=args.settings_build,
options=args.options_build, env=args.env_build)
options=args.options_build, env=args.env_build,
conf=args.conf_build)
# TODO: 2.0 create profile_host object here to avoid passing a lot of arguments to the API

return self._conan.test(args.path, args.reference,
args.profile_host, args.settings_host, args.options_host,
args.env_host, remote_name=args.remote, update=args.update,
build_modes=args.build, test_build_folder=args.test_build_folder,
args.env_host, conf=args.conf_host, remote_name=args.remote,
update=args.update, build_modes=args.build,
test_build_folder=args.test_build_folder,
lockfile=args.lockfile, profile_build=profile_build)

def create(self, *args):
Expand Down Expand Up @@ -369,14 +372,21 @@ def create(self, *args):
info = None
try:
profile_build = ProfileData(profiles=args.profile_build, settings=args.settings_build,
options=args.options_build, env=args.env_build)

info = self._conan.create(args.path, name, version, user, channel,
args.profile_host, args.settings_host, args.options_host,
args.env_host, args.test_folder, args.not_export,
args.build, args.keep_source, args.keep_build, args.verify,
args.manifests, args.manifests_interactive,
args.remote, args.update,
options=args.options_build, env=args.env_build,
conf=args.conf_build)
# TODO: 2.0 create profile_host object here to avoid passing a lot of arguments
# to the API

info = self._conan.create(args.path, name=name, version=version, user=user,
channel=channel, profile_names=args.profile_host,
settings=args.settings_host, conf=args.conf_host,
options=args.options_host, env=args.env_host,
test_folder=args.test_folder, not_export=args.not_export,
build_modes=args.build, keep_source=args.keep_source,
keep_build=args.keep_build, verify=args.verify,
manifests=args.manifests,
manifests_interactive=args.manifests_interactive,
remote_name=args.remote, update=args.update,
test_build_folder=args.test_build_folder,
lockfile=args.lockfile,
lockfile_out=args.lockfile_out,
Expand Down Expand Up @@ -491,7 +501,9 @@ def install(self, *args):
self._check_lockfile_args(args)

profile_build = ProfileData(profiles=args.profile_build, settings=args.settings_build,
options=args.options_build, env=args.env_build)
options=args.options_build, env=args.env_build,
conf=args.conf_build)
# TODO: 2.0 create profile_host object here to avoid passing a lot of arguments to the API

cwd = os.getcwd()

Expand All @@ -507,6 +519,7 @@ def install(self, *args):
name=name, version=version, user=user, channel=channel,
settings=args.settings_host, options=args.options_host,
env=args.env_host, profile_names=args.profile_host,
conf=args.conf_host,
profile_build=profile_build,
remote_name=args.remote,
verify=args.verify, manifests=args.manifests,
Expand All @@ -528,6 +541,7 @@ def install(self, *args):
settings=args.settings_host,
options=args.options_host,
env=args.env_host,
conf=args.conf_host,
profile_names=args.profile_host,
profile_build=profile_build,
remote_name=args.remote,
Expand Down Expand Up @@ -699,16 +713,18 @@ def info(self, *args):
self._check_lockfile_args(args)

profile_build = ProfileData(profiles=args.profile_build, settings=args.settings_build,
options=args.options_build, env=args.env_build)
options=args.options_build, env=args.env_build,
conf=args.conf_build)
# TODO: 2.0 create profile_host object here to avoid passing a lot of arguments to the API

if args.build_order:
self._out.warn("Usage of `--build-order` argument is deprecated and can return"
" wrong results. Use `conan lock build-order ...` instead.")

if args.install_folder and (args.profile_host or args.settings_host
or args.options_host or args.env_host):
or args.options_host or args.env_host or args.conf_host):
raise ArgumentError(None, "--install-folder cannot be used together with a"
" host profile (-s, -o, -e or -pr)")
" host profile (-s, -o, -e, -pr or -c)")

if args.build_order and args.graph:
raise ArgumentError(None, "--build-order cannot be used together with --graph")
Expand All @@ -720,6 +736,7 @@ def info(self, *args):
options=args.options_host,
env=args.env_host,
profile_names=args.profile_host,
conf=args.conf_host,
profile_build=profile_build,
remote_name=args.remote,
build_order=args.build_order,
Expand All @@ -739,6 +756,7 @@ def info(self, *args):
options=args.options_host,
env=args.env_host,
profile_names=args.profile_host,
conf=args.conf_host,
profile_build=profile_build,
remote_name=args.remote,
check_updates=args.update,
Expand All @@ -757,6 +775,7 @@ def info(self, *args):
options=args.options_host,
env=args.env_host,
profile_names=args.profile_host,
conf=args.conf_host,
profile_build=profile_build,
update=args.update,
install_folder=args.install_folder,
Expand Down Expand Up @@ -1015,7 +1034,10 @@ def export_pkg(self, *args):

try:
profile_build = ProfileData(profiles=args.profile_build, settings=args.settings_build,
options=args.options_build, env=args.env_build)
options=args.options_build, env=args.env_build,
conf=args.conf_build)
# TODO: 2.0 create profile_host object here to avoid passing a lot of arguments
# to the API

info = self._conan.export_pkg(conanfile_path=args.path,
name=name,
Expand All @@ -1028,6 +1050,7 @@ def export_pkg(self, *args):
env=args.env_host,
settings=args.settings_host,
options=args.options_host,
conf=args.conf_host,
profile_build=profile_build,
force=args.force,
user=user,
Expand Down Expand Up @@ -1812,12 +1835,20 @@ def workspace(self, *args):
raise ConanException("lockfile_out cannot be specified if lockfile is not defined")

profile_build = ProfileData(profiles=args.profile_build, settings=args.settings_build,
options=args.options_build, env=args.env_build)
options=args.options_build, env=args.env_build,
conf=args.conf_build)
# TODO: 2.0 create profile_host object here to avoid passing a lot of arguments to the API

if args.subcommand == "install":
self._conan.workspace_install(args.path, args.settings_host, args.options_host,
args.env_host, args.remote, args.build,
args.profile_host, args.update,
self._conan.workspace_install(args.path,
settings=args.settings_host,
options=args.options_host,
env=args.env_host,
profile_name=args.profile_host,
conf=args.conf_host,
remote_name=args.remote,
build=args.build,
update=args.update,
profile_build=profile_build,
install_folder=args.install_folder)

Expand Down Expand Up @@ -1987,9 +2018,11 @@ def lock(self, *args):
self._conan.lock_clean_modified(args.lockfile)
elif args.subcommand == "create":
profile_build = ProfileData(profiles=args.profile_build, settings=args.settings_build,
options=args.options_build, env=args.env_build)
options=args.options_build, env=args.env_build,
conf=args.conf_build)
profile_host = ProfileData(profiles=args.profile_host, settings=args.settings_host,
options=args.options_host, env=args.env_host)
options=args.options_host, env=args.env_host,
conf=args.conf_host)

self._conan.lock_create(path=args.path,
reference=args.reference,
Expand Down Expand Up @@ -2092,12 +2125,12 @@ def _print_similar(self, command):
@staticmethod
def _check_lockfile_args(args):
if args.lockfile and (args.profile_build or args.settings_build or args.options_build or
args.env_build):
raise ConanException("Cannot use profile, settings, options or env 'build' when "
args.env_build or args.conf_build):
raise ConanException("Cannot use profile, settings, options, env or conf 'build' when "
"using lockfile")
if args.lockfile and (args.profile_host or args.settings_host or args.options_host or
args.env_host):
raise ConanException("Cannot use profile, settings, options or env 'host' when "
args.env_host or args.conf_host):
raise ConanException("Cannot use profile, settings, options, env or conf 'host' when "
"using lockfile")
if args.lockfile_out and not args.lockfile:
raise ConanException("lockfile_out cannot be specified if lockfile is not defined")
Expand Down Expand Up @@ -2277,7 +2310,17 @@ def settings_args(machine, short_suffix="", long_suffix=""):
' ({} machine). e.g.: -s{} compiler=gcc'.format(machine,
short_suffix))

for item_fn in [environment_args, options_args, profile_args, settings_args]:
def conf_args(machine, short_suffix="", long_suffix=""):
parser.add_argument("-c{}".format(short_suffix),
"--conf{}".format(long_suffix),
nargs=1, action=Extender,
dest='conf_{}'.format(machine),
help='Configuration to build the package, overwriting the defaults'
' ({} machine). e.g.: -c{} '
'tools.cmake.cmaketoolchain:generator=Xcode'.format(machine,
short_suffix))

for item_fn in [environment_args, options_args, profile_args, settings_args, conf_args]:
item_fn("host", "", "") # By default it is the HOST, the one we are building binaries for
item_fn("build", ":b", ":build")
item_fn("host", ":h", ":host")
Expand Down