Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support ament_cmake_python for pkg create #904

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions ros2pkg/ros2pkg/api/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ def create_package_environment(package, destination_directory):
if package.get_build_type() == 'ament_python':
print('creating source folder')
source_directory = _create_folder(package.name, package_directory)
if package.get_build_type() == 'ament_cmake_python':
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are currently no instances of ROS 2 packages where this would be true. That is, package.get_build_type() will never return ament_cmake_python.

That said, it would still be worthwhile to have some way to create a package template for a Python package using CMake. However, it will have to be done a different way because it will use a build_type of ament_cmake. Maybe we can add in a new command-line argument that tells it to generate Python installation stuff in the CMakeLists.txt?

Copy link
Author

@m12watanabe1a m12watanabe1a Apr 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can add in a new command-line argument that tells it to generate Python installation stuff in the CMakeLists.txt?

I see. I agree with that build_type is not appropriate field for generating templates.

So maybe something like like,

ros2 pkg create --build-type ament_cmake --template-name ament_cmake_python <package_name>

print('creating source folder')
source_directory = _create_folder('src', package_directory)
include_directory = _create_folder(package.name, package_directory + os.sep + 'inlclude')

return package_directory, source_directory, include_directory

Expand Down Expand Up @@ -291,3 +295,27 @@ def populate_cpp_library(package, source_directory, include_directory, cpp_libra
include_directory,
'visibility_control.h',
visibility_config)


def populate_ament_cmake_python(package, package_directory, cpp_node_name, cpp_library_name):
cmakelists_config = {
'project_name': package.name,
'dependencies': [str(dep) for dep in package.build_depends],
'cpp_node_name': cpp_node_name,
'cpp_library_name': cpp_library_name,
}
_create_template_file(
'ament_cmake_python',
'CMakeLists.txt.em',
package_directory,
'CMakeLists.txt',
cmakelists_config)

_create_folder(package.name, package_directory)
_create_template_file('ament_cmake_python',
'init.py.em',
package_directory + os.sep + package.name,
'__init__.py',
{})

test_directory = _create_folder('test', package_directory)
118 changes: 118 additions & 0 deletions ros2pkg/ros2pkg/resource/ament_cmake_python/CMakeLists.txt.em
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
cmake_minimum_required(VERSION 3.8)
project(@(project_name))

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(ament_cmake_python REQUIRED)
@[if cpp_library_name]@
find_package(ament_cmake_ros REQUIRED)
@[end if]@
@[if dependencies]@
@[ for dep in dependencies]@
find_package(@dep REQUIRED)
@[ end for]@
@[else]@
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
@[end if]@

@[if cpp_library_name]@
add_library(@(cpp_library_name) src/@(cpp_library_name).cpp)
add_library(@(project_name)::@(cpp_library_name) ALIAS @(cpp_library_name))
target_compile_features(@(cpp_library_name) PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17
target_include_directories(@(cpp_library_name) PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>)
@[ if dependencies]@
ament_target_dependencies(
@(cpp_library_name)
@[ for dep in dependencies]@
"@(dep)"
@[ end for]@
)
@[ end if]@

# Causes the visibility macros to use dllexport rather than dllimport,
# which is appropriate when building the dll but not consuming it.
target_compile_definitions(@(cpp_library_name) PRIVATE "@(project_name.upper())_BUILDING_LIBRARY")

install(
DIRECTORY include/
DESTINATION include/${PROJECT_NAME}
)
install(
TARGETS @(cpp_library_name)
EXPORT export_${PROJECT_NAME}
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)
@[end if]@
@[if cpp_node_name]@

add_executable(@(cpp_node_name) src/@(cpp_node_name).cpp)
target_include_directories(@(cpp_node_name) PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>)
@[ if cpp_library_name]@
target_link_libraries(@(cpp_node_name) @(cpp_library_name))
@[ else]@
target_compile_features(@(cpp_node_name) PUBLIC c_std_99 cxx_std_17) # Require C99 and C++17
@[ if dependencies]@
ament_target_dependencies(
@(cpp_node_name)
@[ for dep in dependencies]@
"@(dep)"
@[ end for]@
)
@[ end if]@
@[ end if]@

install(TARGETS @(cpp_node_name)
DESTINATION lib/${PROJECT_NAME})
@[end if]@

ament_python_install_package(${PROJECT_NAME})

if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
find_package(ament_cmake_pytest REQUIRED)
# the following line skips the linter which checks for copyrights
# comment the line when a copyright and license is added to all source files
set(ament_cmake_copyright_FOUND TRUE)
# the following line skips cpplint (only works in a git repo)
# comment the line when this package is in a git repo and when
# a copyright and license is added to all source files
set(ament_cmake_cpplint_FOUND TRUE)
ament_lint_auto_find_test_dependencies()
set(_pytest_tests
# Add test files here
)
foreach(_test_path ${_pytest_tests})
get_filename_component(_test_name ${_test_path} NAME_WE)
ament_add_pytest_test(${_test_name} ${_test_path}
APPEND_ENV PYTHONPATH=${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 60
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
endforeach()
endif()
@[if cpp_library_name]@

ament_export_include_directories(
"include/${PROJECT_NAME}"
)
ament_export_libraries(
@(cpp_library_name)
)
ament_export_targets(
export_${PROJECT_NAME}
)
@[end if]@

ament_package()
Empty file.
Empty file.
22 changes: 19 additions & 3 deletions ros2pkg/ros2pkg/verb/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from ros2pkg.api.create import create_package_environment
from ros2pkg.api.create import populate_ament_cmake
from ros2pkg.api.create import populate_ament_cmake_python
from ros2pkg.api.create import populate_ament_python
from ros2pkg.api.create import populate_cmake
from ros2pkg.api.create import populate_cpp_library
Expand Down Expand Up @@ -68,7 +69,7 @@ def add_arguments(self, parser, cli_name):
parser.add_argument(
'--build-type',
default='ament_cmake',
choices=['cmake', 'ament_cmake', 'ament_python'],
choices=['cmake', 'ament_cmake', 'ament_python', 'ament_cmake_python'],
help='The build type to process the package with')
parser.add_argument(
'--dependencies',
Expand Down Expand Up @@ -132,13 +133,21 @@ def main(self, *, args):
buildtool_depends = ['ament_cmake_ros']
else:
buildtool_depends = ['ament_cmake']
if args.build_type == 'ament_cmake_python':
if args.library_name:
buildtool_depends = ['ament_cmake_ros']
else:
buildtool_depends = ['ament_cmake']
buildtool_depends.append('ament_cmake_python')

test_dependencies = []
if args.build_type == 'ament_cmake':
test_dependencies = ['ament_lint_auto', 'ament_lint_common']
if args.build_type == 'ament_python':
test_dependencies = ['ament_copyright', 'ament_flake8', 'ament_pep257',
'python3-pytest']
if args.build_type == 'ament_cmake_python':
test_dependencies = ['ament_lint_auto', 'ament_lint_common', 'ament_cmake_pytest']

if args.build_type == 'ament_python' and args.package_name == 'test':
# If the package name is 'test', there will be a conflict between
Expand All @@ -147,6 +156,10 @@ def main(self, *, args):
return "Aborted since 'ament_python' packages can't be named 'test'. Please " + \
'choose a different package name.'

export_build_type = args.build_type
if args.build_type == 'ament_cmake_python':
export_build_type = 'ament_cmake'

package = Package(
package_format=args.package_format,
name=args.package_name,
Expand All @@ -157,7 +170,7 @@ def main(self, *, args):
buildtool_depends=[Dependency(dep) for dep in buildtool_depends],
build_depends=[Dependency(dep) for dep in args.dependencies],
test_depends=[Dependency(dep) for dep in test_dependencies],
exports=[Export('build_type', content=args.build_type)]
exports=[Export('build_type', content=export_build_type)]
)

package_path = os.path.join(args.destination_directory, package.name)
Expand Down Expand Up @@ -200,7 +213,10 @@ def main(self, *, args):
if library_name:
populate_python_libary(package, source_directory, library_name)

if args.build_type == 'ament_cmake' or args.build_type == 'cmake':
if args.build_type == 'ament_cmake_python':
populate_ament_cmake_python(package, package_directory, node_name, library_name)

if args.build_type == 'ament_cmake' or args.build_type == 'cmake' or args.build_type == 'ament_cmake_python':
if node_name:
if not source_directory:
return 'unable to create source folder in ' + args.destination_directory
Expand Down