Example #1
0
def create_cmakelists(package_template, rosdistro, meta=False):
    """
    :param package_template: contains the required information
    :returns: file contents as string
    """
    if meta:
        template_path = get_metapackage_cmake_template_path()
        temp_dict = {
            'name': package_template.name,
            'metapackage_arguments': ''
        }
        return configure_file(template_path, temp_dict)
    else:
        cmakelists_txt_template = read_template_file('CMakeLists.txt',
                                                     rosdistro)
        ctemp = CatkinTemplate(cmakelists_txt_template)
        if package_template.catkin_deps == []:
            components = ''
        else:
            components = ' COMPONENTS\n  %s\n' % '\n  '.join(
                package_template.catkin_deps)
        boost_find_package = \
            ('' if not package_template.boost_comps
             else ('find_package(Boost REQUIRED COMPONENTS %s)\n' %
                   ' '.join(package_template.boost_comps)))
        system_find_package = ''
        for sysdep in package_template.system_deps:
            if sysdep == 'boost':
                continue
            if sysdep.startswith('python-'):
                system_find_package += '# '
            system_find_package += 'find_package(%s REQUIRED)\n' % sysdep
        # provide dummy values
        catkin_depends = (''.join('#     %s\n' % dep
                                  for dep in package_template.catkin_deps)[:-1]
                          if package_template.catkin_deps else
                          '#     other_catkin_pkg')
        system_depends = (''.join(
            '#     %s\n' % dep for dep in package_template.system_deps)[:-1] if
                          package_template.system_deps else '#     system_lib')
        message_pkgs = [
            pkg for pkg in package_template.catkin_deps
            if pkg.endswith('_msgs')
        ]
        if message_pkgs:
            message_depends = '#   %s' % '\n#   '.join(message_pkgs)
        else:
            message_depends = '#   packages containing msgs'
        temp_dict = {
            'name': package_template.name,
            'components': components,
            'include_directories': _create_include_macro(package_template),
            'boost_find': boost_find_package,
            'systems_find': system_find_package,
            'catkin_depends': catkin_depends,
            'system_depends': system_depends,
            'target_libraries': _create_targetlib_args(package_template),
            'message_dependencies': message_depends
        }
        return ctemp.substitute(temp_dict)
def create_cmakelists(package_template, rosdistro, meta=False):
    """
    :param package_template: contains the required information
    :returns: file contents as string
    """
    if meta:
        template_path = get_metapackage_cmake_template_path()
        temp_dict = {"name": package_template.name, "metapackage_arguments": ""}
        return configure_file(template_path, temp_dict)
    else:
        cmakelists_txt_template = read_template_file("CMakeLists.txt", rosdistro)
        ctemp = CatkinTemplate(cmakelists_txt_template)
        if package_template.catkin_deps == []:
            components = ""
        else:
            components = " COMPONENTS\n  %s\n" % "\n  ".join(package_template.catkin_deps)
        boost_find_package = (
            ""
            if not package_template.boost_comps
            else ("find_package(Boost REQUIRED COMPONENTS %s)\n" % " ".join(package_template.boost_comps))
        )
        system_find_package = ""
        for sysdep in package_template.system_deps:
            if sysdep == "boost":
                continue
            if sysdep.startswith("python-"):
                system_find_package += "# "
            system_find_package += "find_package(%s REQUIRED)\n" % sysdep
        # provide dummy values
        catkin_depends = (
            "".join("#     %s\n" % dep for dep in package_template.catkin_deps)[:-1]
            if package_template.catkin_deps
            else "#     other_catkin_pkg"
        )
        system_depends = (
            "".join("#     %s\n" % dep for dep in package_template.system_deps)[:-1]
            if package_template.system_deps
            else "#     system_lib"
        )
        message_pkgs = [pkg for pkg in package_template.catkin_deps if pkg.endswith("_msgs")]
        if message_pkgs:
            message_depends = "#   %s" % "\n#   ".join(message_pkgs)
        else:
            message_depends = "#   packages containing msgs"
        temp_dict = {
            "name": package_template.name,
            "components": components,
            "include_directories": _create_include_macro(package_template),
            "boost_find": boost_find_package,
            "systems_find": system_find_package,
            "catkin_depends": catkin_depends,
            "system_depends": system_depends,
            "target_libraries": _create_targetlib_args(package_template),
            "message_dependencies": message_depends,
        }
        return ctemp.substitute(temp_dict)
Example #3
0
def create_cmakelists(package_template, rosdistro, meta=False):
    """Create CMake file contents from the template.

    :param package_template: contains the required information
    :returns: file contents as string
    """
    if meta:
        template_path = get_metapackage_cmake_template_path()
        temp_dict = {
            'name': package_template.name,
            'metapackage_arguments': '',
        }
        return configure_file(template_path, temp_dict)
    else:
        cmakelists_txt_template = read_template_file('CMakeLists.txt', rosdistro)
        ctemp = CatkinTemplate(cmakelists_txt_template)
        if package_template.catkin_deps == []:
            components = ''
        else:
            components = ' COMPONENTS\n  %s\n' % '\n  '.join(package_template.catkin_deps)
        boost_find_package = \
            ('' if not package_template.boost_comps
             else ('find_package(Boost REQUIRED COMPONENTS %s)\n' %
                   ' '.join(package_template.boost_comps)))
        system_find_package = ''
        for sysdep in package_template.system_deps:
            if sysdep == 'boost':
                continue
            if sysdep.startswith('python-'):
                system_find_package += '# '
            system_find_package += 'find_package(%s REQUIRED)\n' % sysdep
        # provide dummy values
        catkin_depends = (' '.join(package_template.catkin_deps)
                          if package_template.catkin_deps
                          else 'other_catkin_pkg')
        system_depends = (' '.join(package_template.system_deps)
                          if package_template.system_deps
                          else 'system_lib')
        message_pkgs = [pkg for pkg in package_template.catkin_deps if pkg.endswith('_msgs')]
        if message_pkgs:
            message_depends = '#   %s' % '#   '.join(message_pkgs)
        else:
            message_depends = '#   std_msgs  # Or other packages containing msgs'
        temp_dict = {'name': package_template.name,
                     'components': components,
                     'include_directories': _create_include_macro(package_template),
                     'boost_find': boost_find_package,
                     'systems_find': system_find_package,
                     'catkin_depends': catkin_depends,
                     'system_depends': system_depends,
                     'target_libraries': _create_targetlib_args(package_template),
                     'message_dependencies': message_depends
                     }
        return ctemp.substitute(temp_dict)
Example #4
0
def get_expected_cmakelists_txt(metapackage_name):
    """
    Return the expected boilerplate CMakeLists.txt file for a metapackage.

    :param metapackage_name: name of the metapackage
    :type metapackage_name: str
    :returns: expected CMakeLists.txt file
    :rtype: str
    """
    env = {'name': metapackage_name, 'metapackage_arguments': ''}
    return configure_file(get_metapackage_cmake_template_path(), env)
Example #5
0
def get_expected_cmakelists_txt(metapackage_name):
    """
    Returns the expected boilerplate CMakeLists.txt file for a metapackage

    :param metapackage_name: name of the metapackage
    :type metapackage_name: str
    :returns: expected CMakeLists.txt file
    :rtype: str
    """
    env = {
        'name': metapackage_name,
        'metapackage_arguments': ''
    }
    return configure_file(get_metapackage_cmake_template_path(), env)
Example #6
0
File: common.py Project: po1/bloom
def check_metapackage_for_valid_cmake(name):
    if not os.path.exists('CMakeLists.txt'):
        warning("See: http://ros.org/reps/rep-0127.html#metapackage")
        error("Metapackage '{0}' does not have a CMakeLists.txt, refusing to release."
              .format(name),
              exit=True)
    template_path = get_metapackage_cmake_template_path()
    env = {'name': name, 'metapackage_arguments': ''}
    expected_cmake = configure_file(template_path, env)
    with open('CMakeLists.txt', 'r') as f:
        actual_cmake = f.read()
    if expected_cmake != actual_cmake:
        error("Metapackage '{0}' has a non-compliant CMakeLists.txt, expected:"
              .format(name))
        for line in expected_cmake.splitlines():
            info("  " + line)
        error("But got instead:")
        for line in actual_cmake.splitlines():
            info("  " + line)
        warning("See: http://ros.org/reps/rep-0127.html#metapackage")
        error("Metapackage '{0}' has a non-compliant CMakeLists.txt".format(name),
              exit=True)
Example #7
0
import os
import shutil
import sys
import tempfile
import unittest

from catkin_pkg.cmake import configure_file

data = configure_file(
    os.path.join(os.path.dirname(__file__), '..', '..', 'cmake', 'templates',
                 '_setup_util.py.in'), {
                     'CATKIN_LIB_ENVIRONMENT_PATHS': "'lib'",
                     'CATKIN_PKGCONFIG_ENVIRONMENT_PATHS':
                     "os.path.join('lib', 'pkgconfig')",
                     'CATKIN_GLOBAL_BIN_DESTINATION': 'bin',
                     'PYTHON_EXECUTABLE': sys.executable,
                     'PYTHON_INSTALL_DIR': 'pythonX.Y/packages',
                     'CMAKE_PREFIX_PATH_AS_IS': '',
                 })
with tempfile.NamedTemporaryFile('w+') as setup_util_file:
    setup_util_file.write(data)
    setup_util_file.seek(0)

    import imp
    imp.load_source('setup_util', setup_util_file.name, setup_util_file.file)

from setup_util import CATKIN_MARKER_FILE  # noqa: E402
from setup_util import _get_workspaces  # noqa: E402
from setup_util import _prefix_env_variable  # noqa: E402
from setup_util import _rollback_env_variable  # noqa: E402
Example #8
0
def build_catkin_package(path,
                         package,
                         workspace,
                         buildspace,
                         develspace,
                         installspace,
                         install,
                         force_cmake,
                         quiet,
                         last_env,
                         cmake_args,
                         make_args,
                         destdir=None,
                         use_ninja=False):
    cprint("Processing @{cf}catkin@| package: '@!@{bf}" + package.name + "@|'")

    # Make the build dir
    build_dir = _check_build_dir(package.name, workspace, buildspace)

    # Check last_env
    if last_env is not None:
        cprint(blue_arrow + " Building with env: " + "'{0}'".format(last_env))

    # Check for Makefile and maybe call cmake
    if not use_ninja:
        makefile_name = 'Makefile'
    else:
        makefile_name = 'build.ninja'
    makefile = os.path.join(build_dir, makefile_name)
    if not os.path.exists(makefile) or force_cmake:
        package_dir = os.path.dirname(package.filename)
        if not os.path.exists(os.path.join(package_dir, 'CMakeLists.txt')):
            export_tags = [e.tagname for e in package.exports]
            if 'metapackage' not in export_tags:
                print(
                    colorize_line(
                        'Error: Package "%s" does not have a CMakeLists.txt file'
                        % package.name))
                sys.exit(
                    'Can not build catkin package without CMakeLists.txt file')
            # generate CMakeLists.txt for metpackages without one
            print(
                colorize_line(
                    'Warning: metapackage "%s" should have a CMakeLists.txt file'
                    % package.name))
            cmake_code = configure_file(
                get_metapackage_cmake_template_path(), {
                    'name': package.name,
                    'metapackage_arguments': 'DIRECTORY "%s"' % package_dir
                })
            cmakelists_txt = os.path.join(build_dir, 'CMakeLists.txt')
            with open(cmakelists_txt, 'w') as f:
                f.write(cmake_code)
            package_dir = build_dir

        # Run cmake
        cmake_cmd = [
            'cmake', package_dir, '-DCATKIN_DEVEL_PREFIX=' + develspace,
            '-DCMAKE_INSTALL_PREFIX=' + installspace
        ]
        cmake_cmd.extend(cmake_args)
        add_env = get_additional_environment(install, destdir, installspace)
        isolation_print_command(' '.join(cmake_cmd),
                                build_dir,
                                add_env=add_env)
        if last_env is not None:
            cmake_cmd = [last_env] + cmake_cmd
        try:
            run_command_colorized(cmake_cmd, build_dir, quiet, add_env=add_env)
        except subprocess.CalledProcessError as e:
            if os.path.exists(makefile):
                # remove Makefile to force CMake invocation next time
                os.remove(makefile)
            raise
    else:
        print('%s exists, skipping explicit cmake invocation...' %
              makefile_name)
        # Check to see if cmake needs to be run via make
        if not use_ninja:
            make_check_cmake_cmd = ['make', 'cmake_check_build_system']
        else:
            make_check_cmake_cmd = ['ninja', 'build.ninja']
        add_env = get_additional_environment(install, destdir, installspace)
        isolation_print_command(' '.join(make_check_cmake_cmd),
                                build_dir,
                                add_env=add_env)
        if last_env is not None:
            make_check_cmake_cmd = [last_env] + make_check_cmake_cmd
        run_command_colorized(make_check_cmake_cmd,
                              build_dir,
                              quiet,
                              add_env=add_env)

    # Run make
    if not use_ninja:
        make_executable = 'make'
    else:
        make_executable = 'ninja'
    make_cmd = [make_executable]
    make_cmd.extend(handle_make_arguments(make_args))
    isolation_print_command(' '.join(make_cmd), build_dir)
    if last_env is not None:
        make_cmd = [last_env] + make_cmd
    run_command(make_cmd, build_dir, quiet)

    # Make install
    if install:
        if has_make_target(build_dir, 'install', use_ninja=use_ninja):
            make_install_cmd = [make_executable, 'install']
            isolation_print_command(' '.join(make_install_cmd), build_dir)
            if last_env is not None:
                make_install_cmd = [last_env] + make_install_cmd
            run_command(make_install_cmd, build_dir, quiet)
        else:
            print(
                fmt('@{yf}Package has no "@{boldon}install@{boldoff}" target, skipping "%s install" invocation...'
                    % make_executable))
Example #9
0
def build_catkin_package(path, package, workspace, buildspace, develspace,
                         installspace, install, jobs, force_cmake, quiet,
                         cmake_args, make_args, catkin_python_path):
    cprint("Processing @{cf}catkin@| package: '@!@{bf}" + package.name + "@|'")

    # Make the build dir
    build_dir = _check_build_dir(package.name, workspace, buildspace)

    # Help find catkin cmake and python
    env = os.environ.copy()
    try:
        env['PYTHONPATH'] = env['PYTHONPATH'] + os.pathsep + catkin_python_path
    except KeyError:
        env['PYTHONPATH'] = catkin_python_path

    # Check for Makefile and maybe call cmake
    makefile = os.path.join(build_dir, 'Makefile')
    # check if toolchain.cmake, config.cmake exist
    toolchain_cmd = "-DCMAKE_TOOLCHAIN_FILE=%s" % os.path.join(
        workspace, 'toolchain.cmake') if os.path.isfile(
            os.path.join(workspace, 'toolchain.cmake')) else None
    config_cmd = "-C%s" % os.path.join(
        workspace, 'config.cmake') if os.path.isfile(
            os.path.join(workspace, 'config.cmake')) else None
    if not os.path.exists(makefile) or force_cmake:
        package_dir = os.path.dirname(package.filename)
        if not os.path.exists(os.path.join(package_dir, 'CMakeLists.txt')):
            export_tags = [e.tagname for e in package.exports]
            if 'metapackage' not in export_tags:
                print(
                    colorize_line(
                        'Error: Package "%s" does not have a CMakeLists.txt file'
                        % package.name))
                raise RuntimeError(
                    'Can not build catkin package without CMakeLists.txt file')
            # generate CMakeLists.txt for metpackages without one
            print(
                colorize_line(
                    'Warning: metapackage "%s" should have a CMakeLists.txt file'
                    % package.name))
            cmake_code = configure_file(
                get_metapackage_cmake_template_path(), {
                    'name': package.name,
                    'metapackage_arguments': 'DIRECTORY "%s"' % package_dir
                })
            cmakelists_txt = os.path.join(build_dir, 'CMakeLists.txt')
            with open(cmakelists_txt, 'w') as f:
                f.write(cmake_code)
            package_dir = build_dir

        # Run cmake
        cmake_cmd = [
            'cmake',
            package_dir,
        ]
        if toolchain_cmd:
            cmake_cmd.append(toolchain_cmd)
        if config_cmd:
            cmake_cmd.append(config_cmd)
        cmake_cmd.extend(cmake_args)
        isolation_print_command(' '.join(cmake_cmd))
        #if last_env is not None:
        #    cmake_cmd = [last_env] + cmake_cmd
        try:
            run_command_colorized(cmake_cmd, build_dir, quiet, env=env)
        except subprocess.CalledProcessError as e:
            # remove Makefile to force CMake invocation next time
            os.remove(makefile)
            raise
    else:
        print('Makefile exists, skipping explicit cmake invocation...')
        # Check to see if cmake needs to be run via make
        make_check_cmake_cmd = ['make', 'cmake_check_build_system']
        isolation_print_command(' '.join(make_check_cmake_cmd), build_dir)
        #if last_env is not None:
        #    make_check_cmake_cmd = [last_env] + make_check_cmake_cmd
        run_command_colorized(make_check_cmake_cmd, build_dir, quiet, env=env)

    # Run make
    make_cmd = ['make', '-j' + str(jobs), '-l' + str(jobs)]
    make_cmd.extend(make_args)
    isolation_print_command(' '.join(make_cmd), build_dir)
    #if last_env is not None:
    #    make_cmd = [last_env] + make_cmd
    run_command(make_cmd, build_dir, quiet, env=env)

    # Make install
    if install:
        make_install_cmd = ['make', 'install']
        isolation_print_command(' '.join(make_install_cmd), build_dir)
        #if last_env is not None:
        #    make_install_cmd = [last_env] + make_install_cmd
        run_command(make_install_cmd, build_dir, quiet)
Example #10
0
import os
import shutil
import tempfile
import unittest

from catkin_pkg.cmake import configure_file

data = configure_file(
    os.path.join(os.path.dirname(__file__), '..', '..', 'cmake', 'templates',
                 '_setup_util.py.in'), {
                     'CATKIN_GLOBAL_LIB_DESTINATION': 'lib',
                     'CATKIN_GLOBAL_BIN_DESTINATION': 'bin',
                     'PYTHON_INSTALL_DIR': 'pythonX.Y/packages',
                     'CMAKE_PREFIX_PATH_AS_IS': '',
                 })
with tempfile.TemporaryFile() as setup_util_file:
    setup_util_file.write(data)
    setup_util_file.seek(0)

    import imp
    imp.load_source('setup_util', '/somewhere/_setup_util.py', setup_util_file)

import setup_util
from setup_util import _get_workspaces, _prefix_env_variable, _rollback_env_variable, CATKIN_MARKER_FILE


class SetupUtilTest(unittest.TestCase):
    def test_get_reversed_workspaces(self):
        try:
            rootdir = tempfile.mkdtemp()
            mock_env = {}
Example #11
0
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))
Example #12
0
def build_workspace_isolated(
    workspace='.',
    sourcespace=None,
    buildspace=None,
    develspace=None,
    installspace=None,
    merge=False,
    install=False,
    jobs=None,
    force_cmake=False,
    build_packages=None,
    quiet=False,
    cmake_args=[],
    make_args=[],
    catkin_cmake_path=None,
    catkin_python_path=None
):
    '''
    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. does not work with non-catkin packages, ``bool``
    :param install: if True, install all packages to the install space,
        ``bool``
    :param jobs: number of parallel build jobs to run (make -jN -lN), ``int``
    :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]``
    '''
    # Should actually have alot of argument checks here, rather than
    # before feeding the function (makes for safe functions)

    console.pretty_print("Base Path: ", console.cyan)
    console.pretty_println("%s" % workspace, console.yellow)
    console.pretty_print("Build Path: ", console.cyan)
    console.pretty_println("%s" % buildspace, console.yellow)
    console.pretty_print("Source Path: ", console.cyan)
    console.pretty_println("%s" % sourcespace, console.yellow)
    console.pretty_print("Devel Path: ", console.cyan)
    console.pretty_println("%s" % develspace, console.yellow)
    console.pretty_print("Install Path: ", console.cyan)
    console.pretty_println("%s" % installspace, console.yellow)
    console.pretty_print("Catkin CMake Path: ", console.cyan)
    console.pretty_println("%s" % catkin_cmake_path, console.yellow)
    console.pretty_print("Catkin Python Path: ", console.cyan)
    console.pretty_println("%s" % catkin_python_path, console.yellow)
    # Find packages
    packages = find_packages(sourcespace, exclude_subspaces=True)
    if not packages:
        raise RuntimeError("No packages found in source space: %s" % sourcespace)

    # verify that specified package exists in workspace
    if build_packages:
        packages_by_name = {p.name: path for path, p in packages.iteritems()}
        unknown_packages = [p for p in build_packages if p not in packages_by_name]
        if unknown_packages:
            raise RuntimeError('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:
        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:
        raise RuntimeError('Can not build workspace with packages of unknown build_type.')

    # Check to see if the workspace has changed
    if not force_cmake:
        force_cmake, install_toggled = builder.cmake_input_changed(
            packages,
            buildspace,
            install=install,
            cmake_args=cmake_args,
            filename='catkin_make_isolated'
        )
        if force_cmake:
            print('The packages or cmake arguments have changed, forcing cmake invocation')
        elif install_toggled:
            print('The install argument has been toggled, forcing cmake invocation on plain cmake package')

    # Build packages
    original_develspace = copy.deepcopy(develspace)
    for index, path_package in enumerate(ordered_packages):
        path, package = path_package
        if not merge:
            develspace = os.path.join(original_develspace, package.name)
        if not build_packages or package.name in build_packages:
            try:
                export_tags = [e.tagname for e in package.exports]
                is_cmake_package = 'cmake' in [e.content for e in package.exports if e.tagname == 'build_type']
                builder.build_package(
                    path, package,
                    workspace, buildspace, develspace, installspace,
                    install, jobs, force_cmake or (install_toggled and is_cmake_package),
                    quiet, cmake_args, make_args,
                    number=index + 1, of=len(ordered_packages),
                    catkin_cmake_path=catkin_cmake_path,
                    catkin_python_path=catkin_python_path
                )
            except Exception as e:
                import traceback
                traceback.print_exc()
                builder.cprint(
                    '@{rf}@!<==@| ' +
                    'Failed to process package \'@!@{bf}' +
                    package.name + '@|\': \n  ' +
                    ('KeyboardInterrupt' if isinstance(e, KeyboardInterrupt)
                        else str(e))
                )
                if isinstance(e, subprocess.CalledProcessError):
                    cmd = ' '.join(e.cmd) if isinstance(e.cmd, list) else e.cmd
                    print(fmt("\n@{rf}Reproduce this error by running:"))
                    print(fmt("@{gf}@!==> @|") + cmd + "\n")
                sys.exit('Command failed, exiting.')
        else:
            builder.cprint("Skipping package: '@!@{bf}" + package.name + "@|'")

    # Provide a top level devel space environment setup script
    if not merge and not build_packages:
        # generate env.sh and setup.sh which relay to last devel space
        generated_env = os.path.join(original_develspace, 'env.sh')
        with open(generated_env, 'w') as f:
            f.write("""\
#!/usr/bin/env sh
# generated from catkin.builder module

{0} "$@"
""".format(os.path.join(develspace, 'env.sh')))
        os.chmod(generated_env, stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR)
        with open(os.path.join(original_develspace, 'setup.sh'), 'w') as f:
            f.write("""\
#!/usr/bin/env sh
# generated from catkin.builder module

. "{0}/setup.sh"
""".format(develspace))
        # generate setup.bash and setup.zsh for convenience
        variables = {'SETUP_DIR': original_develspace}
        with open(os.path.join(original_develspace, 'setup.bash'), 'w') as f:
            f.write(configure_file(os.path.join(catkin_cmake_path, 'templates', 'setup.bash.in'), variables))
        with open(os.path.join(original_develspace, 'setup.zsh'), 'w') as f:
            f.write(configure_file(os.path.join(catkin_cmake_path, 'templates', 'setup.zsh.in'), variables))
Example #13
0
def build_cmake_package(path,
                        package,
                        workspace,
                        buildspace,
                        develspace,
                        installspace,
                        install,
                        force_cmake,
                        quiet,
                        last_env,
                        cmake_args,
                        make_args,
                        destdir=None):
    # Notify the user that we are processing a plain cmake package
    cprint("Processing @{cf}plain cmake@| package: '@!@{bf}" + package.name +
           "@|'")

    # Make the build dir
    build_dir = _check_build_dir(package.name, workspace, buildspace)

    # Check last_env
    if last_env is not None:
        cprint(blue_arrow + " Building with env: " + "'{0}'".format(last_env))

    # Check for Makefile and maybe call cmake
    makefile = os.path.join(build_dir, 'Makefile')
    install_target = installspace if install else develspace
    if not os.path.exists(makefile) or force_cmake:
        # Call cmake
        cmake_cmd = [
            'cmake',
            os.path.dirname(package.filename),
            '-DCMAKE_INSTALL_PREFIX=' + install_target
        ]
        cmake_cmd.extend(cmake_args)
        isolation_print_command(' '.join(cmake_cmd), build_dir)
        if last_env is not None:
            cmake_cmd = [last_env] + cmake_cmd
        run_command_colorized(cmake_cmd, build_dir, quiet)
    else:
        print('Makefile exists, skipping explicit cmake invocation...')
        # Check to see if cmake needs to be run via make
        make_check_cmake_cmd = ['make', 'cmake_check_build_system']
        isolation_print_command(' '.join(make_check_cmake_cmd), build_dir)
        if last_env is not None:
            make_check_cmake_cmd = [last_env] + make_check_cmake_cmd
        run_command_colorized(make_check_cmake_cmd, build_dir, quiet)

    # Run make
    make_cmd = ['make']
    make_cmd.extend(handle_make_arguments(make_args))
    isolation_print_command(' '.join(make_cmd), build_dir)
    if last_env is not None:
        make_cmd = [last_env] + make_cmd
    run_command(make_cmd, build_dir, quiet)

    # Make install
    make_install_cmd = ['make', 'install']
    isolation_print_command(' '.join(make_install_cmd), build_dir)
    if last_env is not None:
        make_install_cmd = [last_env] + make_install_cmd
    run_command(make_install_cmd, build_dir, quiet)

    # If we are installing, and a env.sh exists, don't overwrite it
    if install and os.path.exists(os.path.join(installspace, 'env.sh')):
        return
    cprint(blue_arrow + " Generating an env.sh")
    # Generate env.sh for chaining to catkin packages
    # except if using --merge which implies that new_env_path equals last_env
    new_env_path = os.path.join(install_target, 'env.sh')
    if new_env_path != last_env:
        variables = {'SETUP_DIR': install_target, 'SETUP_FILENAME': 'setup'}
        with open(os.path.join(new_env_path), 'w') as f:
            f.write(
                configure_file(
                    os.path.join(get_cmake_path(), 'templates', 'env.sh.in'),
                    variables))
        os.chmod(new_env_path, stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR)

    # Generate setup.sh for chaining to catkin packages
    # except if using --merge which implies that new_setup_path equals last_setup_env
    new_setup_path = os.path.join(install_target, 'setup.sh')
    last_setup_env = os.path.join(os.path.dirname(last_env),
                                  'setup.sh') if last_env is not None else None
    if new_setup_path != last_setup_env:
        subs = {}
        subs['cmake_prefix_path'] = install_target + ":"
        subs['ld_path'] = os.path.join(install_target, 'lib') + ":"
        pythonpath = os.path.join(install_target, get_python_install_dir())
        subs['pythonpath'] = pythonpath + ':'
        subs['pkgcfg_path'] = os.path.join(install_target, 'lib', 'pkgconfig')
        subs['pkgcfg_path'] += ":"
        subs['path'] = os.path.join(install_target, 'bin') + ":"
        if not os.path.exists(install_target):
            os.mkdir(install_target)
        with open(new_setup_path, 'w+') as file_handle:
            file_handle.write("""\
#!/usr/bin/env sh
# generated from catkin.builder module

""")
            if last_env is not None:
                file_handle.write('. %s\n\n' % last_setup_env)
            file_handle.write("""\
# detect if running on Darwin platform
_UNAME=`uname -s`
IS_DARWIN=0
if [ "$_UNAME" = "Darwin" ]; then
  IS_DARWIN=1
fi

# Prepend to the environment
export CMAKE_PREFIX_PATH="{cmake_prefix_path}$CMAKE_PREFIX_PATH"
if [ $IS_DARWIN -eq 0 ]; then
  export LD_LIBRARY_PATH="{ld_path}$LD_LIBRARY_PATH"
else
  export DYLD_LIBRARY_PATH="{ld_path}$DYLD_LIBRARY_PATH"
fi
export PATH="{path}$PATH"
export PKG_CONFIG_PATH="{pkgcfg_path}$PKG_CONFIG_PATH"
export PYTHONPATH="{pythonpath}$PYTHONPATH"
""".format(**subs))
Example #14
0
def build_catkin_package(
    path, package,
    workspace, buildspace, develspace, installspace,
    install, force_cmake, quiet, last_env, cmake_args, make_args,
    destdir=None, use_ninja=False, use_nmake=False
):
    cprint(
        "Processing @{cf}catkin@| package: '@!@{bf}" +
        package.name + "@|'"
    )

    # Make the build dir
    build_dir = _check_build_dir(package.name, workspace, buildspace)

    # Check last_env
    if last_env is not None:
        cprint(
            blue_arrow + " Building with env: " +
            "'{0}'".format(last_env)
        )

    # Check for Makefile and maybe call cmake
    if not use_ninja:
        makefile_name = 'Makefile'
    else:
        makefile_name = 'build.ninja'
    makefile = os.path.join(build_dir, makefile_name)
    if not os.path.exists(makefile) or force_cmake:
        package_dir = os.path.dirname(package.filename)
        if not os.path.exists(os.path.join(package_dir, 'CMakeLists.txt')):
            export_tags = [e.tagname for e in package.exports]
            if 'metapackage' not in export_tags:
                print(colorize_line('Error: Package "%s" does not have a CMakeLists.txt file' % package.name))
                sys.exit('Can not build catkin package without CMakeLists.txt file')
            # generate CMakeLists.txt for metpackages without one
            print(colorize_line('Warning: metapackage "%s" should have a CMakeLists.txt file' % package.name))
            cmake_code = configure_file(
                get_metapackage_cmake_template_path(),
                {'name': package.name, 'metapackage_arguments': 'DIRECTORY "%s"' % package_dir})
            cmakelists_txt = os.path.join(build_dir, 'CMakeLists.txt')
            with open(cmakelists_txt, 'w') as f:
                f.write(cmake_code)
            package_dir = build_dir

        # Run cmake
        cmake_cmd = [
            'cmake',
            package_dir,
            '-DCATKIN_DEVEL_PREFIX=' + develspace,
            '-DCMAKE_INSTALL_PREFIX=' + installspace
        ]
        cmake_cmd.extend(cmake_args)
        add_env = get_additional_environment(install, destdir, installspace)
        isolation_print_command(' '.join(cmake_cmd), build_dir, add_env=add_env)
        if last_env is not None:
            cmake_cmd = [last_env] + cmake_cmd
        try:
            run_command_colorized(cmake_cmd, build_dir, quiet, add_env=add_env)
        except subprocess.CalledProcessError as e:
            if os.path.exists(makefile):
                # remove Makefile to force CMake invocation next time
                os.remove(makefile)
            raise
    else:
        print('%s exists, skipping explicit cmake invocation...' % makefile_name)
        # Check to see if cmake needs to be run via make
        if use_ninja:
            make_check_cmake_cmd = ['ninja', 'build.ninja']
        elif use_nmake:
            make_check_cmake_cmd = ['nmake', 'cmake_check_build_system']
        else:
            make_check_cmake_cmd = ['make', 'cmake_check_build_system']

        add_env = get_additional_environment(install, destdir, installspace)
        isolation_print_command(' '.join(make_check_cmake_cmd), build_dir, add_env=add_env)
        if last_env is not None:
            make_check_cmake_cmd = [last_env] + make_check_cmake_cmd
        run_command_colorized(
            make_check_cmake_cmd, build_dir, quiet, add_env=add_env
        )

    # Run make
    if use_ninja:
        make_executable = 'ninja'
    elif use_nmake:
        make_executable = 'nmake'
    else:
        make_executable = 'make'

    make_cmd = [make_executable]
    make_cmd.extend(handle_make_arguments(make_args))
    isolation_print_command(' '.join(make_cmd), build_dir)
    if last_env is not None:
        make_cmd = [last_env] + make_cmd
    run_command(make_cmd, build_dir, quiet)

    # Make install
    # NMake doesn't have an option to list target so try it anyway
    if install or use_nmake:
        if has_make_target(build_dir, 'install', use_ninja=use_ninja):
            make_install_cmd = [make_executable, 'install']
            isolation_print_command(' '.join(make_install_cmd), build_dir)
            if last_env is not None:
                make_install_cmd = [last_env] + make_install_cmd
            run_command(make_install_cmd, build_dir, quiet)
        else:
            print(fmt(
                '@{yf}Package has no "@{boldon}install@{boldoff}" target, skipping "%s install" invocation...'
                % make_executable))
Example #15
0
def build_catkin_package(
    path,
    package,
    workspace,
    buildspace,
    develspace,
    installspace,
    install,
    force_cmake,
    quiet,
    last_env,
    cmake_args,
    make_args,
    destdir=None,
):
    cprint("Processing @{cf}catkin@| package: '@!@{bf}" + package.name + "@|'")

    # Make the build dir
    build_dir = _check_build_dir(package.name, workspace, buildspace)

    # Check last_env
    if last_env is not None:
        cprint(blue_arrow + " Building with env: " + "'{0}'".format(last_env))

    # Check for Makefile and maybe call cmake
    makefile = os.path.join(build_dir, "Makefile")
    if not os.path.exists(makefile) or force_cmake:
        package_dir = os.path.dirname(package.filename)
        if not os.path.exists(os.path.join(package_dir, "CMakeLists.txt")):
            export_tags = [e.tagname for e in package.exports]
            if "metapackage" not in export_tags:
                print(colorize_line('Error: Package "%s" does not have a CMakeLists.txt file' % package.name))
                sys.exit("Can not build catkin package without CMakeLists.txt file")
            # generate CMakeLists.txt for metpackages without one
            print(colorize_line('Warning: metapackage "%s" should have a CMakeLists.txt file' % package.name))
            cmake_code = configure_file(
                get_metapackage_cmake_template_path(),
                {"name": package.name, "metapackage_arguments": 'DIRECTORY "%s"' % package_dir},
            )
            cmakelists_txt = os.path.join(build_dir, "CMakeLists.txt")
            with open(cmakelists_txt, "w") as f:
                f.write(cmake_code)
            package_dir = build_dir

        # Run cmake
        cmake_cmd = [
            "cmake",
            package_dir,
            "-DCATKIN_DEVEL_PREFIX=" + develspace,
            "-DCMAKE_INSTALL_PREFIX=" + installspace,
        ]
        cmake_cmd.extend(cmake_args)
        add_env = get_additional_environment(install, destdir, installspace)
        isolation_print_command(" ".join(cmake_cmd), build_dir, add_env=add_env)
        if last_env is not None:
            cmake_cmd = [last_env] + cmake_cmd
        try:
            run_command_colorized(cmake_cmd, build_dir, quiet, add_env=add_env)
        except subprocess.CalledProcessError as e:
            if os.path.exists(makefile):
                # remove Makefile to force CMake invocation next time
                os.remove(makefile)
            raise
    else:
        print("Makefile exists, skipping explicit cmake invocation...")
        # Check to see if cmake needs to be run via make
        make_check_cmake_cmd = ["make", "cmake_check_build_system"]
        add_env = get_additional_environment(install, destdir, installspace)
        isolation_print_command(" ".join(make_check_cmake_cmd), build_dir, add_env=add_env)
        if last_env is not None:
            make_check_cmake_cmd = [last_env] + make_check_cmake_cmd
        run_command_colorized(make_check_cmake_cmd, build_dir, quiet, add_env=add_env)

    # Run make
    make_cmd = ["make"]
    make_cmd.extend(handle_make_arguments(make_args, force_single_threaded_when_running_tests=True))
    isolation_print_command(" ".join(make_cmd), build_dir)
    if last_env is not None:
        make_cmd = [last_env] + make_cmd
    run_command(make_cmd, build_dir, quiet)

    # Make install
    if install:
        if has_make_target(build_dir, "install"):
            make_install_cmd = ["make", "install"]
            isolation_print_command(" ".join(make_install_cmd), build_dir)
            if last_env is not None:
                make_install_cmd = [last_env] + make_install_cmd
            run_command(make_install_cmd, build_dir, quiet)
        else:
            print(fmt('@{yf}Package has no "@{boldon}install@{boldoff}" target, skipping "make install" invocation...'))
Example #16
0
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):
    '''
    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``
    '''
    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))

    # Check devel space
    if develspace is None:
        develspace = os.path.join(workspace, 'devel_isolated')
    print('Devel space: ' + str(develspace))

    # 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 not use_ninja:
            cmake_args += ['-G', 'Unix Makefiles']
        else:
            cmake_args += ['-G', 'Ninja']
    elif use_ninja:
        print(
            colorize_line(
                "Error: either specify a generator using '-G...' or '--use-ninja' 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))
Example #17
0
def build_catkin_package(
    path, package,
    workspace, buildspace, develspace, installspace,
    install, jobs, force_cmake, quiet, cmake_args, make_args,
    catkin_python_path
):
    cprint(
        "Processing @{cf}catkin@| package: '@!@{bf}" +
        package.name + "@|'"
    )

    # Make the build dir
    build_dir = _check_build_dir(package.name, workspace, buildspace)

    # Help find catkin cmake and python
    env = os.environ.copy()
    try:
        env['PYTHONPATH'] = env['PYTHONPATH'] + os.pathsep + catkin_python_path
    except KeyError:
        env['PYTHONPATH'] = catkin_python_path

    # Check for Makefile and maybe call cmake
    makefile = os.path.join(build_dir, 'Makefile')
    # check if toolchain.cmake, config.cmake exist
    toolchain_cmd = "-DCMAKE_TOOLCHAIN_FILE=%s" % os.path.join(workspace, 'toolchain.cmake') if os.path.isfile(os.path.join(workspace, 'toolchain.cmake')) else None
    config_cmd = "-C%s" % os.path.join(workspace, 'config.cmake') if os.path.isfile(os.path.join(workspace, 'config.cmake')) else None
    if not os.path.exists(makefile) or force_cmake:
        package_dir = os.path.dirname(package.filename)
        if not os.path.exists(os.path.join(package_dir, 'CMakeLists.txt')):
            export_tags = [e.tagname for e in package.exports]
            if 'metapackage' not in export_tags:
                print(colorize_line('Error: Package "%s" does not have a CMakeLists.txt file' % package.name))
                raise RuntimeError('Can not build catkin package without CMakeLists.txt file')
            # generate CMakeLists.txt for metpackages without one
            print(colorize_line('Warning: metapackage "%s" should have a CMakeLists.txt file' % package.name))
            cmake_code = configure_file(
                get_metapackage_cmake_template_path(),
                {'name': package.name, 'metapackage_arguments': 'DIRECTORY "%s"' % package_dir})
            cmakelists_txt = os.path.join(build_dir, 'CMakeLists.txt')
            with open(cmakelists_txt, 'w') as f:
                f.write(cmake_code)
            package_dir = build_dir

        # Run cmake
        cmake_cmd = [
            'cmake',
            package_dir,
        ]
        if toolchain_cmd:
            cmake_cmd.append(toolchain_cmd)
        if config_cmd:
            cmake_cmd.append(config_cmd)
        cmake_cmd.extend(cmake_args)
        isolation_print_command(' '.join(cmake_cmd))
        #if last_env is not None:
        #    cmake_cmd = [last_env] + cmake_cmd
        try:
            run_command_colorized(cmake_cmd, build_dir, quiet, env=env)
        except subprocess.CalledProcessError as e:
            # remove Makefile to force CMake invocation next time
            os.remove(makefile)
            raise
    else:
        print('Makefile exists, skipping explicit cmake invocation...')
        # Check to see if cmake needs to be run via make
        make_check_cmake_cmd = ['make', 'cmake_check_build_system']
        isolation_print_command(' '.join(make_check_cmake_cmd), build_dir)
        #if last_env is not None:
        #    make_check_cmake_cmd = [last_env] + make_check_cmake_cmd
        run_command_colorized(
            make_check_cmake_cmd, build_dir, quiet, env=env
        )

    # Run make
    make_cmd = ['make', '-j' + str(jobs), '-l' + str(jobs)]
    make_cmd.extend(make_args)
    isolation_print_command(' '.join(make_cmd), build_dir)
    #if last_env is not None:
    #    make_cmd = [last_env] + make_cmd
    run_command(make_cmd, build_dir, quiet, env=env)

    # Make install
    if install:
        make_install_cmd = ['make', 'install']
        isolation_print_command(' '.join(make_install_cmd), build_dir)
        #if last_env is not None:
        #    make_install_cmd = [last_env] + make_install_cmd
        run_command(make_install_cmd, build_dir, quiet)
Example #18
0
import os
import shutil
import sys
import tempfile
import unittest

from catkin_pkg.cmake import configure_file

data = configure_file(os.path.join(os.path.dirname(__file__), '..', '..', 'cmake', 'templates', '_setup_util.py.in'),
                      {
                          'CATKIN_LIB_ENVIRONMENT_PATHS': "'lib'",
                          'CATKIN_PKGCONFIG_ENVIRONMENT_PATHS': "os.path.join('lib', 'pkgconfig')",
                          'CATKIN_GLOBAL_BIN_DESTINATION': 'bin',
                          'PYTHON_EXECUTABLE': sys.executable,
                          'PYTHON_INSTALL_DIR': 'pythonX.Y/packages',
                          'CMAKE_PREFIX_PATH_AS_IS': '',
                      })
with tempfile.NamedTemporaryFile('w+') as setup_util_file:
    setup_util_file.write(data)
    setup_util_file.seek(0)

    import imp
    imp.load_source('setup_util', setup_util_file.name, setup_util_file.file)

import setup_util
from setup_util import _get_workspaces, _prefix_env_variable, _rollback_env_variable, CATKIN_MARKER_FILE


class SetupUtilTest(unittest.TestCase):

    def test_get_reversed_workspaces(self):
Example #19
0
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,
):
    """
    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``
    """
    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))

    # Check devel space
    if develspace is None:
        develspace = os.path.join(workspace, "devel_isolated")
    print("Devel space: " + str(develspace))

    # 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 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,
                    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 " + os.path.join(buildspace, package.name) + " && "
                # Then reproduce the command called
                cmd += " ".join(e.cmd) if isinstance(e.cmd, list) else 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_GLOBAL_LIB_DESTINATION": "lib",
                    "CMAKE_PREFIX_PATH_AS_IS": ";".join(os.environ["CMAKE_PREFIX_PATH"].split(os.pathsep)),
                    "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)
                    )
Example #20
0
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):
    '''
    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. does not work with non-catkin 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]``
    '''
    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:
        ws_sourcespace = os.path.join(workspace, 'src')
        if not os.path.exists(ws_sourcespace):
            sys.exit("Could not find source space: {0}".format(sourcespace))
        sourcespace = ws_sourcespace
    sourcespace = os.path.abspath(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')
    buildspace = os.path.abspath(buildspace)
    if not os.path.exists(buildspace):
        os.mkdir(buildspace)
    print('Build space: ' + str(buildspace))

    # Check devel space
    if develspace is None:
        develspace = os.path.join(workspace, 'devel_isolated')
    develspace = os.path.abspath(develspace)
    print('Devel space: ' + str(develspace))

    # Check install space
    if installspace is None:
        installspace = os.path.join(workspace, 'install_isolated')
    installspace = os.path.abspath(installspace)
    print('Install space: ' + str(installspace))

    if cmake_args:
        print("Additional CMake Arguments: " + " ".join(cmake_args))
    else:
        cmake_args = []

    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))

    # verify that specified package exists in workspace
    if build_packages:
        packages_by_name = {p.name: path for path, p in packages.iteritems()}
        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:
        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
    if not force_cmake:
        force_cmake, install_toggled = cmake_input_changed(
            packages,
            buildspace,
            install=install,
            cmake_args=cmake_args,
            filename='catkin_make_isolated')
        if force_cmake:
            print(
                'The packages or cmake arguments have changed, forcing cmake invocation'
            )
        elif install_toggled:
            print(
                'The install argument has been toggled, forcing cmake invocation on plain cmake package'
            )

    # 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:
            try:
                export_tags = [e.tagname for e in package.exports]
                is_cmake_package = 'cmake' in [
                    e.content for e in package.exports
                    if e.tagname == 'build_type'
                ]
                last_env = build_package(
                    path,
                    package,
                    workspace,
                    buildspace,
                    pkg_develspace,
                    installspace,
                    install,
                    force_cmake or (install_toggled and is_cmake_package),
                    quiet,
                    last_env,
                    cmake_args,
                    make_args,
                    catkin_make_args,
                    number=index + 1,
                    of=len(ordered_packages))
            except Exception as e:
                import traceback
                traceback.print_exc()
                cprint('@{rf}@!<==@| ' +
                       'Failed to process package \'@!@{bf}' + package.name +
                       '@|\': \n  ' + ('KeyboardInterrupt' if isinstance(
                           e, KeyboardInterrupt) else str(e)))
                if isinstance(e, subprocess.CalledProcessError):
                    cmd = ' '.join(e.cmd) if isinstance(e.cmd, list) else e.cmd
                    print(fmt("\n@{rf}Reproduce this error by running:"))
                    print(fmt("@{gf}@!==> @|") + cmd + "\n")
                sys.exit('Command failed, exiting.')
        else:
            cprint("Skipping package: '@!@{bf}" + package.name + "@|'")
            last_env = get_new_env(package, pkg_develspace, installspace,
                                   install, last_env)

    # 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_sh = os.path.join(develspace, 'setup.sh')
        generated_setup_util_py = os.path.join(develspace, '_setup_util.py')
        if not merge and pkg_develspace:
            # generate env.sh and setup.sh 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)
            with open(generated_setup_sh, 'w') as f:
                f.write("""\
#!/usr/bin/env sh
# generated from catkin.builder module

. "{0}/setup.sh"
""".format(pkg_develspace))

        elif not pkg_develspace:
            # generate env.sh and setup.sh for an empty devel space
            if 'CMAKE_PREFIX_PATH' in os.environ.keys():
                variables = {
                    'CATKIN_GLOBAL_BIN_DESTINATION':
                    'bin',
                    'CATKIN_GLOBAL_LIB_DESTINATION':
                    'lib',
                    'CMAKE_PREFIX_PATH_AS_IS':
                    ';'.join(os.environ['CMAKE_PREFIX_PATH'].split(
                        os.pathsep)),
                    'PYTHON_INSTALL_DIR':
                    get_python_install_dir(),
                    'SETUP_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.sh.in'), variables))
            os.chmod(generated_env_sh,
                     stat.S_IXUSR | stat.S_IWUSR | stat.S_IRUSR)
            variables = {'SETUP_DIR': develspace}
            with open(generated_setup_sh, 'w') as f:
                f.write(
                    configure_file(
                        os.path.join(get_cmake_path(), 'templates',
                                     'setup.sh.in'), variables))

        if not merge and pkg_develspace:
            # remove _setup_util.py file which might have been generated for an empty
            if os.path.exists(generated_setup_util_py):
                os.remove(generated_setup_util_py)

        if not merge or not pkg_develspace:
            # generate setup.bash and setup.zsh for convenience
            variables = {'SETUP_DIR': develspace}
            with open(os.path.join(develspace, 'setup.bash'), 'w') as f:
                f.write(
                    configure_file(
                        os.path.join(get_cmake_path(), 'templates',
                                     'setup.bash.in'), variables))
            with open(os.path.join(develspace, 'setup.zsh'), 'w') as f:
                f.write(
                    configure_file(
                        os.path.join(get_cmake_path(), 'templates',
                                     'setup.zsh.in'), variables))
Example #21
0
import os
import shutil
import tempfile
import unittest

from catkin_pkg.cmake import configure_file

data = configure_file(os.path.join(os.path.dirname(__file__), '..', '..', 'cmake', 'templates', '_setup_util.py.in'),
                      {
                          'CATKIN_GLOBAL_LIB_DESTINATION': 'lib',
                          'CATKIN_GLOBAL_BIN_DESTINATION': 'bin',
                          'PYTHON_INSTALL_DIR': 'pythonX.Y/packages',
                          'CMAKE_PREFIX_PATH_AS_IS': '',
                      })
with tempfile.TemporaryFile() as setup_util_file:
    setup_util_file.write(data)
    setup_util_file.seek(0)

    import imp
    imp.load_source('setup_util', '/somewhere/_setup_util.py', setup_util_file)

import setup_util
from setup_util import _get_workspaces, _prefix_env_variable, _rollback_env_variable, CATKIN_MARKER_FILE


class SetupUtilTest(unittest.TestCase):

    def test_get_reversed_workspaces(self):
        try:
            rootdir = tempfile.mkdtemp()
            mock_env = {}