Skip to content

Commit 3bbbabb

Browse files
nadavelkabetsrkent
authored andcommitted
Add separate package for testing ament_cmake_python
1 parent 17d4da4 commit 3bbbabb

File tree

14 files changed

+318
-119
lines changed

14 files changed

+318
-119
lines changed

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
5+
build/
6+
install/
7+
log/
8+
docker

ament_cmake_python/ament_cmake_python-extras.cmake

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,17 @@ print(os.path.relpath(sysconfig.get_path('purelib', **kwargs), start='${CMAKE_IN
7979
endif()
8080
endmacro()
8181

82+
macro(_ament_cmake_python_register_extension_hook)
83+
if(NOT DEFINED AMENT_CMAKE_PYTHON_EXTENSION_REGISTERED)
84+
set(AMENT_CMAKE_PYTHON_EXTENSION_REGISTERED TRUE)
85+
86+
ament_register_extension(
87+
"ament_package"
88+
"ament_cmake_python"
89+
"ament_python_install_registered_packages.cmake")
90+
endif()
91+
endmacro()
92+
8293
include("${ament_cmake_python_DIR}/ament_python_install_module.cmake")
8394
include("${ament_cmake_python_DIR}/ament_python_install_package.cmake")
8495
include("${ament_cmake_python_DIR}/ament_get_python_install_dir.cmake")

ament_cmake_python/cmake/ament_python_install_package.cmake

Lines changed: 26 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
# :type SKIP_COMPILE: option
3636
#
3737
macro(ament_python_install_package)
38+
_ament_cmake_python_register_extension_hook()
3839
_ament_cmake_python_register_environment_hook()
3940
_ament_cmake_python_install_package(${ARGN})
4041
endmacro()
@@ -83,129 +84,35 @@ function(_ament_cmake_python_install_package package_name)
8384
set(ARG_DESTINATION ${PYTHON_INSTALL_DIR})
8485
endif()
8586

86-
set(build_dir "${CMAKE_CURRENT_BINARY_DIR}/ament_cmake_python/${package_name}")
87-
88-
string(CONFIGURE "\
89-
from setuptools import find_packages
90-
from setuptools import setup
91-
92-
setup(
93-
name='${package_name}',
94-
version='${ARG_VERSION}',
95-
packages=find_packages(
96-
include=('${package_name}', '${package_name}.*')),
97-
)
98-
" setup_py_content)
99-
100-
file(GENERATE
101-
OUTPUT "${build_dir}/setup.py"
102-
CONTENT "${setup_py_content}"
103-
)
104-
105-
if(AMENT_CMAKE_SYMLINK_INSTALL)
106-
add_custom_target(
107-
ament_cmake_python_symlink_${package_name}
108-
COMMAND ${CMAKE_COMMAND} -E create_symlink
109-
"${ARG_PACKAGE_DIR}" "${build_dir}/${package_name}"
110-
)
111-
set(egg_dependencies ament_cmake_python_symlink_${package_name})
112-
113-
if(ARG_SETUP_CFG)
114-
add_custom_target(
115-
ament_cmake_python_symlink_${package_name}_setup
116-
COMMAND ${CMAKE_COMMAND} -E create_symlink
117-
"${ARG_SETUP_CFG}" "${build_dir}/setup.cfg"
118-
)
119-
list(APPEND egg_dependencies ament_cmake_python_symlink_${package_name}_setup)
120-
endif()
87+
get_property(_pkgs GLOBAL PROPERTY AMENT_CMAKE_PYTHON_PKGS)
88+
list(FIND _pkgs "${package_name}" _idx)
89+
if(_idx EQUAL -1)
90+
set_property(GLOBAL APPEND PROPERTY AMENT_CMAKE_PYTHON_PKGS "${package_name}")
12191
else()
122-
add_custom_target(
123-
ament_cmake_python_copy_${package_name}
124-
COMMAND ${CMAKE_COMMAND} -E copy_directory
125-
"${ARG_PACKAGE_DIR}" "${build_dir}/${package_name}"
126-
)
127-
set(egg_dependencies ament_cmake_python_copy_${package_name})
128-
129-
if(ARG_SETUP_CFG)
130-
add_custom_target(
131-
ament_cmake_python_copy_${package_name}_setup
132-
COMMAND ${CMAKE_COMMAND} -E copy
133-
"${ARG_SETUP_CFG}" "${build_dir}/setup.cfg"
134-
)
135-
list(APPEND egg_dependencies ament_cmake_python_copy_${package_name}_setup)
136-
endif()
92+
message(STATUS "ament_python_install_package: extending '${package_name}'")
13793
endif()
13894

139-
# Technically, we should call find_package(Python3) first to ensure that Python3::Interpreter
140-
# is available. But we skip this here because this macro requires ament_cmake, and ament_cmake
141-
# calls find_package(Python3) for us.
142-
get_executable_path(python_interpreter Python3::Interpreter BUILD)
143-
144-
add_custom_target(
145-
ament_cmake_python_build_${package_name}_egg ALL
146-
COMMAND ${python_interpreter} setup.py egg_info
147-
WORKING_DIRECTORY "${build_dir}"
148-
DEPENDS ${egg_dependencies}
149-
)
150-
151-
set(python_version "py${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}")
152-
153-
set(egg_name "${package_name}")
154-
set(egg_install_name "${egg_name}-${ARG_VERSION}")
155-
set(egg_install_name "${egg_install_name}-${python_version}")
156-
157-
install(
158-
DIRECTORY "${build_dir}/${egg_name}.egg-info/"
159-
DESTINATION "${ARG_DESTINATION}/${egg_install_name}.egg-info"
160-
)
161-
162-
if(ARG_SCRIPTS_DESTINATION)
163-
file(MAKE_DIRECTORY "${build_dir}/scripts") # setup.py may or may not create it
164-
165-
add_custom_target(
166-
ament_cmake_python_build_${package_name}_scripts ALL
167-
COMMAND ${python_interpreter} setup.py install_scripts -d scripts
168-
WORKING_DIRECTORY "${build_dir}"
169-
DEPENDS ${egg_dependencies}
170-
)
171-
172-
if(NOT AMENT_CMAKE_SYMLINK_INSTALL)
173-
# Not needed for nor supported by symlink installs
174-
set(_extra_install_args USE_SOURCE_PERMISSIONS)
175-
endif()
176-
177-
install(
178-
DIRECTORY "${build_dir}/scripts/"
179-
DESTINATION "${ARG_SCRIPTS_DESTINATION}/"
180-
${_extra_install_args}
181-
)
95+
get_property(_dirs GLOBAL PROPERTY AMENT_CMAKE_PYTHON_${package_name}_PACKAGE_DIRS)
96+
list(FIND _dirs "${ARG_PACKAGE_DIR}" _didx)
97+
if(_didx EQUAL -1)
98+
set_property(GLOBAL APPEND PROPERTY AMENT_CMAKE_PYTHON_${package_name}_PACKAGE_DIRS "${ARG_PACKAGE_DIR}")
99+
else()
100+
message(WARNING "duplicate PACKAGE_DIR for '${package_name}', skipping")
182101
endif()
183102

184-
install(
185-
DIRECTORY "${ARG_PACKAGE_DIR}/"
186-
DESTINATION "${ARG_DESTINATION}/${package_name}"
187-
PATTERN "*.pyc" EXCLUDE
188-
PATTERN "__pycache__" EXCLUDE
189-
)
190-
191-
if(NOT ARG_SKIP_COMPILE)
192-
get_executable_path(python_interpreter_config Python3::Interpreter CONFIGURE)
193-
# compile Python files
194-
install(CODE
195-
"execute_process(
196-
COMMAND
197-
\"${python_interpreter_config}\" \"-m\" \"compileall\"
198-
\"${CMAKE_INSTALL_PREFIX}/${ARG_DESTINATION}/${package_name}\"
199-
)"
200-
)
201-
endif()
103+
_ament_cmake_python_override(SKIP_COMPILE)
104+
_ament_cmake_python_override(VERSION)
105+
_ament_cmake_python_override(SETUP_CFG)
106+
_ament_cmake_python_override(DESTINATION)
107+
_ament_cmake_python_override(SCRIPTS_DESTINATION)
108+
endfunction()
202109

203-
if(package_name IN_LIST AMENT_CMAKE_PYTHON_INSTALL_INSTALLED_NAMES)
204-
message(FATAL_ERROR
205-
"ament_python_install_package() a Python module file or package with "
206-
"the same name '${package_name}' has been installed before")
110+
macro(_ament_cmake_python_override param)
111+
set(_prop "AMENT_CMAKE_PYTHON_${package_name}_${param}")
112+
set(_val "${ARG_${param}}")
113+
get_property(_old_val GLOBAL PROPERTY ${_prop})
114+
if(_old_val AND NOT _old_val STREQUAL "${_val}")
115+
message(WARNING "${param} for '${package_name}' changed from '${_old_val}' to '${_val}'")
207116
endif()
208-
list(APPEND AMENT_CMAKE_PYTHON_INSTALL_INSTALLED_NAMES "${package_name}")
209-
set(AMENT_CMAKE_PYTHON_INSTALL_INSTALLED_NAMES
210-
"${AMENT_CMAKE_PYTHON_INSTALL_INSTALLED_NAMES}" PARENT_SCOPE)
211-
endfunction()
117+
set_property(GLOBAL PROPERTY ${_prop} "${_val}")
118+
endmacro()
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Copyright 2025 Open Source Robotics Foundation, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
function(ament_cmake_python_install_registered_packages)
16+
get_property(_pkgs GLOBAL PROPERTY AMENT_CMAKE_PYTHON_PKGS)
17+
foreach(pkg IN LISTS _pkgs)
18+
_ament_cmake_python_install_package_impl(${pkg})
19+
endforeach()
20+
endfunction()
21+
22+
function(_ament_cmake_python_install_package_impl package_name)
23+
foreach(_prop IN ITEMS SKIP_COMPILE VERSION SETUP_CFG DESTINATION SCRIPTS_DESTINATION PACKAGE_DIRS)
24+
get_property(_${_prop} GLOBAL PROPERTY AMENT_CMAKE_PYTHON_${package_name}_${_prop})
25+
endforeach()
26+
27+
_ament_cmake_python_prepare_build(${package_name})
28+
_ament_cmake_python_copy_build_files(${package_name})
29+
30+
# Technically, we should call find_package(Python3) first to ensure that Python3::Interpreter
31+
# is available. But we skip this here because this macro requires ament_cmake, and ament_cmake
32+
# calls find_package(Python3) for us.
33+
get_executable_path(python_interpreter Python3::Interpreter BUILD)
34+
35+
_ament_cmake_python_generate_egg(${package_name})
36+
37+
if(_SCRIPTS_DESTINATION)
38+
_ament_cmake_python_install_scripts(${package_name})
39+
endif()
40+
41+
_ament_cmake_python_install_sources(${package_name})
42+
43+
if(NOT _SKIP_COMPILE)
44+
_ament_cmake_python_byte_compile(${package_name})
45+
endif()
46+
47+
endfunction()
48+
49+
macro(_ament_cmake_python_prepare_build package_name)
50+
set(_build_dir "${CMAKE_CURRENT_BINARY_DIR}/ament_cmake_python/${package_name}")
51+
52+
string(CONFIGURE "\
53+
from setuptools import find_packages
54+
from setuptools import setup
55+
56+
setup(
57+
name='${package_name}',
58+
version='${_VERSION}',
59+
packages=find_packages(
60+
include=('${package_name}', '${package_name}.*')),
61+
)
62+
" setup_py_content)
63+
64+
file(GENERATE
65+
OUTPUT "${_build_dir}/setup.py"
66+
CONTENT "${setup_py_content}"
67+
)
68+
69+
endmacro()
70+
71+
macro(_ament_cmake_python_copy_build_files package_name)
72+
set(_sync_target "ament_cmake_python_sync_${package_name}")
73+
74+
add_custom_target(${_sync_target} DEPENDS ${_PACKAGE_DIRS} ${_SETUP_CFG})
75+
76+
foreach(_dir IN LISTS _PACKAGE_DIRS)
77+
add_custom_command(TARGET ${_sync_target}
78+
COMMAND ${CMAKE_COMMAND} -E copy_directory
79+
"${_dir}" "${_build_dir}/${package_name}"
80+
)
81+
endforeach()
82+
83+
if(_SETUP_CFG)
84+
add_custom_command(TARGET ${_sync_target}
85+
COMMAND ${CMAKE_COMMAND} -E copy_if_different
86+
"${_SETUP_CFG}" "${_build_dir}/setup.cfg"
87+
)
88+
endif()
89+
90+
endmacro()
91+
92+
macro(_ament_cmake_python_generate_egg package_name)
93+
add_custom_target(
94+
ament_cmake_python_build_${package_name}_egg ALL
95+
COMMAND ${python_interpreter} setup.py egg_info
96+
WORKING_DIRECTORY "${_build_dir}"
97+
DEPENDS ${_sync_target}
98+
)
99+
100+
set(python_version "py${Python3_VERSION_MAJOR}.${Python3_VERSION_MINOR}")
101+
102+
set(egg_name "${package_name}")
103+
set(egg_install_name "${egg_name}-${_VERSION}")
104+
set(egg_install_name "${egg_install_name}-${python_version}")
105+
106+
install(
107+
DIRECTORY "${_build_dir}/${egg_name}.egg-info/"
108+
DESTINATION "${_DESTINATION}/${egg_install_name}.egg-info"
109+
)
110+
endmacro()
111+
112+
macro(_ament_cmake_python_install_scripts package_name)
113+
file(MAKE_DIRECTORY "${_build_dir}/scripts") # setup.py may or may not create it
114+
115+
add_custom_target(
116+
ament_cmake_python_build_${package_name}_scripts ALL
117+
COMMAND ${python_interpreter} setup.py install_scripts -d scripts
118+
WORKING_DIRECTORY "${_build_dir}"
119+
DEPENDS ${_sync_target}
120+
)
121+
122+
if(NOT AMENT_CMAKE_SYMLINK_INSTALL)
123+
# Not needed for nor supported by symlink installs
124+
set(_extra_install_args USE_SOURCE_PERMISSIONS)
125+
endif()
126+
127+
install(
128+
DIRECTORY "${_build_dir}/scripts/"
129+
DESTINATION "${_SCRIPTS_DESTINATION}/"
130+
${_extra_install_args}
131+
)
132+
endmacro()
133+
134+
macro(_ament_cmake_python_install_sources package_name)
135+
foreach(_dir IN LISTS _PACKAGE_DIRS)
136+
install(
137+
DIRECTORY "${_dir}/"
138+
DESTINATION "${_DESTINATION}/${package_name}"
139+
PATTERN "*.pyc" EXCLUDE
140+
PATTERN "__pycache__" EXCLUDE
141+
)
142+
endforeach()
143+
endmacro()
144+
145+
macro(_ament_cmake_python_byte_compile package_name)
146+
get_executable_path(python_interpreter_config Python3::Interpreter CONFIGURE)
147+
# compile Python files
148+
install(CODE
149+
"execute_process(
150+
COMMAND
151+
\"${python_interpreter_config}\" \"-m\" \"compileall\"
152+
\"${CMAKE_INSTALL_PREFIX}/${_DESTINATION}/${package_name}\"
153+
)"
154+
)
155+
endmacro()
156+
157+
ament_cmake_python_install_registered_packages()

ament_cmake_python_test/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
cmake_minimum_required(VERSION 3.12)
2+
3+
project(ament_cmake_python_test NONE)
4+
5+
find_package(ament_cmake_core REQUIRED)
6+
7+
if(BUILD_TESTING)
8+
find_package(ament_cmake_pytest REQUIRED)
9+
find_package(ament_cmake_python REQUIRED)
10+
11+
ament_python_install_package(
12+
ament_python_test_package
13+
PACKAGE_DIR test/ament_python_test_package
14+
)
15+
ament_python_install_package(
16+
ament_python_test_package_overlay
17+
PACKAGE_DIR test/ament_python_test_package
18+
)
19+
ament_python_install_package(
20+
ament_python_test_package_overlay
21+
PACKAGE_DIR test/ament_python_test_package_overlay
22+
)
23+
24+
ament_add_pytest_test(
25+
test_ament_python_install_package
26+
test/test_ament_python_install_package.py
27+
ENV TEST_PACKAGE_INSTALL_DIR=${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_DIR}
28+
)
29+
endif()
30+
31+
ament_package()

0 commit comments

Comments
 (0)