CMake结合PCL库学习(1)
經常會有有人問到CMake的學習的問題,而且網上也有很多博客是介紹學習CMake 的用法,但是我覺的學習不用這樣死板,用到了就順便學習一下,也就是邊做邊學,由淺入深,慢慢的就會熟悉了,這個學習的過程中會遇到很多問題,以解決問題的方式驅動自己學習CMake,首先總結一下CMake 的好處,CMake是一個跨平臺編譯的工具,所以不再需要折騰平臺了,比如Windows需要創建Visual Studio項目文件,配置環境等問題,Linux創建Makefile,OS X創建Xcode項目文件。實際上大部分你的配置都會是一樣的,使用CMake會給你很好的項目維護性,也會降低你的維護成本。
cmake 是kitware 公司以及一些開源開發者在開發幾個工具套件(VTK)的過程中衍
生品,最終形成體系,成為一個獨立的開放源代碼項目。官方網站是www.cmake.org,可以通過訪問官方網站獲得更多關于cmake 的信息,
Cmake的特點
1,開放源代碼,使用類BSD 許可發布。http://cmake.org/HTML/Copyright.html
2,跨平臺,并可生成native 編譯配置文件,在Linux/Unix 平臺,生成makefile,在蘋果平臺,可以生成xcode,在Windows 平臺,可以生成MSVC 的工程文件。
3,能夠管理大型項目。
4,簡化編譯構建過程和編譯過程。Cmake 的工具鏈非常簡單:cmake+make。
5,高效慮,可擴展,可以為cmake 編寫特定功能的模塊,擴充cmake 功能。
提示:
1,如果你沒有實際的項目需求,那么看到這里就可以停下來了,因為cmake 的學習過程就是實踐過程,沒有實踐,讀的再多幾天后也會忘記。
2,如果你的工程只有幾個文件,直接編寫Makefile 是最好的選擇。
3,如果使用的是C/C++/Java 之外的語言,請不要使用cmake(至少目前是這樣)
那么接下來我們就根據CMake和PCL庫中的各個層級的CMakeLists.txt文件配合講解CMake的用法。
比如我現在要結合PCL 的庫寫一個基于點云庫的不用數據格式之間轉換的代碼以及CMake文件的解析:該函數的.cpp文件如下:
/*PCL tutorial by yao 2018.03.23the manager of wechat official account "dianyunPCL"*///這是一個將mesh點云數據轉換位OBJ,PCD,PLY,STL,STL,VTK 等格式
//這個工具的可以指定輸出文件的存儲個格式有ASCII binary 和binary compressed三種可選#include <vector>#include <pcl/console/parse.h>
#include <pcl/io/auto_io.h>
#include <pcl/io/obj_io.h>
#include <pcl/io/vtk_lib_io.h>#include <boost/make_shared.hpp>#define ASCII 0
#define BINARY 1
#define BINARY_COMPRESSED 2/*** Display help for this program* @param argc[in]* @param argv[in]*/
void
displayHelp (int argc,char** argv)
{PCL_INFO ("\nUsage: %s [OPTION] SOURCE DEST\n", argv[0]);PCL_INFO ("Convert SOURCE point cloud or mesh to DEST.\n\n");PCL_INFO ("Available formats types for SOURCE and DEST:\n""\tOBJ (Wavefront)\n""\tPCD (Point Cloud Library)\n""\tPLY (Polygon File Format)\n""\tSTL (STereoLithography)\n""\tVTK (The Visualization Toolkit)\n\n");PCL_INFO ("Available options:\n""\t-f, --format Specify DEST output type, available formats are ascii, binary and binary_compressed.\n""\t When not specified, binary is used as default.\n""\t OBJ only supports ascii format.\n""\t binary_compressed is only supported by the PCD file format.\n\n""\t-c --cloud Output DEST as a point cloud, delete all faces.\n\n");
}bool
saveMesh (pcl::PolygonMesh& input,std::string output_file,int output_type);/*** Saves a cloud into the specified file and output type. The file format is automatically parsed.* @param input[in] The cloud to be saved* @param output_file[out] The output file to be written* @param output_type[in] The output file type* @return True on success, false otherwise.*/
bool
savePointCloud (pcl::PCLPointCloud2::Ptr input,std::string output_file,int output_type)
{if (boost::filesystem::path (output_file).extension () == ".pcd"){//TODO Support precision, origin, orientationpcl::PCDWriter w;if (output_type == ASCII){PCL_INFO ("Saving file %s as ASCII.\n", output_file.c_str ());if (w.writeASCII (output_file, *input) != 0)return (false);}else if (output_type == BINARY){PCL_INFO ("Saving file %s as binary.\n", output_file.c_str ());if (w.writeBinary (output_file, *input) != 0)return (false);}else if (output_type == BINARY_COMPRESSED){PCL_INFO ("Saving file %s as binary compressed.\n", output_file.c_str ());if (w.writeBinaryCompressed (output_file, *input) != 0)return (false);}}else if (boost::filesystem::path (output_file).extension () == ".stl"){PCL_ERROR ("STL file format does not support point clouds! Aborting.\n");return (false);}else // OBJ, PLY and VTK{//TODO: Support precision//FIXME: Color is lost during OBJ conversion (OBJ supports color)pcl::PolygonMesh mesh;mesh.cloud = *input;if (!saveMesh (mesh, output_file, output_type))return (false);}return (true);
}/*** Saves a mesh into the specified file and output type. The file format is automatically parsed.* @param input[in] The mesh to be saved* @param output_file[out] The output file to be written* @param output_type[in] The output file type* @return True on success, false otherwise.*/
bool
saveMesh (pcl::PolygonMesh& input,std::string output_file,int output_type)
{if (boost::filesystem::path (output_file).extension () == ".obj"){if (output_type == BINARY || output_type == BINARY_COMPRESSED)PCL_WARN ("OBJ file format only supports ASCII.\n");//TODO: Support precision//FIXME: Color is lost during conversion (OBJ supports color)PCL_INFO ("Saving file %s as ASCII.\n", output_file.c_str ());if (pcl::io::saveOBJFile (output_file, input) != 0)return (false);}else if (boost::filesystem::path (output_file).extension () == ".pcd"){if (!input.polygons.empty ())PCL_WARN ("PCD file format does not support meshes! Only points be saved.\n");pcl::PCLPointCloud2::Ptr cloud = boost::make_shared<pcl::PCLPointCloud2> (input.cloud);if (!savePointCloud (cloud, output_file, output_type))return (false);}else // PLY, STL and VTK{if (output_type == BINARY_COMPRESSED)PCL_WARN ("PLY, STL and VTK file formats only supports ASCII and binary output file types.\n");if (input.polygons.empty() && boost::filesystem::path (output_file).extension () == ".stl"){PCL_ERROR ("STL file format does not support point clouds! Aborting.\n");return (false);}PCL_INFO ("Saving file %s as %s.\n", output_file.c_str (), (output_type == ASCII) ? "ASCII" : "binary");if (!pcl::io::savePolygonFile (output_file, input, (output_type == ASCII) ? false : true))return (false);}return (true);
}/*** Parse input files and options. Calls the right conversion function.* @param argc[in]* @param argv[in]* @return 0 on success, any other value on failure.*/
int
main (int argc,char** argv)
{// Display helpif (pcl::console::find_switch (argc, argv, "-h") != 0 || pcl::console::find_switch (argc, argv, "--help") != 0){displayHelp (argc, argv);return (0);}// Parse all files and optionsstd::vector<std::string> supported_extensions;supported_extensions.push_back("obj");supported_extensions.push_back("pcd");supported_extensions.push_back("ply");supported_extensions.push_back("stl");supported_extensions.push_back("vtk");std::vector<int> file_args;for (int i = 1; i < argc; ++i)for (size_t j = 0; j < supported_extensions.size(); ++j)if (boost::algorithm::ends_with(argv[i], supported_extensions[j])){file_args.push_back(i);break;}std::string parsed_output_type;pcl::console::parse_argument (argc, argv, "-f", parsed_output_type);pcl::console::parse_argument (argc, argv, "--format", parsed_output_type);bool cloud_output (false);if (pcl::console::find_switch (argc, argv, "-c") != 0 ||pcl::console::find_switch (argc, argv, "--cloud") != 0)cloud_output = true;// Make sure that we have one input and one output file onlyif (file_args.size() != 2){PCL_ERROR ("Wrong input/output file count!\n");displayHelp (argc, argv);return (-1);}// Convert parsed output type to output typeint output_type (BINARY);if (!parsed_output_type.empty ()){if (parsed_output_type == "ascii")output_type = ASCII;else if (parsed_output_type == "binary")output_type = BINARY;else if (parsed_output_type == "binary_compressed")output_type = BINARY_COMPRESSED;else{PCL_ERROR ("Wrong output type!\n");displayHelp (argc, argv);return (-1);}}// Try to load as meshpcl::PolygonMesh mesh;if (boost::filesystem::path (argv[file_args[0]]).extension () != ".pcd" &&pcl::io::loadPolygonFile (argv[file_args[0]], mesh) != 0){PCL_INFO ("Loaded a mesh with %d points (total size is %d) and the following channels:\n%s\n",mesh.cloud.width * mesh.cloud.height, mesh.cloud.data.size (), pcl::getFieldsList (mesh.cloud).c_str ());if (cloud_output)mesh.polygons.clear();if (!saveMesh (mesh, argv[file_args[1]], output_type))return (-1);}else if (boost::filesystem::path (argv[file_args[0]]).extension () == ".stl"){PCL_ERROR ("Unable to load %s.\n", argv[file_args[0]]);return (-1);}else{// PCD, OBJ, PLY or VTKif (boost::filesystem::path (argv[file_args[0]]).extension () != ".pcd")PCL_WARN ("Could not load %s as a mesh, trying as a point cloud instead.\n", argv[file_args[0]]);//Eigen::Vector4f origin; // TODO: Support origin/orientation//Eigen::Quaternionf orientation;pcl::PCLPointCloud2::Ptr cloud (new pcl::PCLPointCloud2);if (pcl::io::load (argv[file_args[0]], *cloud) < 0){PCL_ERROR ("Unable to load %s.\n", argv[file_args[0]]);return (-1);}PCL_INFO ("Loaded a point cloud with %d points (total size is %d) and the following channels:\n%s\n", cloud->width * cloud->height, cloud->data.size (),pcl::getFieldsList (*cloud).c_str ());if (!savePointCloud (cloud, argv[file_args[1]], output_type)){PCL_ERROR ("Failed to save %s.\n", argv[file_args[1]]);return (-1);}}return (0);
}
對應的CMakeLists.txt文件的編寫如下 ,有些基本理解
cmake_minimum_required(VERSION 2.8 FATAL_ERROR) #Cmake的最低版本project(yao_pcl) #PROJECT(project_name [CXX] [C] [Java])這個指令定義工程名稱,后面可以指定工程所支持的語言,當然也是可以不寫忽略的,那么默認情況下就是支持所有語言的,set(SRC_LIST yao_convert.cpp)#SET(SRC_LIST yao_convert.cpp) 這里對于在CMake中關鍵字對于大小寫不敏感#set(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]]) SET 指令用來顯式的定義變量,同時也可以定義多個文件 比如#SET(SRC_LIST main.cpp yao_1.cpp yao_2.cpp)。#PCL庫find_package(PCL 1.8 REQUIRED)include_directories(${PCL_INCLUDE_DIRS})link_directories(${PCL_LIBRARY_DIRS})add_definitions(${PCL_DEFINITIONS})add_executable(yao_convert ${SRC_LIST})
#定義了這個工程會生成一個文件名為 hello 的可執行文件,相關的源文件是 SRC_LIST 中
#定義的源文件列表,注意這里使用變量引用的方式是${}這是CMake變量應用方式,但是,有一些例外,比如在 IF 控制語句,變量是直接使用變量名引用,而不需要${}
target_link_libraries(yao_convert ${PCL_LIBRARIES})
編譯該代碼命令:
mkdir build
cd build
cmake …
make
上述過程就是所謂的out-of-source 外部編譯,一個最大的好處是,對于原有的工程沒 有任何影響,所有動作全部發生在編譯目錄。通過這一點,也足以說服我們全部采用外部編譯方式構建工程。
總結基本語法:
1,變量使用${}方式取值,但是在IF 控制語句中是直接使用變量名
2,指令(參數1 參數2…) 參數使用括弧括起,參數之間使用空格或分號分開。
以上面的ADD_EXECUTABLE 指令為例,如果存在另外一個func.cpp 源文件,就要寫成: ADD_EXECUTABLE(hello main.cpp func.cpp)
3,指令是大小寫無關的,參數和變量是大小寫相關的
關于語法上的疑惑
SET(SRC_LIST main.c)也可以寫成SET(SRC_LIST “main.cpp”)
是沒有區別的,但是假設一個源文件的文件名是fu nc.c(文件名中間包含了空格)。
這時候就必須使用雙引號,如果寫成了SET(SRC_LIST fu nc.c),就會出現錯誤,提示你找不到fu 文件和nc.cpp 文件。這種情況,就必須寫成:
SET(SRC_LIST “fu nc.cpp”)
清理工程:
運行: make clean
即可對構建結果進行清理。
以上就是全部內容,可能存在一些錯誤歡迎指示,并可以發郵件交流,您可以可以關注微信公眾號。加入我們翻譯小組或者加入經營微信公眾號群,也加入技術交流群與跟多的小伙伴一起交流。
總結
以上是生活随笔為你收集整理的CMake结合PCL库学习(1)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PCL_common模块api代码解析
- 下一篇: CMake结合PCL库学习(2)