def test_get_previous_tool_used_on_the_space(): res = get_previous_tool_used_on_the_space('folder_that_does_not_exist') assert res is None, res os.makedirs('build') res = get_previous_tool_used_on_the_space('build') assert res is None, res mark_space_as_built_by('build', 'foo') res = get_previous_tool_used_on_the_space('build') assert res == 'foo', res
def build_workspace_isolated( workspace='.', sourcespace=None, buildspace=None, develspace=None, installspace=None, merge=False, install=False, force_cmake=False, colorize=True, build_packages=None, ignore_packages=None, quiet=False, cmake_args=None, make_args=None, catkin_make_args=None, continue_from_pkg=False, only_pkg_with_deps=None, destdir=None, use_ninja=False, use_nmake=False, use_gmake=False, override_build_tool_check=False ): ''' Runs ``cmake``, ``make`` and optionally ``make install`` for all catkin packages in sourcespace_dir. It creates several folders in the current working directory. For non-catkin packages it runs ``cmake``, ``make`` and ``make install`` for each, installing it to the devel space or install space if the ``install`` option is specified. :param workspace: path to the current workspace, ``str`` :param sourcespace: workspace folder containing catkin packages, ``str`` :param buildspace: path to build space location, ``str`` :param develspace: path to devel space location, ``str`` :param installspace: path to install space (CMAKE_INSTALL_PREFIX), ``str`` :param merge: if True, build each catkin package into the same devel space (not affecting plain cmake packages), ``bool`` :param install: if True, install all packages to the install space, ``bool`` :param force_cmake: (optional), if True calls cmake explicitly for each package, ``bool`` :param colorize: if True, colorize cmake output and other messages, ``bool`` :param build_packages: specific packages to build (all parent packages in the topological order must have been built before), ``str`` :param quiet: if True, hides some build output, ``bool`` :param cmake_args: additional arguments for cmake, ``[str]`` :param make_args: additional arguments for make, ``[str]`` :param catkin_make_args: additional arguments for make but only for catkin packages, ``[str]`` :param continue_from_pkg: indicates whether or not cmi should continue when a package is reached, ``bool`` :param only_pkg_with_deps: only consider the specific packages and their recursive dependencies and ignore all other packages in the workspace, ``[str]`` :param destdir: define DESTDIR for cmake/invocation, ``string`` :param use_ninja: if True, use ninja instead of make, ``bool`` :param use_nmake: if True, use nmake instead of make, ``bool`` :param use_gmake: if True, use gmake instead of make, ``bool`` :param override_build_tool_check: if True, build even if a space was built by another tool previously. ''' if not colorize: disable_ANSI_colors() # Check workspace existance if not os.path.exists(workspace): sys.exit("Workspace path '{0}' does not exist.".format(workspace)) workspace = os.path.abspath(workspace) # Check source space existance if sourcespace is None: sourcespace = os.path.join(workspace, 'src') if not os.path.exists(sourcespace): sys.exit('Could not find source space: {0}'.format(sourcespace)) print('Base path: ' + str(workspace)) print('Source space: ' + str(sourcespace)) # Check build space if buildspace is None: buildspace = os.path.join(workspace, 'build_isolated') if not os.path.exists(buildspace): os.mkdir(buildspace) print('Build space: ' + str(buildspace)) # ensure the build space was previously built by catkin_make_isolated previous_tool = get_previous_tool_used_on_the_space(buildspace) if previous_tool is not None and previous_tool != 'catkin_make_isolated': if override_build_tool_check: print(fmt( "@{yf}Warning: build space at '%s' was previously built by '%s', " "but --override-build-tool-check was passed so continuing anyways." % (buildspace, previous_tool))) else: sys.exit(fmt( "@{rf}The build space at '%s' was previously built by '%s'. " "Please remove the build space or pick a different build space." % (buildspace, previous_tool))) mark_space_as_built_by(buildspace, 'catkin_make_isolated') # Check devel space if develspace is None: develspace = os.path.join(workspace, 'devel_isolated') print('Devel space: ' + str(develspace)) # ensure the devel space was previously built by catkin_make_isolated previous_tool = get_previous_tool_used_on_the_space(develspace) if previous_tool is not None and previous_tool != 'catkin_make_isolated': if override_build_tool_check: print(fmt( "@{yf}Warning: devel space at '%s' was previously built by '%s', " "but --override-build-tool-check was passed so continuing anyways." % (develspace, previous_tool))) else: sys.exit(fmt( "@{rf}The devel space at '%s' was previously built by '%s'. " "Please remove the devel space or pick a different devel space." % (develspace, previous_tool))) mark_space_as_built_by(develspace, 'catkin_make_isolated') # Check install space if installspace is None: installspace = os.path.join(workspace, 'install_isolated') print('Install space: ' + str(installspace)) if cmake_args: print("Additional CMake Arguments: " + " ".join(cmake_args)) else: cmake_args = [] if not [arg for arg in cmake_args if arg.startswith('-G')]: if use_ninja: cmake_args += ['-G', 'Ninja'] elif use_nmake: cmake_args += ['-G', 'NMake Makefiles'] else: # no need to check for use_gmake, as it uses the same generator as make cmake_args += ['-G', 'Unix Makefiles'] elif use_ninja or use_nmake: print(colorize_line("Error: either specify a generator using '-G...' or '--use-[ninja|nmake]' but not both")) sys.exit(1) if make_args: print("Additional make Arguments: " + " ".join(make_args)) else: make_args = [] if catkin_make_args: print("Additional make Arguments for catkin packages: " + " ".join(catkin_make_args)) else: catkin_make_args = [] # Find packages packages = find_packages(sourcespace, exclude_subspaces=True) if not packages: print(fmt("@{yf}No packages found in source space: %s@|" % sourcespace)) # whitelist packages and their dependencies in workspace if only_pkg_with_deps: package_names = [p.name for p in packages.values()] unknown_packages = [name for name in only_pkg_with_deps if name not in package_names] if unknown_packages: sys.exit('Packages not found in the workspace: %s' % ', '.join(unknown_packages)) whitelist_pkg_names = get_package_names_with_recursive_dependencies(packages, only_pkg_with_deps) print('Whitelisted packages: %s' % ', '.join(sorted(whitelist_pkg_names))) packages = {path: p for path, p in packages.items() if p.name in whitelist_pkg_names} # verify that specified package exists in workspace if build_packages: packages_by_name = {p.name: path for path, p in packages.items()} unknown_packages = [p for p in build_packages if p not in packages_by_name] if unknown_packages: sys.exit('Packages not found in the workspace: %s' % ', '.join(unknown_packages)) # evaluate conditions for package in packages.values(): package.evaluate_conditions(os.environ) # Report topological ordering ordered_packages = topological_order_packages(packages, blacklisted=ignore_packages) unknown_build_types = [] msg = [] msg.append('@{pf}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' + ('~' * len(str(len(ordered_packages))))) msg.append('@{pf}~~@| traversing %d packages in topological order:' % len(ordered_packages)) for path, package in ordered_packages: if path is None: print(fmt('@{rf}Error: Circular dependency in subset of packages: @!%s@|' % package)) sys.exit('Can not build workspace with circular dependency') export_tags = [e.tagname for e in package.exports] if 'build_type' in export_tags: build_type_tag = [e.content for e in package.exports if e.tagname == 'build_type'][0] else: build_type_tag = 'catkin' if build_type_tag == 'catkin': msg.append('@{pf}~~@| - @!@{bf}' + package.name + '@|') elif build_type_tag == 'cmake': msg.append( '@{pf}~~@| - @!@{bf}' + package.name + '@|' + ' (@!@{cf}plain cmake@|)' ) else: msg.append( '@{pf}~~@| - @!@{bf}' + package.name + '@|' + ' (@{rf}unknown@|)' ) unknown_build_types.append(package) msg.append('@{pf}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' + ('~' * len(str(len(ordered_packages))))) for index in range(len(msg)): msg[index] = fmt(msg[index]) print('\n'.join(msg)) # Error if there are packages with unknown build_types if unknown_build_types: print(colorize_line('Error: Packages with unknown build types exist')) sys.exit('Can not build workspace with packages of unknown build_type') # Check to see if the workspace has changed cmake_args_with_spaces = list(cmake_args) if develspace: cmake_args_with_spaces.append('-DCATKIN_DEVEL_PREFIX=' + develspace) if installspace: cmake_args_with_spaces.append('-DCMAKE_INSTALL_PREFIX=' + installspace) if ( not force_cmake and cmake_input_changed(packages, buildspace, cmake_args=cmake_args_with_spaces, filename='catkin_make_isolated') ): print('The packages or cmake arguments have changed, forcing cmake invocation') force_cmake = True ensure_workspace_marker(workspace) # Build packages pkg_develspace = None last_env = None for index, path_package in enumerate(ordered_packages): path, package = path_package if merge: pkg_develspace = develspace else: pkg_develspace = os.path.join(develspace, package.name) if not build_packages or package.name in build_packages: if continue_from_pkg and build_packages and package.name in build_packages: build_packages = None try: print() last_env = build_package( path, package, workspace, buildspace, pkg_develspace, installspace, install, force_cmake, quiet, last_env, cmake_args, make_args, catkin_make_args, destdir=destdir, use_ninja=use_ninja, use_nmake=use_nmake, use_gmake=use_gmake, number=index + 1, of=len(ordered_packages) ) except subprocess.CalledProcessError as e: _print_build_error(package, e) # Let users know how to reproduce # First add the cd to the build folder of the package cmd = 'cd ' + quote(os.path.join(buildspace, package.name)) + ' && ' # Then reproduce the command called if isinstance(e.cmd, list): # quote arguments to allow copy-n-paste of command cmd += ' '.join([quote(arg) for arg in e.cmd]) else: cmd += e.cmd print(fmt("\n@{rf}Reproduce this error by running:")) print(fmt("@{gf}@!==> @|") + cmd + "\n") sys.exit('Command failed, exiting.') except Exception as e: print("Unhandled exception of type '{0}':".format(type(e).__name__)) import traceback traceback.print_exc() _print_build_error(package, e) sys.exit('Command failed, exiting.') else: cprint("Skipping package: '@!@{bf}" + package.name + "@|'") last_env = get_new_env(package, pkg_develspace, installspace, install, last_env, destdir) # Provide a top level devel space environment setup script if not os.path.exists(develspace): os.makedirs(develspace) if not build_packages: env_script = 'env' if sys.platform == 'win32': env_script += '.bat' env_script_content = """\ @echo off REM generated from catkin.builder Python module call {0} %* """ setup_script_content = """\ @echo off REM generated from catkin.builder Python module call "{0}/setup.{1}" """ else: env_script += '.sh' env_script_content = """\ #!/usr/bin/env sh # generated from catkin.builder Python module {0} "$@" """ setup_script_content = """\ #!/usr/bin/env {1} # generated from catkin.builder Python module . "{0}/setup.{1}" """ setup_sh_content = """\ #!/usr/bin/env sh # generated from catkin.builder Python module if [ ! -z "$_CATKIN_SETUP_DIR" ] && [ "$_CATKIN_SETUP_DIR" != "{1}" ]; then echo "Relocation of this workspace is not supported" return 1 fi _CATKIN_SETUP_DIR= . "{0}/setup.sh" """ generated_env_sh = os.path.join(develspace, env_script) generated_setup_util_py = os.path.join(develspace, '_setup_util.py') if not merge and pkg_develspace: # generate env script and setup.sh|bash|zsh or setup.bat which relay to last devel space with open(generated_env_sh, 'w') as f: f.write(env_script_content.format(os.path.join(pkg_develspace, env_script))) os.chmod(generated_env_sh, stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR) shells_to_write = ['bat'] if sys.platform == 'win32' else ['bash', 'zsh'] for shell in shells_to_write: with open(os.path.join(develspace, 'setup.%s' % shell), 'w') as f: f.write(setup_script_content.format(pkg_develspace, shell)) if sys.platform != 'win32': with open(os.path.join(develspace, 'setup.sh'), 'w') as f: f.write(setup_sh_content.format(pkg_develspace, develspace)) # remove _setup_util.py file which might have been generated for an empty devel space before if os.path.exists(generated_setup_util_py): os.remove(generated_setup_util_py) elif not pkg_develspace: # generate env.* and setup.* scripts for an empty devel space if 'CMAKE_PREFIX_PATH' in os.environ.keys(): variables = { 'CATKIN_GLOBAL_BIN_DESTINATION': 'bin', 'CATKIN_LIB_ENVIRONMENT_PATHS': "'lib'", 'CATKIN_PKGCONFIG_ENVIRONMENT_PATHS': "os.path.join('lib', 'pkgconfig')", 'CMAKE_PREFIX_PATH_AS_IS': ';'.join(os.environ['CMAKE_PREFIX_PATH'].split(os.pathsep)), 'PYTHON_EXECUTABLE': sys.executable, 'PYTHON_INSTALL_DIR': get_python_install_dir(), } with open(generated_setup_util_py, 'w') as f: f.write(configure_file( os.path.join(get_cmake_path(), 'templates', '_setup_util.py.in'), variables)) os.chmod(generated_setup_util_py, stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR) else: sys.exit("Unable to process CMAKE_PREFIX_PATH from environment. Cannot generate environment files.") variables = { 'SETUP_DIR': develspace, 'SETUP_FILENAME': 'setup', } with open(generated_env_sh, 'w') as f: f.write(configure_file(os.path.join(get_cmake_path(), 'templates', env_script + '.in'), variables)) os.chmod(generated_env_sh, stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR) variables = { 'PYTHON_EXECUTABLE': sys.executable, 'SETUP_DIR': develspace, } shells_to_write = ['bat'] if sys.platform == 'win32' else ['sh', 'bash', 'zsh'] for shell in shells_to_write: with open(os.path.join(develspace, 'setup.%s' % shell), 'w') as f: f.write(configure_file( os.path.join(get_cmake_path(), 'templates', 'setup.%s.in' % shell), variables))
def build_workspace_isolated( workspace='.', sourcespace=None, buildspace=None, develspace=None, installspace=None, merge=False, install=False, force_cmake=False, colorize=True, build_packages=None, quiet=False, cmake_args=None, make_args=None, catkin_make_args=None, continue_from_pkg=False, only_pkg_with_deps=None, destdir=None, use_ninja=False, use_nmake=False, override_build_tool_check=False ): ''' Runs ``cmake``, ``make`` and optionally ``make install`` for all catkin packages in sourcespace_dir. It creates several folders in the current working directory. For non-catkin packages it runs ``cmake``, ``make`` and ``make install`` for each, installing it to the devel space or install space if the ``install`` option is specified. :param workspace: path to the current workspace, ``str`` :param sourcespace: workspace folder containing catkin packages, ``str`` :param buildspace: path to build space location, ``str`` :param develspace: path to devel space location, ``str`` :param installspace: path to install space (CMAKE_INSTALL_PREFIX), ``str`` :param merge: if True, build each catkin package into the same devel space (not affecting plain cmake packages), ``bool`` :param install: if True, install all packages to the install space, ``bool`` :param force_cmake: (optional), if True calls cmake explicitly for each package, ``bool`` :param colorize: if True, colorize cmake output and other messages, ``bool`` :param build_packages: specific packages to build (all parent packages in the topological order must have been built before), ``str`` :param quiet: if True, hides some build output, ``bool`` :param cmake_args: additional arguments for cmake, ``[str]`` :param make_args: additional arguments for make, ``[str]`` :param catkin_make_args: additional arguments for make but only for catkin packages, ``[str]`` :param continue_from_pkg: indicates whether or not cmi should continue when a package is reached, ``bool`` :param only_pkg_with_deps: only consider the specific packages and their recursive dependencies and ignore all other packages in the workspace, ``[str]`` :param destdir: define DESTDIR for cmake/invocation, ``string`` :param use_ninja: if True, use ninja instead of make, ``bool`` :param use_nmake: if True, use nmake instead of make, ``bool`` :param override_build_tool_check: if True, build even if a space was built by another tool previously. ''' if not colorize: disable_ANSI_colors() # Check workspace existance if not os.path.exists(workspace): sys.exit("Workspace path '{0}' does not exist.".format(workspace)) workspace = os.path.abspath(workspace) # Check source space existance if sourcespace is None: sourcespace = os.path.join(workspace, 'src') if not os.path.exists(sourcespace): sys.exit('Could not find source space: {0}'.format(sourcespace)) print('Base path: ' + str(workspace)) print('Source space: ' + str(sourcespace)) # Check build space if buildspace is None: buildspace = os.path.join(workspace, 'build_isolated') if not os.path.exists(buildspace): os.mkdir(buildspace) print('Build space: ' + str(buildspace)) # ensure the build space was previously built by catkin_make_isolated previous_tool = get_previous_tool_used_on_the_space(buildspace) if previous_tool is not None and previous_tool != 'catkin_make_isolated': if override_build_tool_check: print(fmt( "@{yf}Warning: build space at '%s' was previously built by '%s', " "but --override-build-tool-check was passed so continuing anyways." % (buildspace, previous_tool))) else: sys.exit(fmt( "@{rf}The build space at '%s' was previously built by '%s'. " "Please remove the build space or pick a different build space." % (buildspace, previous_tool))) mark_space_as_built_by(buildspace, 'catkin_make_isolated') # Check devel space if develspace is None: develspace = os.path.join(workspace, 'devel_isolated') print('Devel space: ' + str(develspace)) # ensure the devel space was previously built by catkin_make_isolated previous_tool = get_previous_tool_used_on_the_space(develspace) if previous_tool is not None and previous_tool != 'catkin_make_isolated': if override_build_tool_check: print(fmt( "@{yf}Warning: devel space at '%s' was previously built by '%s', " "but --override-build-tool-check was passed so continuing anyways." % (develspace, previous_tool))) else: sys.exit(fmt( "@{rf}The devel space at '%s' was previously built by '%s'. " "Please remove the devel space or pick a different devel space." % (develspace, previous_tool))) mark_space_as_built_by(develspace, 'catkin_make_isolated') # Check install space if installspace is None: installspace = os.path.join(workspace, 'install_isolated') print('Install space: ' + str(installspace)) if cmake_args: print("Additional CMake Arguments: " + " ".join(cmake_args)) else: cmake_args = [] if not [arg for arg in cmake_args if arg.startswith('-G')]: if use_ninja: cmake_args += ['-G', 'Ninja'] elif use_nmake: cmake_args += ['-G', 'NMake Makefiles'] else: cmake_args += ['-G', 'Unix Makefiles'] elif use_ninja or use_nmake: print(colorize_line("Error: either specify a generator using '-G...' or '--use-[ninja|nmake]' but not both")) sys.exit(1) if make_args: print("Additional make Arguments: " + " ".join(make_args)) else: make_args = [] if catkin_make_args: print("Additional make Arguments for catkin packages: " + " ".join(catkin_make_args)) else: catkin_make_args = [] # Find packages packages = find_packages(sourcespace, exclude_subspaces=True) if not packages: print(fmt("@{yf}No packages found in source space: %s@|" % sourcespace)) # whitelist packages and their dependencies in workspace if only_pkg_with_deps: package_names = [p.name for p in packages.values()] unknown_packages = [name for name in only_pkg_with_deps if name not in package_names] if unknown_packages: sys.exit('Packages not found in the workspace: %s' % ', '.join(unknown_packages)) whitelist_pkg_names = get_package_names_with_recursive_dependencies(packages, only_pkg_with_deps) print('Whitelisted packages: %s' % ', '.join(sorted(whitelist_pkg_names))) packages = {path: p for path, p in packages.items() if p.name in whitelist_pkg_names} # verify that specified package exists in workspace if build_packages: packages_by_name = {p.name: path for path, p in packages.items()} unknown_packages = [p for p in build_packages if p not in packages_by_name] if unknown_packages: sys.exit('Packages not found in the workspace: %s' % ', '.join(unknown_packages)) # Report topological ordering ordered_packages = topological_order_packages(packages) unknown_build_types = [] msg = [] msg.append('@{pf}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' + ('~' * len(str(len(ordered_packages))))) msg.append('@{pf}~~@| traversing %d packages in topological order:' % len(ordered_packages)) for path, package in ordered_packages: if path is None: print(fmt('@{rf}Error: Circular dependency in subset of packages: @!%s@|' % package)) sys.exit('Can not build workspace with circular dependency') export_tags = [e.tagname for e in package.exports] if 'build_type' in export_tags: build_type_tag = [e.content for e in package.exports if e.tagname == 'build_type'][0] else: build_type_tag = 'catkin' if build_type_tag == 'catkin': msg.append('@{pf}~~@| - @!@{bf}' + package.name + '@|') elif build_type_tag == 'cmake': msg.append( '@{pf}~~@| - @!@{bf}' + package.name + '@|' + ' (@!@{cf}plain cmake@|)' ) else: msg.append( '@{pf}~~@| - @!@{bf}' + package.name + '@|' + ' (@{rf}unknown@|)' ) unknown_build_types.append(package) msg.append('@{pf}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' + ('~' * len(str(len(ordered_packages))))) for index in range(len(msg)): msg[index] = fmt(msg[index]) print('\n'.join(msg)) # Error if there are packages with unknown build_types if unknown_build_types: print(colorize_line('Error: Packages with unknown build types exist')) sys.exit('Can not build workspace with packages of unknown build_type') # Check to see if the workspace has changed cmake_args_with_spaces = list(cmake_args) if develspace: cmake_args_with_spaces.append('-DCATKIN_DEVEL_PREFIX=' + develspace) if installspace: cmake_args_with_spaces.append('-DCMAKE_INSTALL_PREFIX=' + installspace) if ( not force_cmake and cmake_input_changed(packages, buildspace, cmake_args=cmake_args_with_spaces, filename='catkin_make_isolated') ): print('The packages or cmake arguments have changed, forcing cmake invocation') force_cmake = True ensure_workspace_marker(workspace) # Build packages pkg_develspace = None last_env = None for index, path_package in enumerate(ordered_packages): path, package = path_package if merge: pkg_develspace = develspace else: pkg_develspace = os.path.join(develspace, package.name) if not build_packages or package.name in build_packages: if continue_from_pkg and build_packages and package.name in build_packages: build_packages = None try: print() last_env = build_package( path, package, workspace, buildspace, pkg_develspace, installspace, install, force_cmake, quiet, last_env, cmake_args, make_args, catkin_make_args, destdir=destdir, use_ninja=use_ninja, number=index + 1, of=len(ordered_packages) ) except subprocess.CalledProcessError as e: _print_build_error(package, e) # Let users know how to reproduce # First add the cd to the build folder of the package cmd = 'cd ' + quote(os.path.join(buildspace, package.name)) + ' && ' # Then reproduce the command called if isinstance(e.cmd, list): # quote arguments to allow copy-n-paste of command cmd += ' '.join([quote(arg) for arg in e.cmd]) else: cmd += e.cmd print(fmt("\n@{rf}Reproduce this error by running:")) print(fmt("@{gf}@!==> @|") + cmd + "\n") sys.exit('Command failed, exiting.') except Exception as e: print("Unhandled exception of type '{0}':".format(type(e).__name__)) import traceback traceback.print_exc() _print_build_error(package, e) sys.exit('Command failed, exiting.') else: cprint("Skipping package: '@!@{bf}" + package.name + "@|'") last_env = get_new_env(package, pkg_develspace, installspace, install, last_env, destdir) # Provide a top level devel space environment setup script if not os.path.exists(develspace): os.makedirs(develspace) if not build_packages: generated_env_sh = os.path.join(develspace, 'env.sh') generated_setup_util_py = os.path.join(develspace, '_setup_util.py') if not merge and pkg_develspace: # generate env.sh and setup.sh|bash|zsh which relay to last devel space with open(generated_env_sh, 'w') as f: f.write("""\ #!/usr/bin/env sh # generated from catkin.builder module {0} "$@" """.format(os.path.join(pkg_develspace, 'env.sh'))) os.chmod(generated_env_sh, stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR) for shell in ['sh', 'bash', 'zsh']: with open(os.path.join(develspace, 'setup.%s' % shell), 'w') as f: f.write("""\ #!/usr/bin/env {1} # generated from catkin.builder module . "{0}/setup.{1}" """.format(pkg_develspace, shell)) # remove _setup_util.py file which might have been generated for an empty devel space before if os.path.exists(generated_setup_util_py): os.remove(generated_setup_util_py) elif not pkg_develspace: # generate env.sh and setup.sh|bash|zsh for an empty devel space if 'CMAKE_PREFIX_PATH' in os.environ.keys(): variables = { 'CATKIN_GLOBAL_BIN_DESTINATION': 'bin', 'CATKIN_LIB_ENVIRONMENT_PATHS': "'lib'", 'CATKIN_PKGCONFIG_ENVIRONMENT_PATHS': "os.path.join('lib', 'pkgconfig')", 'CMAKE_PREFIX_PATH_AS_IS': ';'.join(os.environ['CMAKE_PREFIX_PATH'].split(os.pathsep)), 'PYTHON_EXECUTABLE': sys.executable, 'PYTHON_INSTALL_DIR': get_python_install_dir(), } with open(generated_setup_util_py, 'w') as f: f.write(configure_file( os.path.join(get_cmake_path(), 'templates', '_setup_util.py.in'), variables)) os.chmod(generated_setup_util_py, stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR) else: sys.exit("Unable to process CMAKE_PREFIX_PATH from environment. Cannot generate environment files.") variables = {'SETUP_FILENAME': 'setup'} with open(generated_env_sh, 'w') as f: f.write(configure_file(os.path.join(get_cmake_path(), 'templates', 'env.sh.in'), variables)) os.chmod(generated_env_sh, stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR) variables = {'SETUP_DIR': develspace} for shell in ['sh', 'bash', 'zsh']: with open(os.path.join(develspace, 'setup.%s' % shell), 'w') as f: f.write(configure_file( os.path.join(get_cmake_path(), 'templates', 'setup.%s.in' % shell), variables))
def main(opts): # Check for develdebug mode if opts.develdebug is not None: os.environ['TROLLIUSDEBUG'] = opts.develdebug.lower() logging.basicConfig(level=opts.develdebug.upper()) # Set color options if (opts.force_color or is_tty(sys.stdout)) and not opts.no_color: set_color(True) else: set_color(False) # Context-aware args if opts.build_this or opts.start_with_this: # Determine the enclosing package try: ws_path = find_enclosing_workspace(getcwd()) # Suppress warnings since this won't necessaraly find all packages # in the workspace (it stops when it finds one package), and # relying on it for warnings could mislead people. this_package = find_enclosing_package( search_start_path=getcwd(), ws_path=ws_path, warnings=[]) except (InvalidPackage, RuntimeError): this_package = None # Handle context-based package building if opts.build_this: if this_package: opts.packages += [this_package] else: sys.exit( "[build] Error: In order to use --this, the current directory must be part of a catkin package.") # If --start--with was used without any packages and --this was specified, start with this package if opts.start_with_this: if this_package: opts.start_with = this_package else: sys.exit( "[build] Error: In order to use --this, the current directory must be part of a catkin package.") if opts.no_deps and not opts.packages and not opts.unbuilt: sys.exit(clr("[build] @!@{rf}Error:@| With --no-deps, you must specify packages to build.")) # Load the context ctx = Context.load(opts.workspace, opts.profile, opts, append=True) # Initialize the build configuration make_args, makeflags, cli_flags, jobserver = configure_make_args( ctx.make_args, ctx.jobs_args, ctx.use_internal_make_jobserver) # Set the jobserver memory limit if jobserver and opts.mem_limit: log(clr("@!@{pf}EXPERIMENTAL: limit memory to '%s'@|" % str(opts.mem_limit))) # At this point psuitl will be required, check for it and bail out if not set try: import psutil # noqa except ImportError as exc: log("Could not import psutil, but psutil is required when using --mem-limit.") log("Please either install psutil or avoid using --mem-limit.") sys.exit("Exception: {0}".format(exc)) job_server.set_max_mem(opts.mem_limit) ctx.make_args = make_args # Load the environment of the workspace to extend if ctx.extend_path is not None: try: load_resultspace_environment(ctx.extend_path) except IOError as exc: sys.exit(clr("[build] @!@{rf}Error:@| Unable to extend workspace from \"%s\": %s" % (ctx.extend_path, exc.message))) # Check if the context is valid before writing any metadata if not ctx.source_space_exists(): sys.exit(clr("[build] @!@{rf}Error:@| Unable to find source space `%s`") % ctx.source_space_abs) # ensure the build space was previously built by catkin_tools previous_tool = get_previous_tool_used_on_the_space(ctx.build_space_abs) if previous_tool is not None and previous_tool != 'catkin build': if opts.override_build_tool_check: log(clr( "@{yf}Warning: build space at '%s' was previously built by '%s', " "but --override-build-tool-check was passed so continuing anyways." % (ctx.build_space_abs, previous_tool))) else: sys.exit(clr( "@{rf}The build space at '%s' was previously built by '%s'. " "Please remove the build space or pick a different build space." % (ctx.build_space_abs, previous_tool))) # the build space will be marked as catkin build's if dry run doesn't return # ensure the devel space was previously built by catkin_tools previous_tool = get_previous_tool_used_on_the_space(ctx.devel_space_abs) if previous_tool is not None and previous_tool != 'catkin build': if opts.override_build_tool_check: log(clr( "@{yf}Warning: devel space at '%s' was previously built by '%s', " "but --override-build-tool-check was passed so continuing anyways." % (ctx.devel_space_abs, previous_tool))) else: sys.exit(clr( "@{rf}The devel space at '%s' was previously built by '%s'. " "Please remove the devel space or pick a different devel space." % (ctx.devel_space_abs, previous_tool))) # the devel space will be marked as catkin build's if dry run doesn't return # Display list and leave the file system untouched if opts.dry_run: # TODO: Add unbuilt dry_run(ctx, opts.packages, opts.no_deps, opts.start_with) return # Print the build environment for a given package and leave the filesystem untouched if opts.get_env: return print_build_env(ctx, opts.get_env[0]) # Now mark the build and devel spaces as catkin build's since dry run didn't return. mark_space_as_built_by(ctx.build_space_abs, 'catkin build') mark_space_as_built_by(ctx.devel_space_abs, 'catkin build') # Get the last build context build_metadata = get_metadata(ctx.workspace, ctx.profile, 'build') if build_metadata.get('cmake_args') != ctx.cmake_args or build_metadata.get('cmake_args') != opts.cmake_args: opts.force_cmake = True if build_metadata.get('needs_force', False): opts.force_cmake = True update_metadata(ctx.workspace, ctx.profile, 'build', {'needs_force': False}) # Always save the last context under the build verb update_metadata(ctx.workspace, ctx.profile, 'build', ctx.get_stored_dict()) # Save the context as the configuration if opts.save_config: Context.save(ctx) # Get parallel toplevel jobs try: parallel_jobs = int(opts.parallel_jobs) except TypeError: parallel_jobs = None # Set VERBOSE environment variable if opts.verbose: os.environ['VERBOSE'] = '1' return build_isolated_workspace( ctx, packages=opts.packages, start_with=opts.start_with, no_deps=opts.no_deps, unbuilt=opts.unbuilt, n_jobs=parallel_jobs, force_cmake=opts.force_cmake, pre_clean=opts.pre_clean, force_color=opts.force_color, quiet=not opts.verbose, interleave_output=opts.interleave_output, no_status=opts.no_status, limit_status_rate=opts.limit_status_rate, lock_install=not opts.no_install_lock, no_notify=opts.no_notify, continue_on_failure=opts.continue_on_failure, summarize_build=opts.summarize # Can be True, False, or None )
def main(opts): # Check for develdebug mode if opts.develdebug is not None: os.environ['TROLLIUSDEBUG'] = opts.develdebug.lower() logging.basicConfig(level=opts.develdebug.upper()) # Set color options opts.force_color = os.environ.get('CATKIN_TOOLS_FORCE_COLOR', opts.force_color) if (opts.force_color or is_tty(sys.stdout)) and not opts.no_color: set_color(True) else: set_color(False) # Context-aware args if opts.build_this or opts.start_with_this: # Determine the enclosing package try: ws_path = find_enclosing_workspace(getcwd()) # Suppress warnings since this won't necessaraly find all packages # in the workspace (it stops when it finds one package), and # relying on it for warnings could mislead people. this_package = find_enclosing_package(search_start_path=getcwd(), ws_path=ws_path, warnings=[]) except (InvalidPackage, RuntimeError): this_package = None # Handle context-based package building if opts.build_this: if this_package: opts.packages += [this_package] else: sys.exit( "[build] Error: In order to use --this, the current directory must be part of a catkin package." ) # If --start--with was used without any packages and --this was specified, start with this package if opts.start_with_this: if this_package: opts.start_with = this_package else: sys.exit( "[build] Error: In order to use --this, the current directory must be part of a catkin package." ) if opts.no_deps and not opts.packages and not opts.unbuilt: sys.exit( clr("[build] @!@{rf}Error:@| With --no-deps, you must specify packages to build." )) # Load the context ctx = Context.load(opts.workspace, opts.profile, opts, append=True) # Initialize the build configuration make_args, makeflags, cli_flags, jobserver = configure_make_args( ctx.make_args, ctx.jobs_args, ctx.use_internal_make_jobserver) # Set the jobserver memory limit if jobserver and opts.mem_limit: log( clr("@!@{pf}EXPERIMENTAL: limit memory to '%s'@|" % str(opts.mem_limit))) # At this point psuitl will be required, check for it and bail out if not set try: import psutil # noqa except ImportError as exc: log("Could not import psutil, but psutil is required when using --mem-limit." ) log("Please either install psutil or avoid using --mem-limit.") sys.exit("Exception: {0}".format(exc)) job_server.set_max_mem(opts.mem_limit) ctx.make_args = make_args # Load the environment of the workspace to extend if ctx.extend_path is not None: try: load_resultspace_environment(ctx.extend_path) except IOError as exc: sys.exit( clr("[build] @!@{rf}Error:@| Unable to extend workspace from \"%s\": %s" % (ctx.extend_path, exc.message))) # Check if the context is valid before writing any metadata if not ctx.source_space_exists(): sys.exit( clr("[build] @!@{rf}Error:@| Unable to find source space `%s`") % ctx.source_space_abs) # ensure the build space was previously built by catkin_tools previous_tool = get_previous_tool_used_on_the_space(ctx.build_space_abs) if previous_tool is not None and previous_tool != 'catkin build': if opts.override_build_tool_check: log( clr("@{yf}Warning: build space at '%s' was previously built by '%s', " "but --override-build-tool-check was passed so continuing anyways." % (ctx.build_space_abs, previous_tool))) else: sys.exit( clr("@{rf}The build space at '%s' was previously built by '%s'. " "Please remove the build space or pick a different build space." % (ctx.build_space_abs, previous_tool))) # the build space will be marked as catkin build's if dry run doesn't return # ensure the devel space was previously built by catkin_tools previous_tool = get_previous_tool_used_on_the_space(ctx.devel_space_abs) if previous_tool is not None and previous_tool != 'catkin build': if opts.override_build_tool_check: log( clr("@{yf}Warning: devel space at '%s' was previously built by '%s', " "but --override-build-tool-check was passed so continuing anyways." % (ctx.devel_space_abs, previous_tool))) else: sys.exit( clr("@{rf}The devel space at '%s' was previously built by '%s'. " "Please remove the devel space or pick a different devel space." % (ctx.devel_space_abs, previous_tool))) # the devel space will be marked as catkin build's if dry run doesn't return # Display list and leave the file system untouched if opts.dry_run: # TODO: Add unbuilt dry_run(ctx, opts.packages, opts.no_deps, opts.start_with) return # Print the build environment for a given package and leave the filesystem untouched if opts.get_env: return print_build_env(ctx, opts.get_env[0]) # Now mark the build and devel spaces as catkin build's since dry run didn't return. mark_space_as_built_by(ctx.build_space_abs, 'catkin build') mark_space_as_built_by(ctx.devel_space_abs, 'catkin build') # Get the last build context build_metadata = get_metadata(ctx.workspace, ctx.profile, 'build') # Force cmake if the CMake arguments have changed if build_metadata.get('cmake_args') != ctx.cmake_args: opts.force_cmake = True # Check the devel layout compatibility last_devel_layout = build_metadata.get('devel_layout', ctx.devel_layout) if last_devel_layout != ctx.devel_layout: sys.exit( clr("@{rf}@!Error:@|@{rf} The current devel space layout, `{}`," "is incompatible with the configured layout, `{}`.@|").format( last_devel_layout, ctx.devel_layout)) # Check if some other verb has changed the workspace in such a way that it needs to be forced if build_metadata.get('needs_force', False): opts.force_cmake = True update_metadata(ctx.workspace, ctx.profile, 'build', {'needs_force': False}) # Always save the last context under the build verb update_metadata(ctx.workspace, ctx.profile, 'build', ctx.get_stored_dict()) # Save the context as the configuration if opts.save_config: Context.save(ctx) # Get parallel toplevel jobs try: parallel_jobs = int(opts.parallel_jobs) except TypeError: parallel_jobs = None # Set VERBOSE environment variable if opts.verbose: os.environ['VERBOSE'] = '1' return build_isolated_workspace( ctx, packages=opts.packages, start_with=opts.start_with, no_deps=opts.no_deps, unbuilt=opts.unbuilt, n_jobs=parallel_jobs, force_cmake=opts.force_cmake, pre_clean=opts.pre_clean, force_color=opts.force_color, quiet=not opts.verbose, interleave_output=opts.interleave_output, no_status=opts.no_status, limit_status_rate=opts.limit_status_rate, lock_install=not opts.no_install_lock, no_notify=opts.no_notify, continue_on_failure=opts.continue_on_failure, summarize_build=opts.summarize # Can be True, False, or None )