文章目录
是接的这篇文章: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 查看本文章
![](/qrcode.jpg)
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