diff --git a/cmake/catkin_generate_environment.cmake b/cmake/catkin_generate_environment.cmake index 45c351667..c1433056d 100644 --- a/cmake/catkin_generate_environment.cmake +++ b/cmake/catkin_generate_environment.cmake @@ -10,6 +10,30 @@ function(catkin_generate_environment) file(WRITE "${CMAKE_BINARY_DIR}/CATKIN_IGNORE" "") endif() + # get multiarch name + set(CATKIN_LIB_ENVIRONMENT_PATHS "'${CATKIN_GLOBAL_LIB_DESTINATION}'") + set(CATKIN_PKGCONFIG_ENVIRONMENT_PATHS "os.path.join('${CATKIN_GLOBAL_LIB_DESTINATION}', 'pkgconfig')") + if (UNIX AND NOT APPLE) + # Two step looking for multiarch support: check for gcc -print-multiarch + # and, if failed, try to run dpkg-architecture + execute_process(COMMAND gcc -print-multiarch + OUTPUT_VARIABLE CATKIN_MULTIARCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + if ("${CATKIN_MULTIARCH}" STREQUAL "") + execute_process(COMMAND dpkg-architecture -qDEB_HOST_MULTIARCH + OUTPUT_VARIABLE CATKIN_MULTIARCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ERROR_QUIET + ) + endif() + if (NOT "${CATKIN_MULTIARCH}" STREQUAL "") + set(CATKIN_LIB_ENVIRONMENT_PATHS "['${CATKIN_GLOBAL_LIB_DESTINATION}', os.path.join('${CATKIN_GLOBAL_LIB_DESTINATION}', '${CATKIN_MULTIARCH}')]") + set(CATKIN_PKGCONFIG_ENVIRONMENT_PATHS "[os.path.join('${CATKIN_GLOBAL_LIB_DESTINATION}', 'pkgconfig'), os.path.join('${CATKIN_GLOBAL_LIB_DESTINATION}', '${CATKIN_MULTIARCH}', 'pkgconfig')]") + endif() + endif() + # generate Python setup util atomic_configure_file(${catkin_EXTRAS_DIR}/templates/_setup_util.py.in ${CATKIN_DEVEL_PREFIX}/_setup_util.py diff --git a/cmake/templates/_setup_util.py.in b/cmake/templates/_setup_util.py.in index 1ce6beb1e..0cfab97c3 100755 --- a/cmake/templates/_setup_util.py.in +++ b/cmake/templates/_setup_util.py.in @@ -52,9 +52,9 @@ IS_WINDOWS = (system == 'Windows') ENV_VAR_SUBFOLDERS = { 'CMAKE_PREFIX_PATH': '', 'CPATH': 'include', - 'LD_LIBRARY_PATH' if not IS_DARWIN else 'DYLD_LIBRARY_PATH': '@CATKIN_GLOBAL_LIB_DESTINATION@', + 'LD_LIBRARY_PATH' if not IS_DARWIN else 'DYLD_LIBRARY_PATH': @CATKIN_LIB_ENVIRONMENT_PATHS@, 'PATH': '@CATKIN_GLOBAL_BIN_DESTINATION@', - 'PKG_CONFIG_PATH': 'lib/pkgconfig', + 'PKG_CONFIG_PATH': @CATKIN_PKGCONFIG_ENVIRONMENT_PATHS@, 'PYTHONPATH': '@PYTHON_INSTALL_DIR@', } @@ -68,11 +68,14 @@ def rollback_env_variables(environ, env_var_subfolders): lines = [] unmodified_environ = copy.copy(environ) for key in sorted(env_var_subfolders.keys()): - subfolder = env_var_subfolders[key] - value = _rollback_env_variable(unmodified_environ, key, subfolder) - if value is not None: - environ[key] = value - lines.append(assignment(key, value)) + subfolders = env_var_subfolders[key] + if not isinstance(subfolders, list): + subfolders = [subfolders] + for subfolder in subfolders: + value = _rollback_env_variable(unmodified_environ, key, subfolder) + if value is not None: + environ[key] = value + lines.append(assignment(key, value)) if lines: lines.insert(0, comment('reset environment variables by unrolling modifications based on all workspaces in CMAKE_PREFIX_PATH')) return lines @@ -143,7 +146,7 @@ def prepend_env_variables(environ, env_var_subfolders, workspaces): return lines -def _prefix_env_variable(environ, name, paths, subfolder): +def _prefix_env_variable(environ, name, paths, subfolders): ''' Return the prefix to prepend to the environment variable NAME, adding any path in NEW_PATHS_STR without creating duplicate or empty items. ''' @@ -151,11 +154,15 @@ def _prefix_env_variable(environ, name, paths, subfolder): environ_paths = [path for path in value.split(os.pathsep) if path] checked_paths = [] for path in paths: - if subfolder: - path = os.path.join(path, subfolder) - # exclude any path already in env and any path we already added - if path not in environ_paths and path not in checked_paths: - checked_paths.append(path) + if not isinstance(subfolders, list): + subfolders = [subfolders] + for subfolder in subfolders: + path_tmp = path + if subfolder: + path_tmp = os.path.join(path_tmp, subfolder) + # exclude any path already in env and any path we already added + if path_tmp not in environ_paths and path_tmp not in checked_paths: + checked_paths.append(path_tmp) prefix_str = os.pathsep.join(checked_paths) if prefix_str != '' and environ_paths: prefix_str += os.pathsep diff --git a/python/catkin/builder.py b/python/catkin/builder.py index 2ce80e0a6..27eb1aa03 100644 --- a/python/catkin/builder.py +++ b/python/catkin/builder.py @@ -248,6 +248,25 @@ def isolation_print_command(cmd, path=None, add_env=None): ) +def get_multiarch(): + if not sys.platform.lower().startswith('linux'): + return '' + # this function returns the suffix for lib directories on supported systems or an empty string + # it uses two step approach to look for multiarch: first run gcc -print-multiarch and if + # failed try to run dpkg-architecture + p = subprocess.Popen( + ['gcc', '-print-multiarch'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + out, err = subprocess.Popen( + ['dpkg-architecture', '-qDEB_HOST_MULTIARCH'], + stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() + + # be sure of returning empty string or a valid multiarch tuple format + assert(not out.strip() or out.strip().count('-') == 2); + return out.strip() + def get_python_install_dir(): # this function returns the same value as the CMake variable PYTHON_INSTALL_DIR from catkin/cmake/python.cmake python_install_dir = 'lib' @@ -518,9 +537,12 @@ def build_cmake_package( 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['pkgcfg_path'] = os.path.join(install_target, 'lib', 'pkgconfig') + ":" subs['path'] = os.path.join(install_target, 'bin') + ":" + arch = get_multiarch() + if arch: + subs['ld_path'] += os.path.join(install_target, 'lib', arch) + ":" + subs['pkgcfg_path'] += os.path.join(install_target, 'lib', arch, 'pkgconfig') + ":" if not os.path.exists(os.path.dirname(new_setup_path)): os.mkdir(os.path.dirname(new_setup_path)) with open(new_setup_path, 'w') as file_handle: diff --git a/test/unit_tests/test_setup_util.py b/test/unit_tests/test_setup_util.py index 818f3cf62..62613ad1f 100644 --- a/test/unit_tests/test_setup_util.py +++ b/test/unit_tests/test_setup_util.py @@ -7,7 +7,8 @@ data = configure_file(os.path.join(os.path.dirname(__file__), '..', '..', 'cmake', 'templates', '_setup_util.py.in'), { - 'CATKIN_GLOBAL_LIB_DESTINATION': 'lib', + 'CATKIN_LIB_ENVIRONMENT_PATHS': "'lib'", + 'CATKIN_PKGCONFIG_ENVIRONMENT_PATHS': "os.path.join('lib', 'pkgconfig')", 'CATKIN_GLOBAL_BIN_DESTINATION': 'bin', 'PYTHON_INSTALL_DIR': 'pythonX.Y/packages', 'CMAKE_PREFIX_PATH_AS_IS': '',