From fa3870f4bc7587fcbc93dad04782d9f22f7792ad Mon Sep 17 00:00:00 2001 From: Steven Peters Date: Mon, 5 May 2014 17:03:59 -0700 Subject: [PATCH] Implement multiarch support in catkin commit 7bad3dabfc0efe28f4abfb010f746757ccde4dec Author: Steven Peters Date: Mon May 5 16:55:04 2014 -0700 Implement multiarch support in catkin commit e99145af8fb2d46022395806e34d9468a4e0df92 Author: Steven Peters Date: Mon May 5 16:45:19 2014 -0700 Updates per comments by @dirk-thomas Remove shell keyword and call Popen with list of strings. Remove extra : from PATH variable packing. Fix indentation. Use " to fix escaped single quotes. commit a0eb2a0ac790f39d8e99f32c45f094479f0102c2 Author: Steven Peters Date: Mon May 5 15:11:28 2014 -0700 Don't check multiarch on non-Linux systems commit 655012a59b06825732ec6a31594f69b8670a4084 Author: Steven Peters Date: Mon May 5 14:45:47 2014 -0700 Updates per comments from @wjwwood Renamed the CATKIN_MULTIARCH_*_DESTINATION variables to CATKIN_*_ENVIRONMENT_PATHS. Use isinstance to verify that variables are lists. Check Popen return code instead of std_err. Fix logic error in catkin_generate_environment.cmake commit 35d982799cba965e87897362d94b4efd1d814b6d Author: Steven Peters Date: Tue Apr 29 18:10:43 2014 -0700 Implement multiarch support in catkin Squashed commit of the following: commit 0f2d1c77f16822072a898d745a4fb190e0c7ed18 Author: Jose Luis Rivero Date: Wed Apr 30 02:36:11 2014 +0200 Improve the method of detecting multiarch Run a two step approach using gcc -print-multiarch and, if failed, fallback to use dpkg-architecture. commit 6039d93ffb75d7e1fc9adfc356eca93e77d739af Author: Jose Luis Rivero Date: Tue Apr 29 19:21:44 2014 +0200 Fix call to get_multiarch by removing the parameter commit dcbc8f34adb698d5f4dd35d291126f98a802dc68 Author: Jose Luis Rivero Date: Tue Apr 29 19:08:27 2014 +0200 Replace dpkg-architecture by gcc -print-multiarch. Silent the error on cmake if the flag is not present. Checking the content of the OUTPUT_VARIABLE for empty should be enough to detect errors on multiarch detection. commit c1c02af04e6f00bb3f18be9ee42dbd06c6d03f96 Author: Steven Peters Date: Mon Apr 28 17:07:42 2014 -0700 Fix test by escaping single quotes commit ae19d1b00804eb80c88be21cfb962a18f6661261 Author: Steven Peters Date: Mon Apr 28 16:20:22 2014 -0700 Starting to fix broken test commit 232d56bd995ce17459a7fb8b4d713e1768716402 Author: Steven Peters Date: Mon Apr 28 15:55:27 2014 -0700 Use temporary path variable in loop per @dirk-thomas 's suggestion commit 324ac938617dabacc9f0f2b54a6aa2f32417b470 Author: Steven Peters Date: Mon Apr 28 15:46:22 2014 -0700 Remove trailing whitespace from dpkg-architecture call commit 90f56a464926c41d7cd08a6f77b3e7d769117e2e Author: Steven Peters Date: Mon Apr 28 15:41:22 2014 -0700 Use string with spaces for subprocess command commit 948eb7db7382441a572a7e38e484da75b6d91cfe Author: Steven Peters Date: Mon Apr 28 15:32:02 2014 -0700 Fix subprocess invocation per suggestion from @wjwwood commit e114c9df656a5fd91662ae124573fb30cfdc3f39 Author: Steven Peters Date: Mon Apr 28 15:24:38 2014 -0700 Use CATKIN_GLOBAL_LIB_DESTINATION and os.path.join commit 6f89efe431491b9627089aee8f68cfae33cf0d4f Author: Steven Peters Date: Mon Apr 28 15:01:52 2014 -0700 Attempt at multiarch support (#545) This is an attempt at multiarch support (#545), supercedes (#604). The dpkg-architecture command is used to identify an appropriate lib folder suffix to use for LD_LIBRARY_PATH and PKG_CONFIG_PATH. builder.py and catkin_generate_environment.cmake are modified accordingly, though there's still a problem with isolated devel spaces. --- cmake/catkin_generate_environment.cmake | 24 ++++++++++++++++++ cmake/templates/_setup_util.py.in | 33 +++++++++++++++---------- python/catkin/builder.py | 26 +++++++++++++++++-- test/unit_tests/test_setup_util.py | 3 ++- 4 files changed, 70 insertions(+), 16 deletions(-) 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': '',