<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[catkin_make的时候发生了什么]]></title><description><![CDATA[<p dir="auto">这是一个比较复杂的问题，但是有时候会有莫名其妙的编译错误，在找错误的过程中会非常需要了解这个过程。</p>
<p dir="auto">首先说一下.in文件。在catkin的目录中有许多.in文件<br />
<img src="/assets/uploads/files/1492173919204-screenshot-from-2017-04-14-20-45-12.png" alt="0_1492173921785_Screenshot from 2017-04-14 20-45-12.png" class=" img-responsive img-markdown" width="755" height="173" /><br />
这些都是模板文件，以<code>/opt/ros/kinetic/share/catkin/cmake/templates/env.sh.in</code>为例<br />
下面是源文件</p>
<pre><code>#!/usr/bin/env sh
# generated from catkin/cmake/templates/env.sh.in

if [ $# -eq 0 ] ; then
  /bin/echo "Usage: env.sh COMMANDS"
  /bin/echo "Calling env.sh without arguments is not supported anymore. Instead spawn a subshell and source a setup file manually."
  exit 1
fi

# ensure to not use different shell type which was set before
CATKIN_SHELL=sh

# source @SETUP_FILENAME@.sh from same directory as this file
_CATKIN_SETUP_DIR=$(cd "`dirname "$0"`" &gt; /dev/null &amp;&amp; pwd)
. "$_CATKIN_SETUP_DIR/@SETUP_FILENAME@.sh"
exec "$@"

</code></pre>
<p dir="auto">这个是生成后的文件</p>
<pre><code>#!/usr/bin/env sh
# generated from catkin/cmake/templates/env.sh.in

if [ $# -eq 0 ] ; then
  /bin/echo "Usage: env.sh COMMANDS"
  /bin/echo "Calling env.sh without arguments is not supported anymore. Instead spawn a subshell and source a setup file manually."
  exit 1
fi

# ensure to not use different shell type which was set before
CATKIN_SHELL=sh

# source setup.sh from same directory as this file
_CATKIN_SETUP_DIR=$(cd "`dirname "$0"`" &gt; /dev/null &amp;&amp; pwd)
. "$_CATKIN_SETUP_DIR/setup.sh"
exec "$@
</code></pre>
<p dir="auto">可以看出源文件中的<code>@parameter@</code>都被替换成了实际的参数。通过调用源文件加上对应的参数就可以生成不同的目标文件了。每个ROS的软件包都要通过这种方式生成对应的xxxConfig.cmake等文件。</p>
<p dir="auto">下面开始说大致的过程</p>
<p dir="auto"><code>catkin_make</code> 实际和下面的指令是等效的</p>
<pre><code>$ cd ~/catkin_ws
$ cd src
$ catkin_init_workspace
$ cd ..
$ mkdir build
$ cd build
$ cmake ../src -DCMAKE_INSTALL_PREFIX=../install -DCATKIN_DEVEL_PREFIX=../devel
$ make
</code></pre>
<p dir="auto">所以最先被编译的是那个在<code>src</code>下的公用的<code>CMakeList.txt</code>文件<br />
这个文件的大部分内容都是在找catkin这个包的位置。最后执行一个cmake函数<code>catkin_workspace</code>。这个函数在<code>/opt/ros/kinetic/share/catkin/cmake/catkin_workspace.cmake</code>文件中定义。这个函数对<code>catkin_make</code>执行时的参数进行解析，比如<code>CATKIN_WHITELIST_PACKAGES</code>。然后开始遍历工作空间中的文件夹，如果文件夹中有<code>package.xml</code>文件就将其当作一个软件包。同时对每个软件包调用<code>add_subdirectory</code>。<code>add_subdirectory</code>是一个<code>cmake</code>的内置函数，会调用这个文件夹内的<code>CMakeList.txt</code>文件。这样就开始了每个软件包的编译了。</p>
<p dir="auto">所以如果你的<code>catkin_make</code>本身出了问题就要在这个过程中去Debug。</p>
<p dir="auto">下面说说每个软件包的编译过程。以<code>geometry2/tf2_geometry_msgs</code>这个包为例<br />
其<code>CMakeList.txt</code>文件如下</p>
<pre><code>cmake_minimum_required(VERSION 2.8.3)
project(tf2_geometry_msgs)

find_package(orocos_kdl)
find_package(catkin REQUIRED COMPONENTS geometry_msgs tf2_ros tf2)
find_package(Boost COMPONENTS thread REQUIRED)

# Issue #53
find_library(KDL_LIBRARY REQUIRED NAMES orocos-kdl HINTS ${orocos_kdl_LIBRARY_DIRS})

catkin_package(
   LIBRARIES ${KDL_LIBRARY}
   INCLUDE_DIRS include
   DEPENDS orocos_kdl
   CATKIN_DEPENDS  geometry_msgs tf2_ros tf2)

include_directories(include
                    ${catkin_INCLUDE_DIRS}
)

link_directories(${orocos_kdl_LIBRARY_DIRS})



install(DIRECTORY include/${PROJECT_NAME}/
  DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
)
catkin_python_setup()

if(CATKIN_ENABLE_TESTING)

find_package(catkin REQUIRED COMPONENTS geometry_msgs rostest tf2_ros tf2)

add_executable(test_geometry_msgs EXCLUDE_FROM_ALL test/test_tf2_geometry_msgs.cpp)
target_link_libraries(test_geometry_msgs ${catkin_LIBRARIES} ${GTEST_LIBRARIES} ${orocos_kdl_LIBRARIES})
add_rostest(${CMAKE_CURRENT_SOURCE_DIR}/test/test.launch)
add_rostest(${CMAKE_CURRENT_SOURCE_DIR}/test/test_python.launch)


if(TARGET tests)
  add_dependencies(tests test_geometry_msgs)
endif()

endif()
</code></pre>
<p dir="auto">首先是指明cmake版本，项目名称，软件包依赖之类的常见操作。然后执行了<code>catkin_package</code>这个函数。这个函数做了大量的工作。<code>catkin_package</code>在<code>/opt/ros/kinetic/share/catkin/cmake/catkin_package.cmake</code>文件中定义。devel和build文件夹内的内容基本都是由其生成的。<br />
这个函数解析<code>package.xml</code>文件，提取出里面的参数，由这些参数给<code>find_package</code>和<code>pkg-config</code>生成对应的配置文件。这样其他的对这个软件包有依赖的程序就可以方便的使用了。</p>
<p dir="auto">所以需要重点分析的就是<code>catkin_package</code>这个函数。<br />
对于编译程序最重要的就是头文件的位置和链接库的位置。也就是include directory 和 library directory。这个函数就是在为软件包配置这些参数。它自动的根据依赖关系把依赖的程序的头文件和链接库目录加入到当前的变量中。然后根据这些参数和对应的模板文件生成对应的配置文件。比如根据<code>/opt/ros/kinetic/share/catkin/cmake/templates/pkgConfig.cmake.in</code>生成软件包的<code>pkgConfig.cmake</code>文件。这样这个软件包就可以被其他的软件包用<code>find_package</code>找到。</p>
<p dir="auto">如果在编译过程中发现有软件包的路径出了问题，那么就要在这个过程去debug。很有可能是生产<code>pkgConfig.cmake</code>时的参数不对。最终可能是依赖包中的软件包路径问题(有挺多的ros软件包都是把路径写死的，这样很不好)。</p>
<p dir="auto">由<code>catkin_package</code>生成的文件最终会被安装到devel和build文件夹下。下面就具体看一下生成了哪些文件。<br />
下面是一个一般的devel的文件结构。devel是develop的缩写，所以这就是开发环境。<br />
<img src="/assets/uploads/files/1492221558349-screenshot-from-2017-04-15-09-59-11.png" alt="0_1492221561279_Screenshot from 2017-04-15 09-59-11.png" class=" img-responsive img-markdown" width="526" height="49" /><br />
<code>bin</code>内是被编译的可执行文件。<code>lib</code>是<code>pkg.pc</code>文件和python的库文件。<code>pkg.pc</code>是<code>pkg-config</code>的配置文件(关于pkg-config可以看另外一篇帖子)。 <code>include</code>用来放置头文件。 <code>share</code>是放置生成的<code>pkgConfig.cmake</code>文件的，在cmake文件中<code>find_package</code>就会用到这些文件。下面是其中的一个例子。<br />
<img src="/assets/uploads/files/1492221848438-screenshot-from-2017-04-15-10-04-03.png" alt="0_1492221851390_Screenshot from 2017-04-15 10-04-03.png" class=" img-responsive img-markdown" width="744" height="40" /><br />
对于<code>build</code>文件夹，生成是一些编译中的中间文件，比如用来存储一些环境变量之类的文件。这个文件夹意义不大。<br />
如果你在编译过程中出现问题可以去看build文件夹中各种文件内部的参数，可以方便的定位到可能出现问题的位置。</p>
<p dir="auto">总结一下整个编译的过程</p>
<ol>
<li>执行<code>catkin_make</code></li>
<li>执行<code>catkin_workspace</code>。解析<code>catkin_make</code>的参数同时遍历整个工作空间把所有的有<code>package.xml</code>的文件夹添加进软件包列表里面。对每个软件包执行<code>add_subdirectory</code></li>
<li>执行每个软件包内部的<code>CMakeList.txt</code>文件。</li>
<li>执行 <code>catkin_package</code>。解析<code>package.xml</code>文件，载入对应的参数。根据依赖参数，载入对应的软件包参数。根据载入参数生成当前软件包的配置文件。</li>
</ol>
]]></description><link>http://community.bwbot.org/topic/182/catkin_make的时候发生了什么</link><generator>RSS for Node</generator><lastBuildDate>Tue, 14 Apr 2026 10:04:52 GMT</lastBuildDate><atom:link href="http://community.bwbot.org/topic/182.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 14 Apr 2017 13:35:44 GMT</pubDate><ttl>60</ttl></channel></rss>