前言
可能我们有时候已经习惯了使用大型IDE去编写一些C 工程,经常使用大型IDE例如VS、Clion、VC 6.0,这些大型的软件都已经为我们提供好了编译链接工具,我们不需要自己去手动设置编译器,也不需要了解相关知识就可以写代码进行编译运行。
但有时候我们还需要去了解这些知识,虽然可能与编写代码关系不大,但是当我们实际拿大型工程落地时,这些技能就是必要的。
当然本文并不是要详细讲解make、cmake等工具的使用,这篇文章主要是借助VSCODE这个非常灵活的平台,利用cmake工具完整地过一边代码,并且经过cmake处理编译后执行的过程。这样可以对整个项目的编译过程有一个比较明确的理解。
如果对以上一些概念不是很熟悉的可以看这里:编译器gcc、clang、make、cmake辨析。
正文
关于如何利用VScode和C 构建大型项目的教程,官方已经提供了一份关于C 的配置指南:https://code.visualstudio.com/docs/languages/cpp
但是这份配置指南仅仅适合比比较小型的项目,当我们识图自己设计或者编译类似于OpenCV等大型项目时,光使用简单的搭建方式是不够用的,因此,无论是小项目还是大项目都有必要使用跨平台的构建工具:cmake,当然VScode中也是有cmake插件的,它可以自动检测我们系统内的cmake并且使用它。
那么我们开始吧,首先我们创建一个测试文件夹,再打开VScode,然后添加一个main.cpp
:
其中的代码来自于利用Pytorch的C 前端(libtorch)读取预训练权重并进行预测,使用的库为OpenCV和libtorch(如果不明白这是什么库的童鞋只知道是两个库就可以,在这里我们的程序中要链接它们)。
可以看到我们这段代码中需要这两个库,而上面的绿色波浪线显示这两个库的头文件还没有找到。
代码语言:javascript复制#include <torch/script.h> // libtorch
#include <opencv2/opencv.hpp> // OpenCV
这两个库怎么找,我们交给cmake吧~
cmake
首先我们找到cmake(CMake Tools)插件并且重新激活下使其生效,
然后我们编写自己的CMakeLists.txt文件:
代码语言:javascript复制cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
project(example-app)
find_package(Torch REQUIRED) // 这里使用命令查找libtorch库
find_package(OpenCV REQUIRED) // 这里使用命名查找OpenCV库
if(NOT Torch_FOUND)
message(FATAL_ERROR "Pytorch Not Found!")
endif(NOT Torch_FOUND)
message(STATUS "Pytorch status:")
message(STATUS " libraries: ${TORCH_LIBRARIES}")
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
add_executable(example-app main.cpp)
# link_directories(/usr/local/lib) 'find_package' has already done this
target_link_libraries(example-app "${TORCH_LIBRARIES}")
target_link_libraries(example-app "${OpenCV_LIBS}")
set_property(TARGET example-app PROPERTY CXX_STANDARD 11)
因为我们的libtorch并不是安装到了系统路径上(例如/usr/bin /usr/local/),所以直接使用Cmake命令是查找不出来的(但是OpenCV我们安装到了系统路径上,所以不用担心就可以找到),因此我们需要在Cmake的参数中添加libtorch库的路径。
CMake传递命令的参数我们在哪儿添加呢?
打开当前工作目录的setting界面,例如USER SETTINGS,添加我们Cmake的配置参数:
代码语言:javascript复制{
...
"cmake.configureArgs":["-DCMAKE_PREFIX_PATH=/home/prototype/Desktop/Cuda-project/libtorch"],
}
好,然后我们执行Cmake的confit命令,我们直接调用命令台工具(Ctrl Shift P),然后选择Cmake Config:
这时候输出配置信息:
代码语言:javascript复制[cmake] Looking for pthread.h
[cmake] Looking for pthread.h - found
[cmake] Looking for pthread_create
[cmake] Looking for pthread_create - not found
[cmake] Looking for pthread_create in pthreads
[cmake] Looking for pthread_create in pthreads - not found
[cmake] Looking for pthread_create in pthread
[cmake] Looking for pthread_create in pthread - found
[cmake] Found Threads: TRUE
[cmake] Found CUDA: /usr/local/cuda (found suitable version "9.2", minimum required is "7.0")
[cmake] Caffe2: CUDA detected: 9.2
[cmake] Caffe2: CUDA nvcc is: /usr/local/cuda/bin/nvcc
[cmake] Caffe2: CUDA toolkit directory: /usr/local/cuda
[cmake] Caffe2: Header version is: 9.2
[cmake] Found CUDNN: /usr/local/cuda/include
[cmake] Found cuDNN: v7.4.1 (include: /usr/local/cuda/include, library: /usr/local/cuda/lib64/libcudnn.so)
[cmake] Autodetected CUDA architecture(s): 6.1;6.1
[cmake] Added CUDA NVCC flags for: -gencode;arch=compute_61,code=sm_61
[cmake] Found torch: /home/prototype/Desktop/Cuda-project/libtorch/lib/libtorch.so
[cmake] Found OpenCV: /usr/local (found version "4.0.0")
[cmake] Pytorch status:
[cmake] libraries: torch;caffe2_library;caffe2_gpu_library;/usr/lib/x86_64-linux-gnu/libcuda.so;/usr/local/cuda/lib64/libnvrtc.so;/usr/local/cuda/lib64/libnvToolsExt.so;/usr/local/cuda/lib64/libcudart_static.a;-lpthread;dl;/usr/lib/x86_64-linux-gnu/librt.so
[cmake] OpenCV library status:
[cmake] version: 4.0.0
[cmake] libraries: opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio
[cmake] include path: /usr/local/include/opencv4
[cmake] Configuring done
[cmake] Generating done
提示所有库都找到了。
然后我们点击下面的build按钮:
就可以进行编译了:
代码语言:javascript复制[build] Starting build
[proc] Executing command: /home/prototype/anaconda3/bin/cmake --build /home/prototype/test/build --config Debug --target all -- -j 14
[build] Scanning dependencies of target example-app
[build] [ 50%] Building CXX object CMakeFiles/example-app.dir/main.cpp.o
[build] [100%] Linking CXX executable example-app
[build] [100%] Built target example-app
[build] Build finished with exit code 0
这里也是提示我们编译成功,成功后我们的目录是这样的:
所有的编译后的东西自动被这个cmake插件放入了build文件夹中,这个文件夹也是cmake插件自动生成的。
我们进入build文件夹执行一下我们生成的可执行文件:
代码语言:javascript复制prototype@prototype-X299-UD4-Pro:~/test$ cd build/
prototype@prototype-X299-UD4-Pro:~/test/build$ ./example-app
usage: example-app <path-to-exported-script-module>
prototype@prototype-X299-UD4-Pro:~/test/build$ ./example-app /home/prototype/Desktop/Deep-Learning/Pytorch-Learn/test/mobilenetv2-trace.pt
Time used:2521.94 ms
很快便输出了执行结果。
但是现在仍然还有两个问题:
- 代码中的头文件依然显示没有找到,也就是之前所说的两个波浪线依然存在
- 每次我们执行程序都需要进入终端然后执行命令行,稍微有点麻烦
下面我们便解决这两个问题:
C/C 拓展
下面这个插件是官方推荐的,在VScode端编写C 代码必备的插件:
我们安装后直接在VScode的工具台启动它:
这时候会在.vscode中生成一个配置文件c_cpp_properties.json
:
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c 17",
"intelliSenseMode": "clang-x64"
}
],
"version": 4
}
然后我们加入这一句:"configurationProvider": "vector-of-bool.cmake-tools",
意思是我们C 的配置信息由之前的Cmake插件提供,这样之后,我们就可以在浏览代码中正常显示我们的头文件了(可以看到头文件下面没有绿色波浪线了):
C 编译器在不同的操作平台上式不同的。在window下,推荐使用mingw-w64,对于mac来说就是XCode自带的Clang。对于Linux来说就是我们经常见到的GCC,之前我们并没有说我们的编译器是什么,因为我们在配置Cmake的时候其会自动搜索当前系统中所有存在编译器然后让我们去选择:
当然我们在选择后也可以在setting中修改,这里不多说了,尽情地探索吧~
tasks.json
之前提到我们在执行编译好的文件后总是需要进入终端再执行命令,很是麻烦,所以我们使用tasks.json
:
点击配置后,我们选择最后一个配置档(other config),然后我们的task.json
如下:
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "echo", <-- 这个是我们设置的task的名字
"type": "shell",
"command": "echo Hello"
}
]
}
我们把上面的command指令换成"command": "build/example-app /home/prototype/Desktop/Deep-Learning/Pytorch-Learn/test/mobilenetv2-trace.pt"
,也就是我们之前手动执行编译好的程序时输入的指令,我们修改后在命令台运行Task:run,选择echo
,执行后会出现:
> Executing task: build/example-app /home/prototype/Desktop/Deep-Learning/Pytorch-Learn/test/mobilenetv2-trace.pt <
Time used:2535.58 ms
Terminal will be reused by tasks, press any key to close it.
可以看到和之前的一样,但是我们不需要自己手动输入一些其他信息了,很是方便。
DEBUG
Debug也一样,我们点击VScode左侧的debug图标,配置launch.json即可,注意"program": "${command:cmake.launchTargetPath}",
设置为Cmake插件的debug模式:
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"args": [],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": true,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
]
}
]
}
这样,我们选择Debug模式的Cmake后,然后build,然后再点击最下方的debug按钮即可进行调试:
后记
上面的这些操作只是简单的操作,我们可以根据项目的需求,自己进行拓展延伸从而可以对大型项目进行编译构造。
参考资料
https://stackoverflow.com/questions/39126648/cmake-does-not-find-includes-libraries
http://www.cnblogs.com/feifanrensheng/p/9695749.html