Skip to content

Commit

Permalink
modified cmi to be able to build metapackages without CMakeLists.txt (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dirk-thomas committed Mar 1, 2013
1 parent 9b2e409 commit d85b0a3
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 21 deletions.
33 changes: 17 additions & 16 deletions cmake/catkin_metapackage.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
# immediately after calling ``project()`` and
# ``find_package(catkin REQUIRED)``.
#
# :param DIRECTORY: the path to the package.xml file if not in the same
# location as the CMakeLists.txt file
# :type DIRECTORY: string
#
# @public
#
function(catkin_metapackage)
if(ARGN)
message(FATAL_ERROR "catkin_metapackage() called with unused arguments: ${ARGN}")
cmake_parse_arguments(ARG "" "DIRECTORY" "" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "catkin_metapackage() called with unused arguments: ${ARG_UNPARSED_ARGUMENTS}")
endif()

debug_message(10 "catkin_metapackage() called in file ${CMAKE_CURRENT_LIST_FILE}")

# verify that project() has been called before
if(NOT PROJECT_NAME)
message(FATAL_ERROR "catkin_metapackage() PROJECT_NAME is not set. You must call project() before calling catkin_metapackage().")
Expand All @@ -23,22 +26,20 @@ function(catkin_metapackage)
message(FATAL_ERROR "catkin_metapackage() PROJECT_NAME is set to 'Project', which is not a valid project name. You must call project() before calling catkin_metapackage().")
endif()

cmake_parse_arguments(PROJECT "" "" "INCLUDE_DIRS;LIBRARIES;CATKIN_DEPENDS;DEPENDS;CFG_EXTRAS" ${ARGN})
if(PROJECT_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "catkin_package() called with unused arguments: ${PROJECT_UNPARSED_ARGUMENTS}")
endif()
debug_message(10 "catkin_metapackage() called in file ${CMAKE_CURRENT_LIST_FILE}")

# call catkin_package_xml()
if(${CMAKE_CURRENT_LIST_FILE} STREQUAL ${CMAKE_BINARY_DIR}/catkin_generated/metapackages/${PROJECT_NAME}/CMakeLists.txt)
set(package_dir ${CMAKE_SOURCE_DIR}/${path})
catkin_package_xml(DIRECTORY ${CMAKE_SOURCE_DIR}/${path})
else()
set(package_dir ${CMAKE_CURRENT_SOURCE_DIR})
catkin_package_xml()
if(NOT ARG_DIRECTORY)
if(${CMAKE_CURRENT_LIST_FILE} STREQUAL ${CMAKE_BINARY_DIR}/catkin_generated/metapackages/${PROJECT_NAME}/CMakeLists.txt)
set(ARG_DIRECTORY ${CMAKE_SOURCE_DIR}/${path})
else()
set(ARG_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
endif()
endif()

catkin_package_xml(DIRECTORY ${ARG_DIRECTORY})

# install package.xml
install(FILES ${package_dir}/package.xml
install(FILES ${ARG_DIRECTORY}/package.xml
DESTINATION share/${PROJECT_NAME}
)
endfunction()
2 changes: 2 additions & 0 deletions cmake/catkin_workspace.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function(catkin_workspace)
if(${is_meta})
message(STATUS "~~ - ${name} (metapackage)")
# verify that CMakeLists.txt of metapackage conforms to standard
set(metapackage_arguments "")
configure_file(${catkin_EXTRAS_DIR}/templates/metapackage.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/catkin_generated/metapackages/${name}/CMakeLists.txt
@ONLY)
Expand Down Expand Up @@ -98,6 +99,7 @@ function(catkin_workspace)
add_subdirectory(${path})
else()
message(STATUS "==> add_subdirectory(${path}) (using generated file from <buildspace>/catkin_generated/metapackages/${name})")
message("WARNING: Add a CMakeLists.txt file to the metapackage '${name}'")
add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/catkin_generated/metapackages/${name} ${CMAKE_BINARY_DIR}/${path})
endif()
elseif(${build_type} MATCHES catkin)
Expand Down
2 changes: 1 addition & 1 deletion cmake/templates/metapackage.cmake.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 2.8.3)
project(@name@)
find_package(catkin REQUIRED)
catkin_metapackage()
catkin_metapackage(@metapackage_arguments@)
19 changes: 15 additions & 4 deletions python/catkin/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
'"catkin_pkg", it is up to date and on the PYTHONPATH.' % e
)

from catkin.cmake import configure_file, get_cmake_path
from catkin.terminal_color import ansi, disable_ANSI_colors, fmt, sanitize


Expand Down Expand Up @@ -212,14 +213,24 @@ def build_catkin_package(
# Check for Makefile and maybe call cmake
makefile = os.path.join(build_dir, 'Makefile')
if not os.path.exists(makefile) or force_cmake:
if not os.path.exists(os.path.join(os.path.dirname(package.filename), 'CMakeLists.txt')):
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')
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(os.path.join(get_cmake_path(), 'templates', 'metapackage.cmake.in'), {'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',
os.path.dirname(package.filename),
package_dir,
'-DCATKIN_DEVEL_PREFIX=' + develspace,
'-DCMAKE_INSTALL_PREFIX=' + installspace
]
Expand Down
82 changes: 82 additions & 0 deletions python/catkin/cmake.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Software License Agreement (BSD License)
#
# Copyright (c) 2013, Open Source Robotics Foundation, Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided
# with the distribution.
# * Neither the name of Open Source Robotics Foundation, Inc. nor
# the names of its contributors may be used to endorse or promote
# products derived from this software without specific prior
# written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

from __future__ import print_function

import os
import re

from catkin.find_in_workspaces import find_in_workspaces


def get_cmake_path():
relpath = os.path.join(os.path.dirname(__file__), '..', '..', 'cmake')
if os.path.exists(relpath):
return os.path.normpath(relpath)
paths = find_in_workspaces(['share'], 'catkin', first_matching_workspace_only=True, first_match_only=True)
if not paths:
raise RuntimeError('Could not determine catkin cmake path')
return os.path.join(paths[0], 'cmake')


def configure_file(template_file, environment):
'''
Evaluate a .in template file used in CMake with configure_file().
:param template_file: path to the template, ``str``
:param environment: dictionary of placeholders to substitute,
``dict``
:returns: string with evaluates template
:raises: KeyError for placeholders in the template which are not
in the environment
'''
with open(template_file, 'r') as f:
template = f.read()
return configure_string(template, environment)


def configure_string(template, environment):
'''
Substitute variables enclosed by @ characters.
:param template: the template, ``str``
:param environment: dictionary of placeholders to substitute,
``dict``
:returns: string with evaluates template
:raises: KeyError for placeholders in the template which are not
in the environment
'''
def substitute(match):
var = match.group(0)[1:-1]
return environment[var]
return re.sub('\@[a-zA-Z0-9_]+\@', substitute, template)

0 comments on commit d85b0a3

Please sign in to comment.