树莓派ros1 环境问题反推 学习下

是接的这篇文章https://mengleil.blog.csdn.net/article/details/105031287

1 代码反推

把rospack的源码 下载下来

git clone https://github.com/ros/rospack.git

用find 命令来推

 // COMMAND: find [package]
  if(command == "find")
  {
    if(!package.size())
    {
      rp.logError(std::string("no ") + rp.get_manifest_type() + " given");
      return false;
    }
    if(target.size() || top.size() || length_str.size() ||
       zombie_only || deps_only || lang.size() || attrib.size())
    {
      rp.logError( "invalid option(s) given");
      return false;
    }
    std::string path;
    if(!rp.find(package, path))
      return false;
    output.append(path + "\n");
    return true;
  }

用的find

bool
Rosstackage::find(const std::string& name, std::string& path)
{
  Stackage* s = findWithRecrawl(name);
  if(s)
  {
    path = s->path_;
    return true;
  }
  else
    return false;
}

用的findWithRecrawl

Stackage*
Rosstackage::findWithRecrawl(const std::string& name)
{
  if(stackages_.count(name))
    return stackages_[name];
  else
  {
    // Try to recrawl, in case we loaded from cache
    crawl(search_paths_, true);
    if(stackages_.count(name))
      return stackages_[name];
  }

  logError(get_manifest_type() + " '" + name + "' not found");
  return NULL;
}

看看 stackages_

class ROSPACK_DECL Rosstackage
{
  private:
    std::string manifest_name_;
    std::string cache_prefix_;
    bool crawled_;
    std::string name_;
    std::string tag_;
    bool quiet_;
    std::vector<std::string> search_paths_;
#if BOOST_VERSION < 106500
    std::tr1::unordered_map<std::string, std::vector<std::string> > dups_;
    std::tr1::unordered_map<std::string, Stackage*> stackages_;
#else
    boost::unordered_map<std::string, std::vector<std::string> > dups_;
    boost::unordered_map<std::string, Stackage*> stackages_;
#endif

是个 unordered_map 比较高端的map

在这里插入图片描述

证明 包的路径存在这里的,找插入的地方

扫描二维码关注公众号,回复: 10153769 查看本文章
void
Rosstackage::addStackage(const std::string& path)
{
#if !defined(BOOST_FILESYSTEM_VERSION) || (BOOST_FILESYSTEM_VERSION == 2)
  std::string name = fs::path(path).filename();
#else
  // in boostfs3, filename() returns a path, which needs to be stringified
  std::string name = fs::path(path).filename().string();
#endif

  Stackage* stackage = 0;
  fs::path dry_manifest_path = fs::path(path) / manifest_name_;
  fs::path wet_manifest_path = fs::path(path) / ROSPACKAGE_MANIFEST_NAME;
  if(fs::is_regular_file(dry_manifest_path))
  {
    stackage = new Stackage(name, path, dry_manifest_path.string(), manifest_name_);
  }
  else if(fs::is_regular_file(wet_manifest_path))
  {
    stackage = new Stackage(name, path, wet_manifest_path.string(), ROSPACKAGE_MANIFEST_NAME);
    loadManifest(stackage);
    stackage->update_wet_information();
  }
  else
  {
    return;
  }

  // skip the stackage if it is not of correct type
  if((manifest_name_ == ROSSTACK_MANIFEST_NAME && stackage->isPackage()) ||
     (manifest_name_ == ROSPACK_MANIFEST_NAME && stackage->isStack()))
  {
    delete stackage;
    return;
  }

  if(stackages_.find(stackage->name_) != stackages_.end())
  {
    if (dups_.find(stackage->name_) == dups_.end())
    {
      std::vector<std::string> dups;
      dups.push_back(stackages_[stackage->name_]->path_);
      dups_[stackage->name_] = dups;
    }
    dups_[stackage->name_].push_back(stackage->path_);
    delete stackage;
    return;
  }

  stackages_[stackage->name_] = stackage;
}

找到 path,看谁调用的 addStackage

void
Rosstackage::crawlDetail(const std::string& path,
                         bool force,
                         int depth,
                         bool collect_profile_data,
                         std::vector<DirectoryCrawlRecord*>& profile_data,
#if BOOST_VERSION < 106500
                         std::tr1::unordered_set<std::string>& profile_hash)
#else
                         boost::unordered_set<std::string>& profile_hash)
#endif                         
{
  if(depth > MAX_CRAWL_DEPTH)

然后往下

void
Rosstackage::crawl(std::vector<std::string> search_path,
                   bool force)
{
  if(!force)
  {
    bool same_search_paths = (search_path == search_paths_);

    // if search paths differ, try to reading the cache corresponding to the new paths
    if(!same_search_paths && readCache())
    {
      // If the cache was valid, then the paths in the cache match the ones
      // we've been asked to crawl.  Store them, so that later, methods
      // like find() can refer to them when recrawling.
      search_paths_ = search_path;
      return;
    }

    if(crawled_ && same_search_paths)
      return;
  }

  // We're about to crawl, so clear internal storage (in case this is the second
  // run in this process).
  clearStackages();
  search_paths_ = search_path;

  std::vector<DirectoryCrawlRecord*> dummy;
  
#if BOOST_VERSION < 106500
  std::tr1::unordered_set<std::string> dummy2;
#else
  boost::unordered_set<std::string> dummy2;
#endif
  for(std::vector<std::string>::const_iterator p = search_paths_.begin();
      p != search_paths_.end();
      ++p)
    crawlDetail(*p, force, 1, false, dummy, dummy2);

  crawled_ = true;

  writeCache();
}

到这

 }

  std::vector<std::string> search_path;
  if(!rp.getSearchPathFromEnv(search_path))
    return false;

  // COMMAND: profile
  if(command == "profile")
  {
    if(package_given || target.size() || top.size() ||
       deps_only || lang.size() || attrib.size())
    {
      rp.logError( "invalid option(s) given");
      return false;
    }
    std::vector<std::string> dirs;
    if(rp.profile(search_path, zombie_only, length, dirs))
      return false;
    for(std::vector<std::string>::const_iterator it = dirs.begin();
        it != dirs.end();
        ++it)
      output.append((*it) + "\n");
    return true;
  }

  // We crawl here because profile (above) does its own special crawl.
  rp.crawl(search_path, force);

然后getSearchPathFromEnv 获取的路径

bool
Rosstackage::getSearchPathFromEnv(std::vector<std::string>& sp)
{
  char* rpp = getenv("ROS_PACKAGE_PATH");
  if(rpp)
  {
    // I can't see that boost filesystem has an elegant cross platform
    // representation for this anywhere like qt/python have.
    #if defined(WIN32)
      const char *path_delim = ";";
    #else //!defined(WIN32)
      const char *path_delim = ":";
    #endif

    std::vector<std::string> rpp_strings;
    boost::split(rpp_strings, rpp,
                 boost::is_any_of(path_delim),
                 boost::token_compress_on);
    for(std::vector<std::string>::const_iterator it = rpp_strings.begin();
        it != rpp_strings.end();
        ++it)
    {
      sp.push_back(*it);
    }
  }
  return true;
}

是从 ROS_PACKAGE_PATH 里获取的

2 脚本反推

这个是执行了 .setup.bash 之后出现的

我看看脚本

setup.bash

#!/usr/bin/env bash
# generated from catkin/cmake/templates/setup.bash.in

CATKIN_SHELL=bash

# source setup.sh from same directory as this file
_CATKIN_SETUP_DIR=$(builtin cd "`dirname "${BASH_SOURCE[0]}"`" > /dev/null && pwd)
. "$_CATKIN_SETUP_DIR/setup.sh"

去执行了 setup.sh

#!/usr/bin/env sh
# generated from catkin/cmake/template/setup.sh.in

# Sets various environment variables and sources additional environment hooks.
# It tries it's best to undo changes from a previously sourced setup file before.
# Supported command line options:
# --extend: skips the undoing of changes from a previously sourced setup file
#   (in plain sh shell which does't support arguments for sourced scripts you
#   can set the environment variable `CATKIN_SETUP_UTIL_ARGS=--extend` instead)

# since this file is sourced either use the provided _CATKIN_SETUP_DIR
# or fall back to the destination set at configure time
: ${_CATKIN_SETUP_DIR:=/home/pi/catkin_ws/devel}
_SETUP_UTIL="$_CATKIN_SETUP_DIR/_setup_util.py"
unset _CATKIN_SETUP_DIR

if [ ! -f "$_SETUP_UTIL" ]; then
  echo "Missing Python script: $_SETUP_UTIL"
  return 22
fi

# detect if running on Darwin platform
_UNAME=`uname -s`
_IS_DARWIN=0
if [ "$_UNAME" = "Darwin" ]; then
  _IS_DARWIN=1
fi
unset _UNAME

# make sure to export all environment variables
export CMAKE_PREFIX_PATH
if [ $_IS_DARWIN -eq 0 ]; then
  export LD_LIBRARY_PATH
else
  export DYLD_LIBRARY_PATH
fi
unset _IS_DARWIN
export PATH
export PKG_CONFIG_PATH
export PYTHONPATH

# remember type of shell if not already set
if [ -z "$CATKIN_SHELL" ]; then
  CATKIN_SHELL=sh
fi

# invoke Python script to generate necessary exports of environment variables
# use TMPDIR if it exists, otherwise fall back to /tmp
if [ -d "${TMPDIR:-}" ]; then
  _TMPDIR="${TMPDIR}"
else
  _TMPDIR=/tmp
fi
_SETUP_TMP=`mktemp "${_TMPDIR}/setup.sh.XXXXXXXXXX"`
unset _TMPDIR
if [ $? -ne 0 -o ! -f "$_SETUP_TMP" ]; then
  echo "Could not create temporary file: $_SETUP_TMP"
  return 1
fi
CATKIN_SHELL=$CATKIN_SHELL "$_SETUP_UTIL" $@ ${CATKIN_SETUP_UTIL_ARGS:-} >> "$_SETUP_TMP"
_RC=$?
if [ $_RC -ne 0 ]; then
  if [ $_RC -eq 2 ]; then
    echo "Could not write the output of '$_SETUP_UTIL' to temporary file '$_SETUP_TMP': may be the disk if full?"
  else
    echo "Failed to run '\"$_SETUP_UTIL\" $@': return code $_RC"
  fi
  unset _RC
  unset _SETUP_UTIL
  rm -f "$_SETUP_TMP"
  unset _SETUP_TMP
  return 1
fi
unset _RC
unset _SETUP_UTIL
. "$_SETUP_TMP"
rm -f "$_SETUP_TMP"
unset _SETUP_TMP

# source all environment hooks
_i=0
while [ $_i -lt $_CATKIN_ENVIRONMENT_HOOKS_COUNT ]; do
  eval _envfile=\$_CATKIN_ENVIRONMENT_HOOKS_$_i
  unset _CATKIN_ENVIRONMENT_HOOKS_$_i
  eval _envfile_workspace=\$_CATKIN_ENVIRONMENT_HOOKS_${_i}_WORKSPACE
  unset _CATKIN_ENVIRONMENT_HOOKS_${_i}_WORKSPACE
  # set workspace for environment hook
  CATKIN_ENV_HOOK_WORKSPACE=$_envfile_workspace
  . "$_envfile"
  unset CATKIN_ENV_HOOK_WORKSPACE
  _i=$((_i + 1))
done
unset _i

unset _CATKIN_ENVIRONMENT_HOOKS_COUNT

首先执行了_setup_util.py

主要是这个.py

里面有生成日志,最后被删除了,注释掉删除的东东,把日志拿出来看

# reset environment variables by unrolling modifications based on all workspaces in CMAKE_PREFIX_PATH
export CMAKE_PREFIX_PATH=""
export LD_LIBRARY_PATH=""
export PKG_CONFIG_PATH=""
# prepend folders of workspaces to environment variables
export CMAKE_PREFIX_PATH="/home/pi/catkin_ws/devel"
export LD_LIBRARY_PATH="/home/pi/catkin_ws/devel/lib"
export PATH="$PATH"
export PKG_CONFIG_PATH="/home/pi/catkin_ws/devel/lib/pkgconfig"
export PYTHONPATH=""
# found environment hooks in workspaces
export _CATKIN_ENVIRONMENT_HOOKS_COUNT="5"
export _CATKIN_ENVIRONMENT_HOOKS_0="/etc/catkin/profile.d/1.ros_distro.sh"
export _CATKIN_ENVIRONMENT_HOOKS_0_WORKSPACE=""
export _CATKIN_ENVIRONMENT_HOOKS_1="/etc/catkin/profile.d/1.ros_etc_dir.sh"
export _CATKIN_ENVIRONMENT_HOOKS_1_WORKSPACE=""
export _CATKIN_ENVIRONMENT_HOOKS_2="/etc/catkin/profile.d/1.ros_package_path.sh"
export _CATKIN_ENVIRONMENT_HOOKS_2_WORKSPACE=""
export _CATKIN_ENVIRONMENT_HOOKS_3="/etc/catkin/profile.d/1.ros_python_version.sh"
export _CATKIN_ENVIRONMENT_HOOKS_3_WORKSPACE=""
export _CATKIN_ENVIRONMENT_HOOKS_4="/etc/catkin/profile.d/1.ros_version.sh"
export _CATKIN_ENVIRONMENT_HOOKS_4_WORKSPACE=""

结合日志研究下主要是这个函数

def find_env_hooks(environ, cmake_prefix_path):
    '''
    Generate shell code with found environment hooks
    for the all workspaces.
    '''
    lines = []
    lines.append(comment('found environment hooks in workspaces'))

    generic_env_hooks = []
    generic_env_hooks_workspace = []
    specific_env_hooks = []
    specific_env_hooks_workspace = []
    generic_env_hooks_by_filename = {}
    specific_env_hooks_by_filename = {}
    generic_env_hook_ext = 'bat' if IS_WINDOWS else 'sh'
    specific_env_hook_ext = environ['CATKIN_SHELL'] if not IS_WINDOWS and 'CATKIN_SHELL' in environ and environ['CATKIN_SHELL'] else None
    # remove non-workspace paths
    workspaces = [path for path in cmake_prefix_path.split(os.pathsep) if path and os.path.isfile(os.path.join(path, CATKIN_MARKER_FILE))]
    workspaces.append('/')
    for workspace in reversed(workspaces):
        env_hook_dir = os.path.join(workspace, 'etc', 'catkin', 'profile.d')
        if os.path.isdir(env_hook_dir):
            for filename in sorted(os.listdir(env_hook_dir)):
                if filename.endswith('.%s' % generic_env_hook_ext):
                    # remove previous env hook with same name if present
                    if filename in generic_env_hooks_by_filename:
                        i = generic_env_hooks.index(generic_env_hooks_by_filename[filename])
                        generic_env_hooks.pop(i)
                        generic_env_hooks_workspace.pop(i)
                    # append env hook
                    generic_env_hooks.append(os.path.join(env_hook_dir, filename))
                    generic_env_hooks_workspace.append(workspace)
                    generic_env_hooks_by_filename[filename] = generic_env_hooks[-1]
                elif specific_env_hook_ext is not None and filename.endswith('.%s' % specific_env_hook_ext):
                    # remove previous env hook with same name if present
                    if filename in specific_env_hooks_by_filename:
                        i = specific_env_hooks.index(specific_env_hooks_by_filename[filename])
                        specific_env_hooks.pop(i)
                        specific_env_hooks_workspace.pop(i)
                    # append env hook
                    specific_env_hooks.append(os.path.join(env_hook_dir, filename))
                    specific_env_hooks_workspace.append(workspace)
                    specific_env_hooks_by_filename[filename] = specific_env_hooks[-1]
    env_hooks = generic_env_hooks + specific_env_hooks
    env_hooks_workspace = generic_env_hooks_workspace + specific_env_hooks_workspace
    count = len(env_hooks)
    lines.append(assignment('_CATKIN_ENVIRONMENT_HOOKS_COUNT', count))
    for i in range(count):
        lines.append(assignment('_CATKIN_ENVIRONMENT_HOOKS_%d' % i, env_hooks[i]))
        lines.append(assignment('_CATKIN_ENVIRONMENT_HOOKS_%d_WORKSPACE' % i, (env_hooks_workspace[i] if env_hooks_workspace[i] != '/' else '')))
    return lines

里面是通过env的钩子。。。

env_hook_dir = os.path.join(workspace, 'etc', 'catkin', 'profile.d')

钩子的路径,去看看

在这里插入图片描述

删除ros-environment的包之后这几个文件就不见了

包的脚本应该是这个1.ros_package_path.sh

通过 这个拼成命令

def assignment(key, value):
    if not IS_WINDOWS:
        return 'export %s="%s"' % (key, value)
    else:
        return 'set %s=%s' % (key, value)

通过shell 去设置到环境里

CATKIN_SHELL=$CATKIN_SHELL "$_SETUP_UTIL" $@ ${CATKIN_SETUP_UTIL_ARGS:-} >> "$_SETUP_TMP"

然后去遍历执行

_i=0
while [ $_i -lt $_CATKIN_ENVIRONMENT_HOOKS_COUNT ]; do
  eval _envfile=\$_CATKIN_ENVIRONMENT_HOOKS_$_i
  unset _CATKIN_ENVIRONMENT_HOOKS_$_i
  eval _envfile_workspace=\$_CATKIN_ENVIRONMENT_HOOKS_${_i}_WORKSPACE
  unset _CATKIN_ENVIRONMENT_HOOKS_${_i}_WORKSPACE
  # set workspace for environment hook
  CATKIN_ENV_HOOK_WORKSPACE=$_envfile_workspace
  . "$_envfile"
  unset CATKIN_ENV_HOOK_WORKSPACE
  _i=$((_i + 1))
done
unset _i

unset _CATKIN_ENVIRONMENT_HOOKS_COUNT

真绕

3 钩子脚本

官网在这https://github.com/ros/ros_environment

3.1 1.ros_distro.sh
# generated from ros_environment/env-hooks/1.ros_distro.sh.in

if [ -n "$ROS_DISTRO" -a "$ROS_DISTRO" != "Debian" ]; then
  echo "ROS_DISTRO was set to '$ROS_DISTRO' before. Please make sure that the environment does not mix paths from different distributions."
fi
export ROS_DISTRO=Debian

这个简单粗暴

3.2 1.ros_etc_dir.sh
# generated from ros_environment/env-hooks/1.ros_etc_dir.sh.em

# env variable in installspace
if [ -z "$CATKIN_ENV_HOOK_WORKSPACE" ]; then
  CATKIN_ENV_HOOK_WORKSPACE=""
fi
export ROS_ETC_DIR="$CATKIN_ENV_HOOK_WORKSPACE//etc/ros"

同上

3.3 1.ros_package_path.sh
# generated from ros_environment/env-hooks/1.ros_package_path.sh.em

# python function to generate ROS package path based on all workspaces
PYTHON_CODE_BUILD_ROS_PACKAGE_PATH=$(cat <<EOF
from __future__ import print_function
import os
env_name = 'CMAKE_PREFIX_PATH'
paths = [path for path in os.environ[env_name].split(os.pathsep)] if env_name in os.environ and os.environ[env_name] != '' else []
workspaces = [path for path in paths if os.path.exists(os.path.join(path, '.catkin'))]
paths = []
for workspace in workspaces:
    filename = os.path.join(workspace, '.catkin')
    data = ''
    with open(filename) as f:
        data = f.read()
    if data == '':
        paths.append(os.path.join(workspace, 'share'))
        if os.path.isdir(os.path.join(workspace, 'stacks')):
            paths.append(os.path.join(workspace, 'stacks'))
    else:
        for source_path in data.split(';'):
            paths.append(source_path)
print(os.pathsep.join(paths))
EOF
)
export ROS_PACKAGE_PATH="`/usr/bin/python -c \"$P:QYTHON_CODE_BUILD_ROS_PACKAGE_PATH\"`

这个 shell 里套python 有点意思

$CMAKE_PREFIX_PATH 获取路径
在这里插入图片描述

然后在.catkin 里获取包的路径/home/pi/catkin_ws/src

3.4 后面两个一样的

在这里插入图片描述

发布了75 篇原创文章 · 获赞 22 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_36628778/article/details/105039786