1. 安装
环境:Ubuntu+Nvidia GPU 、 Nvidia Jeston 系列
安装VSCode
VSCode插件
- C/C++
- Chinese(Simplified)(简体中文)
- CMake Tools
- Python
- C/C++ Extension Pack
- C/C++ Themes
- CMake
- isort
- Pylance
- Jupyter
2. VScode使用
一般的项目目录结构
2.1 调试Python代码
launch.json
点击左边的运行和调试,如果.vscode目录下没有launch.json文件,那么就点“创建launch.json”文件
选择Python File:
然后复制下面的内容进去:
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}", // 当前文件
// "program": "demo.py", // 指定文件
"console": "integratedTerminal",
"justMyCode": true // false表示可以进入第三方库(如Pytorch)里进行调试
}
]
}
名词解释
name对应的是调试的名字:
program:要调试的代码的绝对目录,一般填的是“${file}”, 也可以改成其他的文件。
justMyCode 表示是否只调试自己写的代码,改成False就可以跳到第三方库如Pytroch里面。
调试
然后进入py文件,点击左侧的调试按钮,就可以开始调试:
如果要切换Python解释器的路径,可以在vscode中,使用快捷键 ctrl + shift + p, 然后输入:
select interpreter
选择对应的python解释器即可。
2.2 调试C++代码
点击终端–运行生成任务–找到对应编辑器,点击右边的齿轮即可在.vscode目录下生成task.json文件。
找到编辑器位置的方法:which g++
task.json
用于生成可执行文件,核心是要改里面的args参数。
配置好后,在终端–运行生成任务(Ctrl+Shift+B), 就可以在release目录下生成一个可执行文件,“-o”里面有指定输出的文件夹的文职
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "C/C++: g++ 生成活动文件",
"command": "/usr/bin/g++", // g++的路径,通过which g++ 查看
"args": [
"-fdiagnostics-color=always", // 颜色
"-g", // 调试信息
"-Wall", // 开启所有警告
"-std=c++14", // c++14标准
"${file}", // 文件本身,仅适用于C++基础知识教学,无法同时编译所有文件
// "${fileDirname}/*.cpp", // 文件所在的文件夹路径下所有cpp文件
"-o", // 输出
"${workspaceFolder}/release/${fileBasenameNoExtension}" // 文件所在的文件夹路径/release/当前文件的文件名,不带后缀
],
"options": {
"cwd": "${fileDirname}" // 文件所在的文件夹路径
},
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "编译器: /usr/bin/g++"
}
]
}
变量解释
以:/home/Coding/Test/.vscode/tasks.json 为例
${workspaceFolder} :表示当前workspace文件夹路径,也即/home/Coding/Test
${workspaceRootFolderName}:表示workspace的文件夹名,也即Test
${file}:文件自身的绝对路径,也即/home/Coding/Test/.vscode/tasks.json
${relativeFile}:文件在workspace中的路径,也即.vscode/tasks.json
${fileBasenameNoExtension}:当前文件的文件名,不带后缀,也即tasks
${fileBasename}:当前文件的文件名,tasks.json
${fileDirname}:文件所在的文件夹路径,也即/home/Coding/Test/.vscode
${fileExtname}:当前文件的后缀,也即.json
${lineNumber}:当前文件光标所在的行号
${env:PATH}:系统中的环境变量
launch.json
用于调试(Debug)代码,如果要调试C++代码,需要在上面Python的基础上进行一些修改
不要删掉launch.json原来的内容,打开launch.json后,点击“添加配置” ,选择 C/C++(gdb)启动
添加配置后,需要修改的内容如下:
- 在setupCommands后面新增 “preLaunchTask”: “C/C++: g++ 生成活动文件” , 其中, “C/C++: g++ 生成活动文件” 就是task.json中的 label
- program:对应的东西,是我们要调试的可执行程序的位置,对应的是task.json里面的"-o"。即 “${workspaceFolder}/release/ ${fileBasenameNoExtension}”
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "C++调试 (gdb) 启动",
"type": "cppdbg", // C++调试
"request": "launch",
"program": "${workspaceFolder}/release/${fileBasenameNoExtension}", // 文件所在的文件夹路径/release/当前文件的文件名,不带后缀
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}", // 文件所在的文件夹路径
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "为 gdb 启用整齐打印",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "将反汇编风格设置为 Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"preLaunchTask": "C/C++: g++ 生成活动文件" // tasks.json的label
},
{
"name": "Python: Current File",
"type": "python",
"request": "launch",
"program": "${file}", // 当前文件
// "program": "demo.py", // 指定文件
"console": "integratedTerminal",
"justMyCode": true // false表示可以进入第三方库(如Pytorch)里进行调试
}
]
}
调试
调试按钮中,选择C++调试的名字,然后点击绿色调试按钮。
3. Cmake的使用
为什么使用Cmake?
答:引用外部库如gflags,需要在命令行添加很多参数,很麻烦
3.1 安装Cmake
sudo apt install cmake -y
或者编译安装(推荐,可以指定版本)
# 以v3.25.1版本为例
git clone -b v3.25.1 https://github.com/Kitware/CMake.git
cd CMake
# 你使用`--prefix`来指定安装路径,或者去掉`--prefix`,安装在默认路径。
./bootstrap --prefix=<安装路径> && make && sudo make install
# 验证
cmake --version
3.2 使用示例
3.2.1 命令行运行
# 第一步:配置,-S 指定源码目录,-B 指定构建目录
cmake -S . -B build
# 第二步:生成,--build 指定构建目录
cmake --build build
# 运行
./build/first_cmake
3.2.2 Cmake-tools 插件运行
先把build文件夹删掉,启用Cmake-tools插件
然后点击左侧的Cmake-tools图标,点击重新配置项目,然后随便选一个编辑器。
然后在生成那里,点击最右侧的生成按钮即可生成build文件和可执行文件。
./ 运行可执行文件。
3.3 语法基础
a.指定版本
# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.10)
# first_cmake是项目名称,VERSION是版本号,DESCRIPTION是项目描述,LANGUAGES是项目语言
project(first_cmake
VERSION 1.0.0
DESCRIPTION "项目描述"
LANGUAGES CXX)
# 添加一个可执行程序,first_cmake是可执行程序名称,main.cpp是源文件
add_executable(first_cmake main.cpp)
命令cmake_minimum_required来指定当前工程所使用的CMake版本,不区分大小写的,通常用小写。VERSION是这个函数的一个特殊关键字,版本的值在关键字之后。CMake中的命令大多和cmake_minimum_required相似,不区分大小写,并有很多关键字来引导命令的参数输入(类似函数传参)。
b.设置项目
project(ProjectName
VERSION 1.0.0
DESCRIPTION "项目描述"
LANGUAGES CXX)
在CMakeLists.txt的开头,都会使用project来指定本项目的名称、版本、介绍、与使用的语言。在project中,第一个ProjectName(例子中用的是first_cmake)不需要参数,其他关键字都有参数。
c.添加可执行目标文件
add_executable(first_cmake main.cpp)
add_executable用于生成可执行文件。
这里我们用到add_executable,其中第一个参数是最终生成的可执行文件名以及在CMake中定义的Target名。我们可以在CMake中继续使用Target的名字为Target的编译设置新的属性和行为。命令中第一个参数后面的参数都是编译目标所使用到的源文件。
d.生成静态库
目录结构:accound_dir是我们要生成静态库的目录。test_account是要链接静态库的目录。
这里我们用到add_library,和add_executable一样,Account为最终生成的库文件名(lib库名称.a),第二个参数是用于指定链接库为动态链接库(SHARED)还是静态链接库(STATIC),后面的参数是需要用到的源文件。
进入account_dir,执行编译命令,可以生成build目录以及静态库 libAccount.a
这里我们只需要libAccount.a 文件,所以把build目录下其他文件删掉。
e.链接静态库
先看一下代码
CMakeList.txt
# test_account/CMakeLists.txt
# 最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目名称
project(test_account)
# 添加执行文件
add_executable(test_account test_account.cpp)
# 添加头文件.h文件目录,如果不添加,找不到头文件
target_include_directories(test_account PUBLIC "../account_dir")
# 添加静态库库文件目录,如果不添加,找不到库文件
target_link_directories(test_account PUBLIC "../account_dir/build")
# 添加目标链接库,Account的名字和accound_dir/CMakeList.txt中的add_library中的名字一样
target_link_libraries(test_account PRIVATE Account)
我们通过add_library和add_executable定义了Target,我们可以通过Target的名称为其添加属性,例如:
- 通过target_include_directories,我们给test_account添加了头文件引用路径"…/account_dir"。上面的关键词PUBLIC,PRIVATE用于说明目标属性的作用范围,更多介绍参考下节。
- 通过target_link_libraries,将前面生成的静态库libAccount.a链接给对象test_account,但此时还没指定库文件的目录,CMake无法定位库文件
- 再通过target_link_directories,添加库文件的目录即可。
注:如果不链接静态库的话会报错:
编译运行结果:
程序执行顺序为:main() --> Account的构造函数–>Account的析构函数
f.生成动态库
改成SHARED即可,静态库的全名是libAcoocun.so,静态库是 .a
编译account_dir:
同样的只留下.so文件
g.链接动态库
test_account下的cmakelist不做更改
可以使用ldd查看可执行文件所依赖的文件:
h.把两个cmakelist.txt合并到一起
合并到一起,一次性编译:
#6.build_together/CMakeLists.txt`
# 最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目信息
project(test_account)
# 添加动态库
add_library(Account SHARED "./account_dir/Account.cpp" "./account_dir/Account.h")
# 添加可执行文件
add_executable(test_account "./test_account/test_account.cpp")
# 添加头文件
target_include_directories(test_account PUBLIC "./account_dir")
# 添加链接库
target_link_libraries(test_account Account)
i. 全部编译
# 最低版本要求
cmake_minimum_required(VERSION 3.10)
# 项目信息
project(opencv_basic_input_output)
# 添加opencv库
find_package(OpenCV REQUIRED)
# 添加gflags库
find_package(gflags REQUIRED)
# 添加头文件(两个target都需要)
include_directories(${OpenCV_INCLUDE_DIRS} ${gflags_INCLUDE_DIRS})
link_libraries(${OpenCV_LIBS} ${gflags_LIBRARIES})
# 将src目录下的所有cpp文件编译成对应的可执行文件
# 例如:src/1_read_image.cpp -> 1_read_image
# 列出src目录下的所有cpp文件,存入SRC_FILES变量,它是一个列表,GLOBAL_RECURSE表示递归查找
file(GLOB_RECURSE SRC_FILES src/*.cpp)
message(STATUS "SRC_FILES: ${SRC_FILES}")
# 遍历SRC_FILES列表,对每个文件编译成一个可执行文件
foreach(SRC_FILE ${SRC_FILES})
# 获取文件名,不包含后缀,存入TARGET_NAME变量,NAME_WLE:File name with neither the directory nor the last extension
get_filename_component(TARGET_NAME ${SRC_FILE} NAME_WLE)
# 添加可执行文件
add_executable(${TARGET_NAME} ${SRC_FILE})
endforeach()
#[[
cmake -S . -B build
cmake --build build
]]
3.4 CMake 中的 PUBLIC、PRIVATE、INTERFACE
举例:
# 创建库
add_library(C c.cpp)
add_library(D d.cpp)
add_library(B b.cpp)
# C是B的PUBLIC依赖项
target_link_libraries(B PUBLIC C)
# D是B的PRIVATE依赖项
target_link_libraries(B PRIVATE D)
# 添加可执行文件
add_executable(A a.cpp)
# 将B链接到A
target_link_libraries(A B)
因为C是B的PUBLIC依赖项,所以C会传播到A
因为D是B的PRIVATE依赖性,所以D不会传播到A
3.4 CMake 中的 变量
像其他编程语言一样,我们应该将CMake理解为一门编程语言。我们也需要设定变量来储存我们的选项,信息。有时候我们通过变量来判断我们在什么平台上,通过变量来判断我们需要编译哪些Target,也通过变量来决定添加哪些依赖。
设置变量
变量缓存
可以通过在命令行接收新的变量缓存的名字
内置变量
信息变量:
动态库变量:
设置为ON时,编译生成动态库.so文件
如果改成OFF,则生成的是.a静态库
描述系统的变量
3.5 include引入其他代码
3.6 if 条件分支
if(variable)
# 为true的常量:ON、YES、TRUE、Y、1、非0数字
else()
# 为false的常量:OFF、NO、FALSE、N、0、空字符串、NOTFOUND
endif()
可以和条件一起使用的关键词有
NOT, TARGET, EXISTS (file), DEFINED等
STREQUAL, AND, OR, MATCHES (regular expression), VERSION_LESS, VERSION_LESS_EQUAL等
3.7 函数和宏
# 定义一个宏,宏名为my_macro,没有参数
macro(my_macro)
message("宏内部的信息")
set(macro_var "宏内部变量test")
endmacro(my_macro)
# 定义一个函数,函数名为second_func,有两个参数
function(second_func arg1 arg2)
message("第一个参数:${arg1}, 第二个参数:${arg2}")
endfunction(second_func)
3.8 发布安装
当需要发布项目时你需要指定项目文件的安装路径。下面的代码片段中,使用install安装demo_test,并分别将可执行文件安装在bin中,动态链接库和静态链接库都安装在lib,公共头文件安装在include。这里的路径都将添加${CMAKE_INSTALL_PREFIX}作为前缀(如果不设置CMAKE_INSTALL_PREFIX,则会安装到/usr/local 目录下)。实现安装的功能在你需要发布你项目给其他人使用时,非常有用。
# 设置安装
install(TARGETS demo_test
RUNTIME DESTINATION bin # 可执行文件
LIBRARY DESTINATION lib # 动态库
ARCHIVE DESTINATION lib # 静态库
PUBLIC_HEADER DESTINATION include # 公共头文件
)
3.9 find package
如果是自己的cmake文件,需要设置cmake搜索目录
设置库目录,用于自定义
通过缓存变量,设置dlib的安装路径
3.10 OpenCV示例