Skip to content

Commit

Permalink
add --use-ninja option to catkin_make(_isolated) to use ninja instead…
Browse files Browse the repository at this point in the history
… of make
  • Loading branch information
dirk-thomas committed Oct 23, 2014
1 parent c58b1d7 commit 046aace
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 27 deletions.
28 changes: 23 additions & 5 deletions bin/catkin_make
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,22 @@ def main():
print(fmt('@{yf}Packages @{boldon}"%s"@{boldoff} not found in the workspace - ignoring them' % ', '.join(sorted(unknown_packages))), file=sys.stderr)
args.pkg = [name for name in args.pkg if name in packages_by_name]

if not [arg for arg in cmake_args if arg.startswith('-G')]:
if not args.use_ninja:
cmake_args += ['-G', 'Unix Makefiles']
else:
cmake_args += ['-G', 'Ninja']
elif args.use_ninja:
return fmt("@{rf}Error: either specify a generator using '-G...' or '--use-ninja' but not both")

# check if cmake must be run (either for a changed list of package paths or changed cmake arguments)
force_cmake = cmake_input_changed(packages, build_path, cmake_args=cmake_args)

# consider calling cmake
makefile = os.path.join(build_path, 'Makefile')
if not args.use_ninja:
makefile = os.path.join(build_path, 'Makefile')
else:
makefile = os.path.join(build_path, 'build.ninja')
if not os.path.exists(makefile) or args.force_cmake or force_cmake:
cmd = [
'cmake',
Expand All @@ -155,20 +166,26 @@ def main():
except subprocess.CalledProcessError:
return fmt('@{rf}Invoking @{boldon}"cmake"@{boldoff} failed')
else:
cmd = ['make', 'cmake_check_build_system']
if not args.use_ninja:
cmd = ['make', 'cmake_check_build_system']
else:
cmd = ['ninja', 'build.ninja']
try:
print_command_banner(cmd, build_path, color=not args.no_color)
if args.no_color:
run_command(cmd, build_path)
else:
run_command_colorized(cmd, build_path)
except subprocess.CalledProcessError:
return fmt('@{rf}Invoking @{boldon}"make cmake_check_build_system"@{boldoff} failed')
return fmt('@{rf}Invoking @{boldon}"%s"@{boldoff} failed' % ' '.join(cmd))

ensure_workspace_marker(base_path)

# invoke make
cmd = ['make']
if not args.use_ninja:
cmd = ['make']
else:
cmd = ['ninja']
cmd.extend(handle_make_arguments(args.make_args))
try:
if not args.pkg:
Expand All @@ -179,7 +196,7 @@ def main():
print_command_banner(cmd, make_path, color=not args.no_color)
run_command(cmd, make_path)
except subprocess.CalledProcessError:
return fmt('@{rf}Invoking @{boldon}"make"@{boldoff} failed')
return fmt('@{rf}Invoking @{boldon}"%s"@{boldoff} failed' % ' '.join(cmd))


def _parse_args(args=sys.argv[1:]):
Expand All @@ -202,6 +219,7 @@ def _parse_args(args=sys.argv[1:]):
add('-C', '--directory', default=os.curdir, help="The base path of the workspace (default '%s')" % os.curdir)
add('--source', help="The path to the source space (default 'workspace_base/src')")
add('--build', help="The path to the build space (default 'workspace_base/build')")
add('--use-ninja', action='store_true', help="Use 'ninja' instead of 'make'")
add('--force-cmake', action='store_true', help="Invoke 'cmake' even if it has been executed before")
add('--no-color', action='store_true', help='Disables colored output (only for catkin_make and CMake)')
add('--pkg', nargs='+', help="Invoke 'make' on specific packages only")
Expand Down
4 changes: 3 additions & 1 deletion bin/catkin_make_isolated
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ def parse_args(args=None):
help='Build each catkin package into a common devel space.')
add('--install-space', default=None,
help="Sets the target install space (default 'workspace_base/install_isolated')")
add('--use-ninja', action='store_true', help="Use 'ninja' instead of 'make'")
add('--install', action='store_true', default=False,
help='Causes each catkin package to be installed.')
add('--force-cmake', action='store_true', default=False,
Expand Down Expand Up @@ -142,7 +143,8 @@ def main():
catkin_make_args=opts.catkin_make_args,
continue_from_pkg=opts.from_package is not None,
only_pkg_with_deps=opts.only_pkg_with_deps,
destdir=destdir
destdir=destdir,
use_ninja=opts.use_ninja
)

if __name__ == '__main__':
Expand Down
3 changes: 3 additions & 0 deletions cmake/env-hooks/05.catkin_make.bash
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ function _catkin_make()
if [ -f "$makefile_dir/Makefile" ]; then
cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=( $( compgen -W "`make -C $makefile_dir -qp 2>/dev/null | awk -F':' '/^[a-zA-Z0-9][a-zA-Z0-9_\.]*:/ { print $1 }'`" -- $cur ))
elif [ -f "$makefile_dir/build.ninja" ]; then
cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=( $( compgen -W "`ninja -C $makefile_dir -t targets 2>/dev/null | awk -F':' '/^[a-zA-Z0-9][a-zA-Z0-9_\.]*:/ { print $1 }'`" -- $cur ))
fi
fi
} &&
Expand Down
3 changes: 3 additions & 0 deletions cmake/env-hooks/05.catkin_make_isolated.bash
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ function _catkin_make_isolated()
if [ -f "$makefile_dir/Makefile" ]; then
cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=( $( compgen -W "`make -C $makefile_dir -qp 2>/dev/null | awk -F':' '/^[a-zA-Z0-9][a-zA-Z0-9_\.]*:/ { print $1 }'`" -- $cur ))
elif [ -f "$makefile_dir/build.ninja" ]; then
cur=${COMP_WORDS[COMP_CWORD]}
COMPREPLY=( $( compgen -W "`ninja -C $makefile_dir -t targets 2>/dev/null | awk -F':' '/^[a-zA-Z0-9][a-zA-Z0-9_\.]*:/ { print $1 }'`" -- $cur ))
fi
fi
} &&
Expand Down
81 changes: 60 additions & 21 deletions python/catkin/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def build_catkin_package(
path, package,
workspace, buildspace, develspace, installspace,
install, force_cmake, quiet, last_env, cmake_args, make_args,
destdir=None
destdir=None, use_ninja=False
):
cprint(
"Processing @{cf}catkin@| package: '@!@{bf}" +
Expand All @@ -352,7 +352,11 @@ def build_catkin_package(
)

# Check for Makefile and maybe call cmake
makefile = os.path.join(build_dir, 'Makefile')
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')):
Expand Down Expand Up @@ -390,9 +394,12 @@ def build_catkin_package(
os.remove(makefile)
raise
else:
print('Makefile exists, skipping explicit cmake invocation...')
print('%s exists, skipping explicit cmake invocation...' % makefile_name)
# Check to see if cmake needs to be run via make
make_check_cmake_cmd = ['make', 'cmake_check_build_system']
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:
Expand All @@ -402,7 +409,11 @@ def build_catkin_package(
)

# Run make
make_cmd = ['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:
Expand All @@ -411,19 +422,25 @@ def build_catkin_package(

# Make install
if install:
if has_make_target(build_dir, 'install'):
make_install_cmd = ['make', '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 "make install" invocation...'))
print(fmt('@{yf}Package has no "@{boldon}install@{boldoff}" target, skipping "%s install" invocation...' % make_executable))


def has_make_target(path, target):
output = run_command(['make', '-pn'], path, quiet=True)
def has_make_target(path, target, use_ninja=False):
if not use_ninja:
output = run_command(['make', '-pn'], path, quiet=True)
else:
output = run_command(['ninja', '-t', 'targets'], path, quiet=True)
lines = output.splitlines()
# strip nanja warnings since they look similar to targets
if use_ninja:
lines = [l for l in lines if not l.startswith('ninja: warning:')]
targets = [m.group(1) for m in [re.match('^([a-zA-Z0-9][a-zA-Z0-9_\.]*):', l) for l in lines] if m]
return target in targets

Expand All @@ -439,7 +456,7 @@ def build_cmake_package(
path, package,
workspace, buildspace, develspace, installspace,
install, force_cmake, quiet, last_env, cmake_args, make_args,
destdir=None
destdir=None, use_ninja=False
):
# Notify the user that we are processing a plain cmake package
cprint(
Expand All @@ -460,7 +477,11 @@ def build_cmake_package(
"'{0}'".format(last_env))

# Check for Makefile and maybe call cmake
makefile = os.path.join(build_dir, 'Makefile')
if not use_ninja:
makefile_name = 'Makefile'
else:
makefile_name = 'build.ninja'
makefile = os.path.join(build_dir, makefile_name)
install_target = installspace if install else develspace
if not os.path.exists(makefile) or force_cmake:
# Call cmake
Expand All @@ -475,9 +496,12 @@ def build_cmake_package(
cmake_cmd = [last_env] + cmake_cmd
run_command_colorized(cmake_cmd, build_dir, quiet)
else:
print('Makefile exists, skipping explicit cmake invocation...')
print('%s exists, skipping explicit cmake invocation...' % makefile_name)
# Check to see if cmake needs to be run via make
make_check_cmake_cmd = ['make', 'cmake_check_build_system']
if not use_ninja:
make_check_cmake_cmd = ['make', 'cmake_check_build_system']
else:
make_check_cmake_cmd = ['ninja', 'build.ninja']
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
Expand All @@ -486,7 +510,11 @@ def build_cmake_package(
)

# Run make
make_cmd = ['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:
Expand All @@ -497,7 +525,7 @@ def build_cmake_package(
run_command(make_cmd, build_dir, quiet, add_env={'DESTDIR': ''})

# Make install
make_install_cmd = ['make', 'install']
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
Expand Down Expand Up @@ -610,7 +638,7 @@ def build_package(
path, package,
workspace, buildspace, develspace, installspace,
install, force_cmake, quiet, last_env, cmake_args, make_args, catkin_make_args,
destdir=None,
destdir=None, use_ninja=False,
number=None, of=None
):
if platform.system() in ['Linux', 'Darwin']:
Expand All @@ -624,7 +652,7 @@ def build_package(
path, package,
workspace, buildspace, develspace, installspace,
install, force_cmake, quiet, last_env, cmake_args, make_args + catkin_make_args,
destdir=destdir
destdir=destdir, use_ninja=use_ninja
)
if not os.path.exists(new_last_env):
raise RuntimeError(
Expand All @@ -638,7 +666,7 @@ def build_package(
path, package,
workspace, buildspace, develspace, installspace,
install, force_cmake, quiet, last_env, cmake_args, make_args,
destdir=destdir
destdir=destdir, use_ninja=use_ninja
)
else:
sys.exit('Can not build package with unknown build_type')
Expand Down Expand Up @@ -699,7 +727,8 @@ def build_workspace_isolated(
catkin_make_args=None,
continue_from_pkg=False,
only_pkg_with_deps=None,
destdir=None
destdir=None,
use_ninja=False
):
'''
Runs ``cmake``, ``make`` and optionally ``make install`` for all
Expand Down Expand Up @@ -734,6 +763,7 @@ def build_workspace_isolated(
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()
Expand Down Expand Up @@ -773,6 +803,15 @@ def build_workspace_isolated(
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:
Expand Down Expand Up @@ -871,7 +910,7 @@ def build_workspace_isolated(
workspace, buildspace, pkg_develspace, installspace,
install, force_cmake,
quiet, last_env, cmake_args, make_args, catkin_make_args,
destdir=destdir,
destdir=destdir, use_ninja=use_ninja,
number=index + 1, of=len(ordered_packages)
)
except subprocess.CalledProcessError as e:
Expand Down

0 comments on commit 046aace

Please sign in to comment.