Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/Tools/ardupilotwaf/cmake.py
Views: 1798
# encoding: utf-812# Copyright (C) 2015-2016 Intel Corporation. All rights reserved.3#4# This file is free software: you can redistribute it and/or modify it5# under the terms of the GNU General Public License as published by the6# Free Software Foundation, either version 3 of the License, or7# (at your option) any later version.8#9# This file is distributed in the hope that it will be useful, but10# WITHOUT ANY WARRANTY; without even the implied warranty of11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.12# See the GNU General Public License for more details.13#14# You should have received a copy of the GNU General Public License along15# with this program. If not, see <http://www.gnu.org/licenses/>.1617"""18Waf tool for external builds with cmake. This tool defines the feature19'cmake_build', for building through the cmake interface.2021You can use CMAKE_MIN_VERSION environment variable before loading this tool in22the configuration to set a minimum version required for cmake. Example::2324def configure(cfg):25cfg.env.CMAKE_MIN_VERSION = '3.5.2'26cfg.load('cmake')2728Usage example::2930def build(bld):31# cmake configuration32foo = bld.cmake(33name='foo',34cmake_src='path/to/foosrc', # where is the source tree35cmake_bld='path/to/foobld', # where to generate the build system36cmake_vars=dict(37CMAKE_BUILD_TYPE='Release',38...39),40)4142# cmake build for external target 'bar'43bld(44features='cmake_build',45cmake_config='foo', # this build depends on the cmake generation above defined46cmake_target='bar', # what to pass to option --target of cmake47)4849# cmake build for target 'baz' (syntactic sugar)50foo.build('baz')5152The keys of cmake_vars are sorted so that unnecessary execution is avoided. If53you want to ensure an order in which the variables are passed to cmake, use an54OrderedDict. Example::5556def build(bld):57foo_vars = OrderedDict()58foo_vars['CMAKE_BUILD_TYPE'] = 'Release'59foo_vars['FOO'] = 'value_of_foo'60foo_vars['BAR'] = 'value_of_bar'6162# cmake configuration63foo = bld.cmake(64cmake_vars=foo_vars,65...66)6768There may be cases when you want to establish dependency between other tasks and69the external build system's products (headers and libraries, for example). In70that case, you can specify the specific files in the option 'target' of your71cmake_build task generator. Example::7273def build(bld):74...7576# declaring on target only what I'm interested in77foo.build('baz', target='path/to/foobld/include/baz.h')7879# myprogram.c includes baz.h, so the dependency is (implicitly)80# established81bld.program(target='myprogram', source='myprogram.c')8283# another example84foo.build('another', target='another.txt')8586bld(87rule='${CP} ${SRC} ${TGT}',88source=bld.bldnode.find_or_declare('another.txt'),89target='another_copied.txt',90)919293You can also establish the dependency directly on a task object::9495@feature('myfeature')96def process_myfeature(self):97baz_taskgen = self.bld.get_tgen_by_name('baz')98baz_taskgen.post()99100# every cmake_build taskgen stores its task in cmake_build_task101baz_task = baz_taskgen.cmake_build_task102103tsk = self.create_task('mytask')104105tsk.set_run_after(baz_task)106107# tsk is run whenever baz_task changes its outputs, namely,108# path/to/foobld/include/baz.h109tsk.dep_nodes.extend(baz_task.outputs)110111If your cmake build creates several files (that may be dependency for several112tasks), you can use the parameter cmake_output_patterns. It receives a pattern113or a list of patterns relative to the cmake build directory. After the build114task is run, the files that match those patterns are set as output of the cmake115build task, so that they get a signature. Example::116117def build(bld):118...119120foo.build('baz', cmake_output_patterns='include/*.h')121122...123"""124125from waflib import Context, Node, Task, Utils126from waflib.Configure import conf127from waflib.TaskGen import feature, taskgen_method128129from collections import OrderedDict130import os131import re132import sys133134class cmake_configure_task(Task.Task):135vars = ['CMAKE_BLD_DIR']136run_str = '${CMAKE} ${CMAKE_FLAGS} ${CMAKE_SRC_DIR} ${CMAKE_VARS} ${CMAKE_GENERATOR_OPTION}'137color = 'BLUE'138139def exec_command(self, cmd, **kw):140kw['stdout'] = sys.stdout141return super(cmake_configure_task, self).exec_command(cmd, **kw)142143def uid(self):144if not hasattr(self, 'uid_'):145m = Utils.md5()146def u(s):147m.update(s.encode('utf-8'))148u(self.__class__.__name__)149u(self.env.get_flat('CMAKE_SRC_DIR'))150u(self.env.get_flat('CMAKE_BLD_DIR'))151u(self.env.get_flat('CMAKE_VARS'))152u(self.env.get_flat('CMAKE_FLAGS'))153self.uid_ = m.digest()154155return self.uid_156157def __str__(self):158return self.cmake.name159160def keyword(self):161return 'CMake Configure'162163# Clean cmake configuration164cmake_configure_task._original_run = cmake_configure_task.run165def _cmake_configure_task_run(self):166cmakecache_path = self.outputs[0].abspath()167if os.path.exists(cmakecache_path):168os.remove(cmakecache_path)169self._original_run()170cmake_configure_task.run = _cmake_configure_task_run171172class cmake_build_task(Task.Task):173run_str = '${CMAKE} --build ${CMAKE_BLD_DIR} --target ${CMAKE_TARGET}'174color = 'BLUE'175# the cmake-generated build system is responsible of managing its own176# dependencies177always_run = True178179def exec_command(self, cmd, **kw):180kw['stdout'] = sys.stdout181return super(cmake_build_task, self).exec_command(cmd, **kw)182183def uid(self):184if not hasattr(self, 'uid_'):185m = Utils.md5()186def u(s):187m.update(s.encode('utf-8'))188u(self.__class__.__name__)189u(self.env.get_flat('CMAKE_BLD_DIR'))190u(self.env.get_flat('CMAKE_TARGET'))191self.uid_ = m.digest()192193return self.uid_194195def __str__(self):196return '%s %s' % (self.cmake.name, self.cmake_target)197198def keyword(self):199return 'CMake Build'200201cmake_build_task.original_post_run = cmake_build_task.post_run202def _cmake_build_task_post_run(self):203self.output_patterns = Utils.to_list(self.output_patterns)204if not self.output_patterns:205return self.original_post_run()206bldnode = self.cmake.bldnode207for node in bldnode.ant_glob(self.output_patterns, remove=False):208self.set_outputs(node)209return self.original_post_run()210cmake_build_task.post_run = _cmake_build_task_post_run211212class CMakeConfig(object):213'''214CMake configuration. This object shouldn't be instantiated directly. Use215bld.cmake().216'''217def __init__(self, bld, name, srcnode, bldnode, cmake_vars, cmake_flags):218self.bld = bld219self.name = name220self.srcnode = srcnode221self.bldnode = bldnode222self.vars = cmake_vars223self.flags = cmake_flags224225self._config_task = None226self.last_build_task = None227228def vars_keys(self):229keys = list(self.vars.keys())230if not isinstance(self.vars, OrderedDict):231keys.sort()232return keys233234def config_sig(self):235m = Utils.md5()236def u(s):237m.update(s.encode('utf-8'))238u(self.srcnode.abspath())239u(self.bldnode.abspath())240for v in self.flags:241u(v)242keys = self.vars_keys()243for k in keys:244u(k)245u(self.vars[k])246return m.digest()247248def config_task(self, taskgen):249sig = self.config_sig()250if self._config_task and self._config_task.cmake_config_sig == sig:251return self._config_task252253self._config_task = taskgen.create_task('cmake_configure_task')254self._config_task.cwd = self.bldnode255self._config_task.cmake = self256self._config_task.cmake_config_sig = sig257258env = self._config_task.env259env.CMAKE_BLD_DIR = self.bldnode.abspath()260env.CMAKE_SRC_DIR = self.srcnode.abspath()261262keys = self.vars_keys()263env.CMAKE_VARS = ["-D%s='%s'" % (k, self.vars[k]) for k in keys]264env.CMAKE_FLAGS = self.flags265266self._config_task.set_outputs(267self.bldnode.find_or_declare('CMakeCache.txt'),268)269270if self.last_build_task:271self._config_task.set_run_after(self.last_build_task)272273self.bldnode.mkdir()274275return self._config_task276277def build(self, cmake_target, **kw):278return self.bld.cmake_build(self.name, cmake_target, **kw)279280_cmake_instances = {}281def get_cmake(name):282if name not in _cmake_instances:283raise Exception('cmake: configuration named "%s" not found' % name)284return _cmake_instances[name]285286@conf287def cmake(bld, name, cmake_src=None, cmake_bld=None, cmake_vars={}, cmake_flags=''):288'''289This function has two signatures:290- bld.cmake(name, cmake_src, cmake_bld, cmake_vars):291Create a cmake configuration.292- bld.cmake(name):293Get the cmake configuration with name.294'''295if not cmake_src and not cmake_bld and not cmake_vars:296return get_cmake(name)297298if name in _cmake_instances:299bld.fatal('cmake: configuration named "%s" already exists' % name)300301if not isinstance(cmake_src, Node.Node):302cmake_src = bld.path.find_dir(cmake_src)303304if not cmake_bld:305cmake_bld = cmake_src.get_bld()306elif not isinstance(cmake_bld, Node.Node):307cmake_bld = bld.bldnode.make_node(cmake_bld)308309c = CMakeConfig(bld, name, cmake_src, cmake_bld, cmake_vars, cmake_flags)310_cmake_instances[name] = c311return c312313@feature('cmake_build')314def process_cmake_build(self):315if not hasattr(self, 'cmake_target'):316self.bld.fatal('cmake_build: taskgen is missing cmake_target')317if not hasattr(self, 'cmake_config'):318self.bld.fatal('cmake_build: taskgen is missing cmake_config')319320tsk = self.create_cmake_build_task(self.cmake_config, self.cmake_target)321self.cmake_build_task = tsk322323outputs = Utils.to_list(getattr(self, 'target', ''))324if not isinstance(outputs, list):325outputs = [outputs]326327for o in outputs:328if not isinstance(o, Node.Node):329o = self.path.find_or_declare(o)330tsk.set_outputs(o)331332tsk.output_patterns = getattr(self, 'cmake_output_patterns', [])333334@conf335def cmake_build(bld, cmake_config, cmake_target, **kw):336kw['cmake_config'] = cmake_config337kw['cmake_target'] = cmake_target338kw['features'] = Utils.to_list(kw.get('features', [])) + ['cmake_build']339340if 'name' not in kw:341kw['name'] = '%s_%s' % (cmake_config, cmake_target)342343return bld(**kw)344345@taskgen_method346def create_cmake_build_task(self, cmake_config, cmake_target):347cmake = get_cmake(cmake_config)348349tsk = self.create_task('cmake_build_task')350tsk.cmake = cmake351tsk.cmake_target = cmake_target352tsk.output_patterns = []353tsk.env.CMAKE_BLD_DIR = cmake.bldnode.abspath()354tsk.env.CMAKE_TARGET = cmake_target355356self.cmake_config_task = cmake.config_task(self)357tsk.set_run_after(self.cmake_config_task)358359if cmake.last_build_task:360tsk.set_run_after(cmake.last_build_task)361cmake.last_build_task = tsk362363return tsk364365def _check_min_version(cfg):366cfg.start_msg('Checking cmake version')367cmd = cfg.env.get_flat('CMAKE'), '--version'368out = cfg.cmd_and_log(cmd, quiet=Context.BOTH)369m = re.search(r'\d+\.\d+(\.\d+(\.\d+)?)?', out)370if not m:371cfg.end_msg(372'unable to parse version, build is not guaranteed to succeed',373color='YELLOW',374)375else:376version = Utils.num2ver(m.group(0))377minver_str = cfg.env.get_flat('CMAKE_MIN_VERSION')378minver = Utils.num2ver(minver_str)379if version < minver:380cfg.fatal('cmake must be at least at version %s' % minver_str)381cfg.end_msg(m.group(0))382383generators = dict(384default=[385(['ninja', 'ninja-build'], 'Ninja'),386(['make'], 'Unix Makefiles'),387],388win32=[389(['ninja', 'ninja-build'], 'Ninja'),390(['nmake'], 'NMake Makefiles'),391],392)393394def configure(cfg):395cfg.find_program('cmake')396397if cfg.env.CMAKE_MIN_VERSION:398_check_min_version(cfg)399400l = generators.get(Utils.unversioned_sys_platform(), generators['default'])401for names, generator in l:402if cfg.find_program(names, mandatory=False):403cfg.env.CMAKE_GENERATOR_OPTION = '-G%s' % generator404break405else:406cfg.fatal("cmake: couldn't find a suitable CMake generator. " +407"The ones supported by this Waf tool for this platform are: %s" % ', '.join(g for _, g in l))408409410