关键词
g++; vscode; c++; pkg-config; include; lib; linux; .pc; tasks.json; launch.json; WSL
前言
需求及手动解决方法
问题
很多时候需要使用别人开源的东西 for C/C++,我们的目标是使用别人的include
和链接库!这俩需求一般都包含在下载下来的文件,这里以下载好的onnxruntime-linux-x64-1.4.0.tgz
为例(这是onnx在linux上的发行版)。
解压之后文件结构如下:
onnxruntime-linux-x64-1.4.0$ tree
.
├── C_API.md
├── GIT_COMMIT_ID
├── LICENSE
├── Privacy.md
├── README.md
├── ThirdPartyNotices.txt
├── VERSION_NUMBER
├── include
│ ├── cpu_provider_factory.h
│ ├── cuda_provider_factory.h
│ ├── onnxruntime_c_api.h
│ ├── onnxruntime_cxx_api.h
│ └── onnxruntime_cxx_inline.h
└── lib
├── libonnxruntime.so -> libonnxruntime.so.1.4.0
└── libonnxruntime.so.1.4.0
- 其中
lib
问价下存储着我们的lib文件 - 然后
include
下存储着所有头文件
TIPS:C++动态库的使用、C++编译及执行过程
下面是原始的使用方法
pwd
mkdir test && cd test
touch test.cpp && vim ./test.cpp
然后输入
#include <iostream>
#include <onnxruntime_cxx_api.h>
int main() {
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "test"); // 测试
return 0;
}
用vscode打开会方便一些!
可以看到,此时搜索不到onnxruntime
for CPP
g++编译及vscode配置
设置c_cpp_properties.json
中的includePath
到onnxruntime的include
文件夹。
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/home/cola/cola/ColaMain/ColaStore/cache/onnxruntime-linux-x64-1.4.0/include"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "gnu17",
"cppStandard": "gnu++14",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}
编译的时候需要用到链接库文件,所以需要修改tasks.json
来编译!
先用g++
在命令行编译!
g++ test.cpp -o test -I ../include/ -L ../lib/ -lonnxruntime
./test
# 输出
./test: error while loading shared libraries: libonnxruntime.so.1.4.0: cannot open shared object file: No such file or directory
- 编译成功了,但是运行的时候失败,因为没有找到动态库
libonnxruntime.so.1.4.0
!
ldd ./test
linux-vdso.so.1 (0x00007ffff7487000)
libonnxruntime.so.1.4.0 => not found
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9cf06c0000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9cf06a0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9cf04a0000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9cf0351000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9cf08c2000)
直接复制到当前文件夹,即可!- 好像没起作用
- 重新编译,编译的时候指定动态库搜索路径
g++ test.cpp -o test -I ../include/ -L ../lib/ -lonnxruntime -Wl,-rpath=../lib
./test
# 输出成功
cola
然后设置vscode的tasks.json
原始如下:
- 当不包含特殊库且单个文件时,这样是可以的!
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++ 生成活动文件",
"command": "/usr/bin/g++",
"args": [
"-fdiagnostics-color=always",
"-g",
"${file}",
"-o",
"${fileDirname}/${fileBasenameNoExtension}"
],
"options": {
"cwd": "${fileDirname}"
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "编译器: /usr/bin/g++"
}
]
}
修改args
如下
- 可以看到,这和命令行编译时的参数是一一对应的!
"args": [
"-fdiagnostics-color=always",
"-g",
"test.cpp",
"-I",
"../include",
"-L",
"../lib",
"-lonnxruntime",
"-o",
"${fileDirname}/${fileBasenameNoExtension}",
"-Wl,-rpath=../lib",
],
执行该任务后,可以生成和在命令行一样的输出文件!
至此,我们就明确了要是用别人的一个库,需要怎么做
需求
-
明确我们要使用的主角仅仅是
include
下的头文件和lib
下的库文件 -
如果我们需要在其他很多地方使用库和头文件,则每次都需要自己写一大段命令行来用g++编译
-
这样很不方便呀!
需求
- 如何才能让
onnx
这种别人写好的库像标准库那样供我们使用呢!
明确
解决方案1:pkg-config
- 特点:专门用于用命令行编译的时候使用!
- 缺点:依然没有设置其能被全局
include
头文件和全局使用lib- 解决方案2可以解决!
类比
编译opencv
时,需要加上pkg-config --cflags --libs opencv4
,这是做啥呢!
echo `pkg-config --cflags --libs opencv4`
# 输出
-I/usr/local/include/opencv4 -L/usr/local/lib -lopencv_gapi -lopencv_highgui -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_video -lopencv_calib3d -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_core
- 可以看见,这其实就是将我们要在g++后面添加的参数,进行了设置!
所以,类比opencv
的,我们可以自己写一个config
,然后像这样使用!
原理
- 定义一个
xxx.pc
文件,那么pkg-config -xxx
就可以获得全部信息啦! - 注:
pkg-config
是一个命令
pkg-config
的信息来自于两个地方:
- 第一种:取系统的/usr/lib下的所有*.pc文件。
- 第二种:PKG_CONFIG_PATH环境变量所指向的路径下的所有*.pc文件。
添加自己的.pc
文件,两种方式:
-
把你的pc文件,直接放到
/usr/lib/…
默认路径下。 -
把你的pc文件的路径写到
PKG_CONFIG_PATH
环境变量里。写自己的
.pc
文件
参考opencv
的
# Package Information for pkg-config
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include/opencv4
Name: OpenCV
Description: Open Source Computer Vision Library
Version: 4.5.5
Libs: -L${exec_prefix}/lib -lopencv_gapi -lopencv_highgui -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_video -lopencv_calib3d -lopencv_features2d -lopencv_dnn -lopencv_flann -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_core
Libs.private: -ldl -lm -lpthread -lrt
Cflags: -I${includedir}
写onnx的!
# Package Information for pkg-config
prefix=/home/cola/cola/ColaMain/ColaStore/cache/onnxruntime-linux-x64-1.4.0/lib
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
Name: onnxruntime
Description: onnxruntime library made by cola in 2022年2月13日
Version: 1.4.0
Libs: -L${libdir} -lonnxruntime
Cflags: -I${includedir}
添以下到~/.bashrc
,然后再执行source ~/.bashrc
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/cola/cola/ColaMain/ColaStore/cache/Cola_pkgconfig
export PKG_CONFIG_PATH
测试
pkg-config onnxruntime --cflags --libs
# 输出
-I/home/cola/cola/ColaMain/ColaStore/cache/onnxruntime-linux-x64-1.4.0/lib/include -L/home/cola/cola/ColaMain/ColaStore/cache/onnxruntime-linux-x64-1.4.0/lib/lib -lonnxruntime
编译运行
g++ test.cpp -o test `pkg-config onnxruntime --libs --cflags`
./test
# 输出
./test: error while loading shared libraries: libonnxruntime.so.1.4.0: cannot open shared object file: No such file or directory
- 编译成功,但是运行时找不到
将.so
文件复制到当前目录下,然后:
g++ test.cpp -o test `pkg-config onnxruntime --libs --cflags` -Wl,-rpath=./
./test
# 输出 前提是 当前路径下有需要的.so文件
cola
附录:pkg-config
的参数
pkg-config onnxruntime --cflags --libs # 头文件信息和库信息
pkg-config --list-all # 所有pkg-config文件
解决方案2: 像标准库一样
想法
对,标准库不就是随地使用么!同时,我也希望onnx
能这样!
提前明确
todo
- 明确附录中:链接库的搜索路径!
- 完成方案2中对include和lib库搜索的设置!
- vscode中tasks.json到底如何使用
pkg-config
实作
参考:[库搜索路径的全局设置](#include
和lib
的全局搜索路径 by 环境变量)
include
和lib
的全局搜索路径 by 环境变量
注意
- 以下方法都是先明确对应命令所需文件的搜索文件夹路径
- 他们都会对应一个环境变量
- 然后我们修改环境变量
- 所有都是修改的
./bashrc
- 也可以修改
.bash_profile
- 二者区别
- 也可以修改
include路径设置
- https://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html
路径搜索优先级
CPATH # C/C++的
C_INCLUDE_PATH # C的
CPLUS_INCLUDE_PATH # C++的
OBJC_INCLUDE_PATH # OBJC_INCLUDE_PATH
修改方法
将以下内容加入到~/.bashrc
中
TMP_PATH="/home/cola/cola/ColaMain/ColaStore/cache/onnxruntime-linux-x64-1.4.0/include"
export CPATH=$CPATH:$TMP_PATH
vim ~/.bashrc
source ~/.bashrc
lib路径配置
- https://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html
原理:设置LIBRARY_PATH
和LD_LIBRARY_PATH
- 之前一直以为是
LD_LIBRARY_PATH
!结果一直出错!凸(艹皿艹 )- 区别在于前者是编译前,后者是编译后!我们需要的是编译前的搜索路径!
添加以下到~/.bashrc
TMP_PATH="/home/cola/cola/ColaMain/ColaStore/cache/onnxruntime-linux-x64-1.4.0/lib"
export LIBRARY_PATH=$LIBRARY_PATH:$TMP_PATH # for compile
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$TMP_PATH # for run time
测试
g++
命令行
g++ test.cpp -lonnxruntime -o test && ./test
# 输出
cola
编写vscode::tasks.json
附录
Linux环境下的include路径
查看当前C/C++中include的文件夹
- https://stackoverflow.com/questions/4980819/what-are-the-gcc-default-include-directories
$ cc -xc /dev/null -E -Wp,-v 2>&1 | sed -n 's,^ ,,p'
/usr/lib/gcc/x86_64-linux-gnu/9/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
$ c++ -xc++ /dev/null -E -Wp
,-v 2>&1 | sed -n 's,^ ,,p'
/usr/include/c++/9
/usr/include/x86_64-linux-gnu/c++/9
/usr/include/c++/9/backward
/usr/lib/gcc/x86_64-linux-gnu/9/include
/usr/local/include
/usr/include/x86_64-linux-gnu
/usr/include
Linux环境下链接库路径
- https://gcc.gnu.org/onlinedocs/cpp/Environment-Variables.html
程序运行时共享库的搜索路径:
-
环境变量
LD_LIBRARY_PATH
-
可执行程序的
-rpath
-WL,-rpath=PathToMyLib
-
系统搜索路径:
/lib
和/usr/lib
程序编译时的搜索路径: LD_LIBRARY_PATH
- https://stackoverflow.com/questions/4250624/ld-library-path-vs-library-path#:~:text=LIBRARY_PATH%20is%20used%20by%20gcc,been%20successfully%20compiled%20and%20linked.
- 可以在编译的时候用
g++ -v
参数查看!