使用C/C++实现线性代数计算——环境bringup

概要

本文主要借助Eigen来实现矩阵运算,提供不同平台的编译方法,支持往STM32平台移植。Eigen是一个头文件库,提供了一组C++模板类用于线性代数运算,具有高性能、简洁和易用性的特点。其主要特性是:

  • 支持动态大小的矩阵和向量
  • 提供了广泛的线性代数运算
  • 直观的API设计
  • 高度优化的算法实现

参考资料:

  1. Eigen官方指导页面:https://eigen.tuxfamily.org/dox/GettingStarted.html

Windows平台

环境:Win10专业版,提供三种方式:IDE Codeblocks、IDE VS、cmake;

安装

Eigen提供的是源码,可以直接放在自己的C/C++项目里使用。对于有IDE的情况,直接在IDE的Project里面配置路径,对于无IDE的情况,本文提供两种方式:a、cmke+compile tools源码方式编译;b、预先将eigen预编译为库文件,然后在自己的project里面使用;

先官网下载最新稳定版的Eigen源码zip压缩包:https://eigen.tuxfamily.org/index.php?title=Main_Page
Eigen主页
下载后,解压缩到一个自己能找到的路径下面,例如:C:\MinGW\eigen-3.4.0。

cmake编译安装

参考文章:https://zhuanlan.zhihu.com/p/363769672
选择解压后的源码文件和build输出目录,点击Configuration,选择第一个默认的MinGW,然后确定等待配置完成;然后点击Generate,等待生成Makefiles.
在这里插入图片描述
生成完毕后,以管理员身份开一个cmd窗口,然后切到build目录下面,输入如下图两条命令:
在这里插入图片描述

此时Eigen已经编译安装OK,安装的路径在“C:\Program Files (x86)\Eigen3”。

codeblocks

第一种C/C++常用的IDE是Codeblocks,该工具轻量(不像VS那么重型)、开源、跨平台,非常适合开发一些小型的proj。

创建新Project

创建一个新Project,选择“Console Application”,接下来选择C++,然后自定义Project title、选一个自己喜欢的路径保存新Project,编译工具选择GCC,一路Next即可得到如下图:
新Codeblocks 项目示例
点击在这里插入图片描述 按钮,如果弹出一个“Hello World”新窗口,证明IDE能正常使用。

配置Eigen源码路径

在Code::Blocks中配置Eigen库的路径。具体步骤如下:
在“Project”菜单,选择“Build Options”;
在“Search directies”中,添加Eigen库头文件所在的目录路径。
在这里插入图片描述

写一个小demo

写一个官网提供的小demo测试一下:

#include <iostream>
#include <Eigen/Dense>

using Eigen::MatrixXd;
using Eigen::VectorXd;

int main()
{
	 MatrixXd m = MatrixXd::Random(3,3);
	 m = (m + MatrixXd::Constant(3,3,1.2)) * 50;
	 std::cout << "m =" << std::endl << m << std::endl;
	 VectorXd v(3);
	 v << 1, 2, 3;
	 std::cout << "m * v =" << std::endl << m * v << std::endl;
}

编译运行

点击编译运行,得到如下结果,说明测试OK。
在这里插入图片描述

Visual Studio

Visual Studio的编译使用与Codeblocks原理相同,都是源码直接参与编译,区别在于IDE中添加Eigen源码文件的方式,本文演示使用的是VS2022社区版,具体步骤如下:

新建VS项目

新建一个VS2022的新的空项目,然后找到右边侧边栏的“解决方案资源管理器”,右键“源文件”选择“新建项”,建一个空的main.cpp文件,
然后复制上面的demo程序到main.cpp中。

配置Eigen头文件路径

仍然点击“解决方案资源管理器”,选择到项目,右键选择最下面的“属性”,将会弹出下面的窗口,在“VC++目录”中给“包含目录”新建一个Eigen源码所在的路径,选择“应用”、“确定”即可。
在这里插入图片描述

编译验证

点击编译运行按钮在这里插入图片描述,输出内容与codeblock一致,验证通过。

cmake

源码解压后,在根目录可以看到有CMakeList.txt,说明支持cmake编译(事实上,Eigen最普遍的用法就是在Linux平台,尤其是Ubuntu,通过cmake编译安装的,后面会介绍到),这里我们提供两种方式,一种是源码方式与我们自己写的demo代码一起编译,生成可执行文件,这种方式本质上与上面介绍的两种IDE方式没有什么区别,只是我们借助cmake编译,而不是用IDE提供的编译工具链编译;第二种方式是编译生成一个Windows平台的库文件,然后在demo中使用。

源码方式

本方法需要事先安装cmake、MinGW工具,请事先准备好环境。

创建一个目录,结构如下:
在这里插入图片描述
其中main.cpp是C++源码文件,里面放置上面提供的demo实例程序,然后编写一个CMakelists.txt,内容如下:

cmake_minimum_required(VERSION 3.6)

project(eigen_demo VERSION 0.1)

add_executable(eigen_demo main.cpp)

# 解压的eigen-3.4.0所在路径
set(inc_path "D:/eigen-3.4.0")
target_include_directories(eigen_demo PUBLIC "${inc_path}")

进入cmd/powershell终端,依次执行如下命令:

# cmake编译
cmake -G "MinGW Makefiles" ..
cmake --build .

# 运行编译生成的exe文件
.\eigen_demo.exe

cmake是跨平台的工具,所以以上脚本也能在Linux系平台编译运行。

库文件方式

cmake脚本如下:

cmake_minimum_required(VERSION 3.6)

project(mylibeigen VERSION 0.1)

# 指定标准
set(CMAKE_CXX_STANDARD 14)

set(eigen_dir "D:/eigen-3.4.0")

# aux_source_directory("${eigen_dir}/Eigen/src" src_list)

# 添加静态库,静态/动态只能二者选其一
# add_library(mylibeigen STATIC "${eigen_dir}/Eigen/src")
# 添加动态库,静态/动态只能二者选其一
add_library(mylibeigen SHARED "${eigen_dir}/Eigen/src")

link_directories("${eigen_dir}/Eigen")

# 设置静态库的存放路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

#强制按照C++语言编译
set_target_properties(mylibeigen PROPERTIES LINKER_LANGUAGE CXX)

然后在终端执行:cmake -G "MingGW Makefiles .. && cmake --build .",即可在cmakelists.txt同级的lib目录(要事先建好空目录)里面找到对应的库文件,如下:
在这里插入图片描述
验证编译出的库文件是否能正常使用:
新建一个main.cpp文件,编写上述示例demo文件,然后新建一个CMakeListst.txt文件如下:

cmake_minimum_required(VERSION 3.6)

project(mylibeigen VERSION 0.1)

cmake_minimum_required(VERSION 3.6)

project(eigen_demo VERSION 0.1)

link_libraries(mylibeigen)
link_directories(${PROJECT_SOURCE_DIR}/lib)
add_executable(eigen_demo main.cpp)

set(inc_path "D:/eigen-3.4.0")
target_include_directories(eigen_demo PUBLIC "${inc_path}")

新建一个build目录并进入,编译,然后在同级build目录下生成一个新的exe文件,运行输出结果和上面一样。

Linux平台

事实上Eigen最普遍的使用环境正是Linux平台,下载eigen源码,按照以下步骤编译安装:

unzip /your/path/to/eigen-3.4.0
cd eigen-3.4.0
mkdir build
cd build
cmake ..
make install

执行完上述命令后,eigen安装到了/usr/local/include/eigen3路径下,引用头文件时#include <eigen3/Eigen/Dense>
编写上述测试代码,然后g++ main.cpp -o eigen_demo,生成可执行文件,终端执行结果符合预期。
如果编译时还是报错找不到头文件,可以尝试直接include绝对路径,或者已知绝对路径,在编译时指定头文件搜索路径,如g++ -I /usr/include/eigen3 main.cpp -o eigen_demo

无OS的开发板移植

环境:STM32开发板,开发环境是Windows+Keil。开发板使用的一般是C语言,而不是C++,直接将C/C++混合编译成bin文件,烧录到开发板中使用;

C/C++混合编译

官方提供的有在C语言中调用C++的demo示例,具体路径在:eigen-3.4.0\demos\mix_eigen_and_c,进去看一下里面的东西:
在这里插入图片描述
一个cpp源文件和头文件,一个c文件,在readme里还贴心的附上了如何使用该命令,我们先按照里面提供的命令试一下,分别在windows和linux跑一遍,如果能跑通,我们推导一下如果自己的项目要用到eigen,编译脚本应该如何写,最后在下一节配置一下Keil中的混合编译配置。
如果你安装过MinGW,那么在自己的cmd终端敲 g++ --versiongcc --version可以正常打印出版本号,这也就意味者我们在Windows终端能直接用官方提供的三行命令实现C中调用Eigen,需要提示的是,如果你敲第一行命令发现报了下面的错误:
在这里插入图片描述
可能意为demo项目中的cpp文件缺少了一个#include<iostream>宏,加上后就可以编译出cpp对应的.o目标文件了,这时再编译后面的命令就正常了,贴一个成功运行的截图:
在这里插入图片描述
OK,现在我们来分析一下在C语言中复用Eigen的原理,然后提炼出通用性的编译规则。

在C语言中不能直接用Eigen中暴露出的接口的,因为C++是C的一个超集,里面很多语法特性在C语言里是不支持的,这也是为啥需要有一个binary_library.cppbinary_library.h作为中间过渡,在cpp文件里主要做了1件事:将Eigen中类指针转成了struct类型的指针,这样就可以在C语言里面使用struct * 描述矩阵。h文件是一个纯粹的C头文件,里面将Eigen声明C++接口重新转了一把,并通过extern C语法告诉编译器,编译时如果是C环境就编译为C目标文件。

在编译时,官方提供了两行命令,第一行命令是用g++编译器编译出C目标文件,其中的-msse2是为了启动x86和x86-64架构的SSE2指令集,该指令集主要用于浮点数、线性计算等运算密集的场合。第二行命令是使用gcc将c文件和目标文件编译为可执行文件,-lstdc++是用于链接C++标准库,因为binary_library.cpp里对Eigen有依赖。

(PS:Linux环境的编译是一样的,这里不再赘述,如有问题可以留言或者在文末添加作者的联系方式,我们一起看看是啥问题!)

Keil中的设置

如何想要编译出能在STM32平台运行的bin文件,需要在IDE里设置一下编译选项,如下:
在这里插入图片描述
新建一个keil project项目,记得自动添加必要的stm32启动文件,否则链接时会发生错误。然后添加上面demo里的c/cpp文件,添加eigen-3.4.0公共头文件路径,然后配置c++编译语法,点击编译,可以正常编译出bin文件。后面我们借助这种方法集成到一个stm32项目中,烧录进去,即可实现矩阵相关的运算。

总结

本文主要介绍了不同的平台、不同的IDE,不同的编译场景下,Eigen的编译问题,为线性代数计算器做好环境setup,在使用的过程中,推荐优先使用源码编译。
·
·
·
·
最后的最后,如果你能看到这里,说明你可能遇到问题了,请关注wx公众号,“24K纯学渣”,添加作者联系方式,我们一起看看是什么奇怪的问题!

  • 4
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值