Windows环境含第三方库代码编译的三种方式

       个人平时编译代码倾向于用轻量级和跨平台的方式,比如最常用的Cmake编译,还有VScode编译等。然而轻量级可能容易满足,跨平台因为各种原因往往受阻。最近正好有个合适的例子解决这个小问题,小小总结一下。方便起见,以高翔《视觉SLAM十四讲》第三章中Eigen库调用的eigenMatrix.cpp代码为例,源代码如下:

#include <iostream>
using namespace std;
#include <ctime>
// Eigen 部分
#include <Eigen/Core>
// 稠密矩阵的代数运算(逆,特征值等)
#include <Eigen/Dense>

#define MATRIX_SIZE 50

/****************************
* 本程序演示了 Eigen 基本类型的使用
****************************/

int main(int argc, char** argv)
{
    // Eigen 中所有向量和矩阵都是Eigen::Matrix,它是一个模板类。它的前三个参数为:数据类型,行,列
    // 声明一个2*3的float矩阵
    Eigen::Matrix<float, 2, 3> matrix_23;

    // 同时,Eigen 通过 typedef 提供了许多内置类型,不过底层仍是Eigen::Matrix
    // 例如 Vector3d 实质上是 Eigen::Matrix<double, 3, 1>,即三维向量
    Eigen::Vector3d v_3d;
    // 这是一样的
    Eigen::Matrix<float, 3, 1> vd_3d;

    // Matrix3d 实质上是 Eigen::Matrix<double, 3, 3>
    Eigen::Matrix3d matrix_33 = Eigen::Matrix3d::Zero(); //初始化为零
    // 如果不确定矩阵大小,可以使用动态大小的矩阵
    Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > matrix_dynamic;
    // 更简单的
    Eigen::MatrixXd matrix_x;
    // 这种类型还有很多,我们不一一列举

    // 下面是对Eigen阵的操作
    // 输入数据(初始化)
    matrix_23 << 1, 2, 3, 4, 5, 6;
    // 输出
    cout << matrix_23 << endl;

    // 用()访问矩阵中的元素
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++)
            cout << matrix_23(i, j) << "\t";
        cout << endl;
    }

    // 矩阵和向量相乘(实际上仍是矩阵和矩阵)
    v_3d << 3, 2, 1;
    vd_3d << 4, 5, 6;
    // 但是在Eigen里你不能混合两种不同类型的矩阵,像这样是错的
    // Eigen::Matrix<double, 2, 1> result_wrong_type = matrix_23 * v_3d;
    // 应该显式转换
    Eigen::Matrix<double, 2, 1> result = matrix_23.cast<double>() * v_3d;
    cout << result << endl;

    Eigen::Matrix<float, 2, 1> result2 = matrix_23 * vd_3d;
    cout << result2 << endl;

    // 同样你不能搞错矩阵的维度
    // 试着取消下面的注释,看看Eigen会报什么错
    // Eigen::Matrix<double, 2, 3> result_wrong_dimension = matrix_23.cast<double>() * v_3d;

    // 一些矩阵运算
    // 四则运算就不演示了,直接用+-*/即可。
    matrix_33 = Eigen::Matrix3d::Random();      // 随机数矩阵
    cout << matrix_33 << endl << endl;

    cout << matrix_33.transpose() << endl;      // 转置
    cout << matrix_33.sum() << endl;            // 各元素和
    cout << matrix_33.trace() << endl;          // 迹
    cout << 10 * matrix_33 << endl;               // 数乘
    cout << matrix_33.inverse() << endl;        // 逆
    cout << matrix_33.determinant() << endl;    // 行列式

    // 特征值
    // 实对称矩阵可以保证对角化成功
    Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eigen_solver(matrix_33.transpose() * matrix_33);
    cout << "Eigen values = \n" << eigen_solver.eigenvalues() << endl;
    cout << "Eigen vectors = \n" << eigen_solver.eigenvectors() << endl;

    // 解方程
    // 我们求解 matrix_NN * x = v_Nd 这个方程
    // N的大小在前边的宏里定义,它由随机数生成
    // 直接求逆自然是最直接的,但是求逆运算量大

    Eigen::Matrix< double, MATRIX_SIZE, MATRIX_SIZE > matrix_NN;
    matrix_NN = Eigen::MatrixXd::Random(MATRIX_SIZE, MATRIX_SIZE);
    Eigen::Matrix< double, MATRIX_SIZE, 1> v_Nd;
    v_Nd = Eigen::MatrixXd::Random(MATRIX_SIZE, 1);

    clock_t time_stt = clock(); // 计时
    // 直接求逆
    Eigen::Matrix<double, MATRIX_SIZE, 1> x = matrix_NN.inverse() * v_Nd;
    cout << "time use in normal inverse is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;

    // 通常用矩阵分解来求,例如QR分解,速度会快很多
    time_stt = clock();
    x = matrix_NN.colPivHouseholderQr().solve(v_Nd);
    cout << "time use in Qr decomposition is " << 1000 * (clock() - time_stt) / (double)CLOCKS_PER_SEC << "ms" << endl;

    return 0;
}

高翔博士给出了在Linux环境下用cmake编译的CMakelists.txt

cmake_minimum_required( VERSION 2.8 )
project( useEigen )

set( CMAKE_BUILD_TYPE "Release" )
set( CMAKE_CXX_FLAGS "-O3" )

# 添加Eigen头文件
include_directories( "/usr/include/eigen3" )

# in osx and brew install
# include_directories( /usr/local/Cellar/eigen/3.3.3/include/eigen3 )

add_executable( eigenMatrix eigenMatrix.cpp )

Linux环境对开发自然是很爽的啦,这个Linux环境下的CMakelists.txt我就不用测试了(即使有问题,解决也很easey!)下面着重说说对开发不太友好的Windows环境下如何编译这个调用第三方Eigen库的源代码。

1、第一种方式:Visual Studio2019编译

 首先,打开Visual Studio2019 IDE,在菜单栏选择文件=>新建=>项目,创建新项目(选C++空项目),配置新项目

(1)创建C++新项目

 (2)配置eigentest新项目

 然后,在右侧解决方案=>源文件=>添加=>现有项,添加eigenMatrix.cpp源代码。

再然后,在菜单栏项目=>属性=>C/C++=>常规=>附加包含目录中添加Eigen库的安装目录,          最后在配置选择release/debug模式,平台选择x64/x86平台,点击确定即可完成

 在菜单栏点击本地Windows调试器编译结果如下:

 客观地说,VS编译的方式中规中矩挺好的。但是细心点可以发现,对于本例就一个cpp文件的代码,配置编译竟然需要这么多环节,更不用说VS IDE启动慢、耗资源的问题了。

2、第二种编译方式:VS Code

可能微软也意识到VS问题了,才开发的VS Code。不像VS是Windows系统环境专用的IDE,VS Code其实就是个轻量级的编辑器,不过VS Code可以跨平台:除了在Windows系统环境可以用外,在Linux系统环境和Mac OS环境下也可以使用。当然喽,VS Code每次编译都要配置一遍,主要配置三个json文件:c_cpp_properterties.json,launch.json和tasks.json(这三个文件在源代码根目录下的.vscode隐藏文件中)。其实配置多了会发现这里有个小技巧:根据个人PC环境(操作系统及编译器等)配置一套基础版的.vscode的json文件,然后开发新项目时将整个基础版的.vscode文件夹copy到新项目文件夹根目录下;如果不调用第三方库的话,新项目就可以直接编译,如果新项目要调用第三方库,在json文件中配置第三方库即可。由于之前我根据自己的PC环境配置过一套.vscode的json文件,所以我就直接将整个.vscode文件夹copy到eigenMatrix.cpp文件根目录下了(官网和网上说这块配置的很多,这里就不细说了),具体如下:

c_cpp_properterties.json文件:

{
    "configurations": [
        {
            "name": "GCC",
            "includePath": [
                "${workspaceFolder}/**"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE"
            ],
            "windowsSdkVersion": "10.0.18362.0",
            "compilerPath": "C:/TDM-GCC-64/bin/g++.exe",
            "cStandard": "c17",
            "cppStandard": "c++17",
            "intelliSenseMode": "gcc-x64"
        }
    ],
    "version": 4
}

launch.json文件:

{

    "version": "0.2.0",

    "configurations": [

      {

        "name": "g++.exe - Build and debug active file",

        "type": "cppdbg",

        "request": "launch",

        "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",

        "args": [],

        "stopAtEntry": false,

        "cwd": "${workspaceFolder}",

        "environment": [],

        "externalConsole": false,

        "MIMode": "gdb",

        "miDebuggerPath": "C:\\TDM-GCC-64\\bin\\gdb.exe",

        "setupCommands": [

          {

            "description": "Enable pretty-printing for gdb",

            "text": "-enable-pretty-printing",

            "ignoreFailures": true

          }

        ],

        "preLaunchTask": "C/C++: g++.exe build active file"

      }

    ]

  }

tasks.json文件:

{
    "version": "2.0.0",
    "tasks": [
      {
        "type": "shell",
        "label": "C/C++: g++.exe build active file",
        "command": "C:\\TDM-GCC-64\\bin\\g++.exe",
        "args": ["-g", "${file}", "-o", "${fileDirname}\\${fileBasenameNoExtension}.exe"],
        "options": {
          "cwd": "${workspaceFolder}"
        },
        "problemMatcher": ["$gcc"],
        "group": {
          "kind": "build",
          "isDefault": true
        }
      }
    ]
  }

由于需要调用第三方Eigen库,需要在tasks.json文件“args”字段中添加"-I","D:\\eigen-3.3.9\\"

在VS Code菜单栏点击Run或按Ctrl+F5编译后结果如下:

 细心点的话可以发现,实际上时执行了编译命令: Executing task: C:\TDM-GCC-64\bin\g++.exe -g D:\Codes\c-cpp_work\cpp_work\EigenTest\eigenMatrix.cpp -o D:\Codes\c-cpp_work\cpp_work\EigenTest\eigenMatrix.exe -I D:\eigen-3.3.9\

虽然VS Code编译已经满足轻量级、跨平台编译的要求了,但是如果不用我发现的小技巧的话配置json文件还是略显繁琐,而且可能会经常遇到配置json文件不知道该在哪配置还有配置路径时斜杠/,反斜杠\,双反斜杠\\等问题。给追求轻量级、跨平台编译的开发人员来说缺了点爽快的感觉。

3、第三种编译方式:cmake编译

跟在Linux系统环境下cmake编译一样,写个CMakeLists.txt配置文件就可以了。只不过在Windows系统环境下可能第三方库是自定义安装的, find_package(XXX REQUIRED)去找的话有可能找不到导致编译失败。所以为防止查找失败最好指定第三方库的安装目录 include_directories("D:/yyy") 。话不多说,直接贴我的配置如下:

cmake_minimum_required (VERSION 2.6)
project (EigenTest)

add_executable (eigentest eigenMatrix.cpp)

#设置Eigen库路径
#include_directories("D:/eigen-3.3.9/")
find_package (Eigen)
if (Eigen_FOUND) 
    include_directories(${EIGEN_INCLUDE_DIRS})
    target_link_libraries (eigentest ${EIGEN_LIBRARIES})
    message("Find_package:${EIGEN_INCLUDE_DIRS}")
else(Eigen_FOUND)  
    include_directories("D:/eigen-3.3.9/")  
    target_link_libraries (eigentest ${EIGEN_LIBRARIES})
    message("Not find_package:${EIGEN_INCLUDE_DIRS}")
endif(Eigen_FOUND) 

这步跟高翔博士在Linux系统环境下的CMakeList.txt配置相比,可以认为只是根据个人PC环境修改了Eigen库的include_directories。配置完CMakeList.txt后,编译步骤如下:

(1)在eigenMatrix.cpp代码根目录新建build文件夹

(2)进入build文件夹路径栏输入cmd,进入DOS模式

(3)cmake编译(在DOS界面命令行执行:cmake .. -G"Unix Makefiles")

(4)make生成可执行文件(在DOS界面命令行执行:make)

(5)运行可执行exe文件(在DOS界面命令行执行:eigentest.exe)

eigentest.exe执行结果如下:

 cmake是根本意义上的轻量级、快平台的编译方式,个人比较推崇。但是在Windows系统环境下有很多坑:

比如上面提到的第三方库自定义安装后find_package就找不到了;

再比如编译时cmake ..常常会失败,所以你仔细看帖子的话会发现我用的命令是cmake .. -G"Unix Makefiles"

还有就是在Linux环境安装cmake很简单用apt-get install cmake 就好了,但是在Windows系统环境下除了安装cmake外还需要安装make命令,不然老会报错make不是命令!

本贴以Eigen库为例做了简单介绍,其他比如OpenCV等第三方库也可按照类似方式配置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值