从基本的程序开始,编写一个hello.cpp如下:
#include "iostream"
using namespace std;
int main(int argc, char** argv)
{
cout << "Hello SLAM" << endl;
return 0;
}
在Linux中,程序是一个具有执行权限的文件。可以是一个脚本.sh文件,也可以是一个二进制文件,不过我们并不限定其后缀名(Windows需要指定为.exe文件)。对于上面所写的程序hello.cpp,转换为可执行文件前需要对其进行编译操作。
这里我们介绍几种编译方式:g++编译、cmake编译。
g++编译:
首先通过编译指令编译成可执行文件。
g++ hello.cpp
检查当前目录会发现多出来一个a.out的可执行文件,此时可以运行该文件。
./a.out
注意这是一个极其简单的程序,使用了大量的默认参数。
若是如下ros基本程序:
#include "ros/ros.h"
using namespace std;
int main(int argc, char** argv)
{
ros::init(argc, argv, "hello");
ros::NodeHandle n;
ros::spin();
return 0;
}
使用g++编译时直接使用上述g++ hello.cpp时会出现以下报错:
hello.cpp:1:10: fatal error: ros/ros.h: No such file or directory
#include "ros/ros.h"
^~~~~~~~~~~
compilation terminated.
提示找不到“ros/ros.h”头文件
此时需要将ros/ros.h头文件路径写入,让g++编译器能找到这个头文件
g++ hello.cpp -I /opt/ros/melodic/include/
当提供了头文件路径,仍会出现以下问题:
/tmp/cc9gnSVE.o: In function `main':
hello.cpp:(.text+0x72): undefined reference to `ros::init(int&, char**, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unsigned int)'
hello.cpp:(.text+0x104): undefined reference to `ros::NodeHandle::NodeHandle(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::less<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&)'
hello.cpp:(.text+0x127): undefined reference to `ros::spin()'
hello.cpp:(.text+0x13b): undefined reference to `ros::NodeHandle::~NodeHandle()'
hello.cpp:(.text+0x1c1): undefined reference to `ros::NodeHandle::~NodeHandle()'
collect2: error: ld returned 1 exit status
原因是没有提供相应的库搜索路径和库名称,-L参数指定库目录,-l(小写L)指定库的名字
g++ hello.cpp -I /opt/ros/melodic/include -L /opt/ros/melodic/lib/ -lroscpp
至此,在hello.cpp同级目录会出现可执行文件a.out。
Cmake编译:
理论上,任何一个cpp文件都可以用g++编译。但当程序规模越来越大时,需要使用一些工程管理工具会更加高效。这里介绍使用cmake对源代码进行管理
在一个cmake工程中,我们会用cmake命令生成一个makefile文件,然后,用make命令根据这个makefile文件内容编译整个工程。
在上述最简单那个hello.cpp文件同级目录下创建一个CMakeLists.txt文件,写入:
cmake_minimum_required(VERSION 2.8)
project(Hello)
add_executable(hello src/hello.cpp)
通过终端输入下列命令进行编译。
cmake .
make -j4
运行代码:
./hello
当程序变成上述ros基本程序时,进行编译过程同样会出现查找不到ros/ros.h等问题。
此时CMakeLists.txt文件应写入:
cmake_minimum_required(VERSION 2.8)
project(Hello)
#include_directories 添加特定的头文件搜索路径,相当于指定g++编译器的-I参数
include_directories(/opt/ros/melodic/include)
#link_directories 向工程添加多个特定的库文件搜索路径,相当于指定g++编译器的-L参数
link_directories(/opt/ros/melodic/lib/)
add_executable(hello src/hello.cpp)
#target_link_libraries 为hello添加需要动态链接库
target_link_libraries(hello roscpp)
一般会在CMakeLists.txt目录下创建一个新的build文件夹,方便放置生成的Makefile文件等。
mkdir build && cd build
cmake ..
make -j4
运行完上述命令,可以在build目录下发现hello节点了。
这时候,我们发现上面代码有点冗余,当需要多个库文件时,需要写入多个库文件搜索路径和链接库名称。 我们可以通过使用find_package找到对应的库路径。
cmake_minimum_required(VERSION 3.0)
project(Hello)
find_package(roscpp REQUIRED)
include_directories(/opt/ros/melodic/include)
add_executable(hello src/hello.cpp)
target_link_libraries(hello ${roscpp_LIBRARIES})
通过上述可以进行更好的对源文件进行管理。