使用conda管理C++项目依赖
之前尝试xrepo的时候了解到conda也可以管理C++项目1,现在针对常用的库验证下。conda安装过程不细说,建议参考官方文档2。由于conda提供的库多以动态链接形式发布,为了确保程序打包输出能正常运行,尝试通过cmake自动打包输出依赖的库文件。
1. 编译CGAL+qt项目
1.1 建立虚拟环境
首先要建立并激活虚拟环境。conda自带的默认虚拟环境为base,命名上注意不要和默认虚拟环境重名。这里通过虚拟环境安装依赖,避免不同项目之间的依赖产生冲突。
conda create -n cgal_env # 建立虚拟环境,-n 指定虚拟环境名称
conda activate cgal_env # 激活虚拟环境
虚拟环境激活之后会在shell前面显示(cgal_env)。如果是安装conda之后第一次建立虚拟环境,激活的时候可能会报错,一般重启shell即可解决。
激活虚拟环境之后,在虚拟环境中安装cgal包及其依赖。这里碰到一个问题,conda的托管的cgal不会自动安装依赖的qt6,得手动安装。
conda install cgal -c conda-forge # -c 指定通道 conda-forge
conda install qt6-main -c conda-forge
1.2 编写工程文件
以官方教程3为例,建立cmake项目文件夹surface_mesh_viewer。编写C++源文件main.cpp如下所示。
// main.cpp
/***
* reference: https://doc.cgal.org/latest/Manual/devman_create_and_use_a_cmakelist.html
***/
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/draw_surface_mesh.h>
#include <fstream>
#include <QApplication>
#include <QFileDialog>
typedef CGAL::Simple_cartesian<double> Kernel;
typedef Kernel::Point_3 Point;
typedef CGAL::Surface_mesh<Point> Mesh;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
const std::string filename = (argc > 1) ? argv[1] : QFileDialog::getOpenFileName(nullptr, "Open a mesh file", "", "Supported formats (*.off *.stl *.obj *.ply);;OFF format (*.off);;STL format (*.stl);;OBJ format (*.obj);;PLY format (*.ply)").toStdString();
if (filename.empty())
return EXIT_FAILURE;
Mesh sm;
if (!CGAL::IO::read_polygon_mesh(filename, sm))
{
if (filename.substr(filename.find_last_of(".") + 1) == "stl")
std::cerr << "Invalid STL file: " << filename << std::endl;
else if (filename.substr(filename.find_last_of(".") + 1) == "obj")
std::cerr << "Invalid OBJ file: " << filename << std::endl;
else if (filename.substr(filename.find_last_of(".") + 1) == "ply")
std::cerr << "Invalid PLY file: " << filename << std::endl;
else if (filename.substr(filename.find_last_of(".") + 1) == "off")
std::cerr << "Invalid OFF file: " << filename << std::endl;
else
std::cerr << "Invalid file: " << filename << "(Unknown file format.)" << std::endl;
return EXIT_FAILURE;
}
// Internal color property maps are used if they exist and are called
// "v:color", "e:color" and "f:color".
auto vcm =
sm.add_property_map<Mesh::Vertex_index, CGAL::IO::Color>("v:color").first;
auto ecm =
sm.add_property_map<Mesh::Edge_index, CGAL::IO::Color>("e:color").first;
auto fcm = sm.add_property_map<Mesh::Face_index>(
"f:color", CGAL::IO::white() /*default*/)
.first;
for (auto v : vertices(sm))
{
if (v.idx() % 2)
{
put(vcm, v, CGAL::IO::black());
}
else
{
put(vcm, v, CGAL::IO::blue());
}
}
for (auto e : edges(sm))
{
put(ecm, e, CGAL::IO::gray());
}
put(fcm, *(sm.faces().begin()), CGAL::IO::red());
// Draw!
CGAL::draw(sm);
return EXIT_SUCCESS;
}
这里用到了cmake作为编译工具,编写CMakeLists.txt文件。