cmake简明使用指南

Last update 2018/8/8

先执行cmake生成makefile,然后看看里面的内容,(至少在ubuntu16.04上的cmake3.5.1上),有如下内容提供:

# Help Target
help:
@echo "The following are some of the valid targets for this Makefile:"
@echo "... all (the default if no target is provided)"
@echo "... clean"
@echo "... depend"
@echo "... edit_cache"
@echo "... rebuild_cache"
@echo "... net_demo"
@echo "... src/net_demo.o"
@echo "... src/net_demo.i"
@echo "... src/net_demo.s"
.PHONY : help

其中net_demo是我自己的build target,可以忽略。可以看到,提供了edit_cache选项,则通过make edit_cache可以交互式的修改一些变量,挺好的。

why this manual?

必须用cmake

很多开源项目如KDE、VTK、OpenCV、Caffe等,都使用cmake来构建。要玩转这些项目,就需要掌握cmake。而且趋势是cmake会更加流行。

实际情况往往是,系统预装的opencv不够用,尝试编译opencv的时候遇到cmake各种问题,被折腾的死去活来,于是决定好好学一下cmake。

cmake资料不够好

cmake经历了多个版本发展,现在(2017.05.05)它的官方文档比原来有了很多进步。

现有的

小白视角

从一个cmake小白的角度来总结cmake的用法。

环境说明

cmake提供命令行方式,以及图形界面方式(包括cmake-GUI和ccmake)。这里仅使用cmake命令行方式,因为更简单直接。

使用ubuntu16.04, cmake3.5版。其他系统和cmake版本问题也都不大,因为本文尽量做到具备较好的通用性。

先确保安装了gcc,g++和cmake

hello world

最简单的cmake项目,不使用IDE(如CLion),也不考虑什么编码风格的,就是干,简单粗暴!

代码

编辑两个文件:main.cc和CMakeLists.txt。它们放在你的项目目录,比如~/work/hello-cmake

main.cc

#include <iostream>
using namespace std; int main(){
cout << "Hello World!" << endl;
return 0;
}

CMakeLists.txt

cmake_minimum_required (VERSION 2.8)
project(hello-world)
add_executable(hello main.cc)

运行

开终端,运行这些命令:

cd ~/work/hello-cmake    #进入你的cmake项目目录
cmake . #执行cmake
make #执行make

windows下的做法

可以用Visual Studio来编译

假设C++代码和CMakeLists.txt文件内容相同。那么打开cmd执行如下命令,或者把如下命令保存到一个文件(例如build.bat)中再执行这个文件:

# 在源码相同目录下构建
cmake -G "Visual Studio 14" #生成.sln文件
cmake --build . #调用native build tool。在windows上,相当于是打开.sln然后手动点击构建。

或者在专门的文件夹里面编译:

#当然,把编译出来的东西单独放到一个目录也是OK的
mkdir build
cd build
cmake -G "Visual Studio 14" ..
cmake --build .
cd ..

以及,可以指定用Release模式,x64架构:

BUILD_DIR=build
rm -rf $BUILD_DIR
mkdir -p $BUILD_DIR
cd $BUILD_DIR cmake \
-G "Visual Studio 14 Win64" \
.. cmake --build . --config Release
# 在windows上,必须在build的时候指定编译类型,而不是cmake的阶段

或者用Unix的构建工具套件,这里使用的是tdmgcc64。安装之后把mingw32-make.exe复制一份为make.exe再执行

mkdir buildUnix
cd buildUnix
cmake -G "Unix Makefiles" ..
make
cd ..

必要的解释

cmake命令会在提供的路径(上例为".")下,找到CMakeLists.txt并执行它。执行成功后生成makefile(或其他类似的,目前阶段就认为是makefile好了);执行make,会根据makefile内容去执行。

至于cmake和make执行了哪些操作,需要了解cmake的语法,以及makefile的编写规则。有了cmake,其实可以忽略makefile,不妨认为makefile就是写给编译器gcc看的。

更便利的运行方式

通常cmake运行后产生若干文件,和源码目录混杂在一起并不是一个好的选择。通常新建一个build目录,在build目录执行cmake。

个人倾向于建一个脚本,每次用cmake构建时,参数比较多,用这个脚本比较方便:

compile.sh

#!/bin/bash

set -x   #把本行后的脚本执行内容,打印到屏幕。用于调试
set -e #本行后,如果某行执行结果返回值不是true,那么终止 LOG="log.build"
touch $LOG
rm $LOG exec &> >(tee -a "$LOG") #将屏幕输出内容,同时写入log文件:便于后续查找 echo "Logging to $LOG" BUILD_ROOT=build
if [ -d $BUILD_ROOT ]; then
rm -rf $BUILD_ROOT
fi
mkdir -p $BUILD_ROOT
cd $BUILD_ROOT
echo "building root folder is $BUILD_ROOT" echo "Now do cmake" cmake .. echo "Now do make" make -j8 echo "Done"

执行构建脚本:

chmod +x compile.sh
./compile.sh
cd build
./hello

cmake使用原理

自顶向下看,cmake执行的是给定路径下的CMakeLists.txt,比如"."表示当前路径,".."表示当前目录的父目录。

CMakeLists.txt中指定项目的输入和输出:

输出:产生的可执行文件(或者库文件?)

输入:产生输出所依赖的源文件(以及库文件?)

CMakeLists.txt中通过cmake的语法编写相应代码语句,这些语句被cmake解释执行。进而产生makefile,用make去执行就完成编译。

cmake语法并不很复杂,往往翻看下cmake的官方手册就能知道某个变量、命令、标准的各种细节了。

cmake官方文档

遇到cmake指令看不懂,直接看文档,基本上解决问题。

在线文档

https://cmake.org/cmake/help/latest/

自行构建离线文档

实在是忍受不了查看文档时刷一个个网页一直出不来结果的情况。自己动手丰衣足食。如果你网络比较好,可以跳过这一节。

查看哪些apt包是cmake的文档:

aptitude search cmake

结果显示cmake-doc提供了文档,cmake-data则是另一种形式的文档。

安装cmake及其文档:

sudo apt install cmake cmake-doc cmake-data  #安装cmake文档
dpkg -L cmake-doc #查看cmake-doc包安装位置

发现是在/usr/share/doc/cmake-data目录,它的马甲目录(链接)是/usr/share/doc/cmake-doc,那就开启来好了:

cd /usr/share/doc/cmake-data/html
python -m SimpleHTTPServer 4002 #用python开一个本地http服务器

浏览器访问http://localhost:4002查看文档。

“另一种形式的文档”呢?在/usr/share/cmake-3.5/Help目录,是.rst格式文档,要用sphinx编译:

sudo pip install sphinx   #先确保装了pip
cd /usr/share/cmake-3.5/Help
sudo sphinx-quickstart #按照提示来,唯一需要注意的是autogen选择y。这一步生成makefile
cd _build
sudo make html #编译生成html
cd html
python -m SimpleHTTPServer 4003

可以把上述开启文档的http服务器命令用tmux开启。

查询某个命令http://10.10.10.53:4003/command/

查询某个变量http://10.10.10.53:4003/variable/

查询某个手册http://10.10.10.53:4003/manual/

查询某个模块http://10.10.10.53:4003/module/

查询发行日志http://10.10.10.53:4003/release/

**查询 policy **:http://10.10.10.53:4003/policy/ 包含了各种cmake规范

find_package()的用法

先吐个槽

本来,直接查看手册中find_package()一节即可。

鉴于现有一些博客对于find_package()这条命令介绍不够好,比如这篇内容陈旧、不全面;比如这篇纯粹是官方文档翻译,而官方文档不够突出重点,所以再罗嗦一小节的内容。

平时用cmake,遇到问题最多就是这个find_package()命令的使用导致的。最常见于寻找opencv包的情况。

这里喷一下opencv:要想用opencv各种特性,就要自行把opencv_contrib编译进去。编译时候还会出现各种3rdparty的包从github上无法下载要手动解决的问题,不方便。

find_package()是如何工作的

find_package()

先从CMAKE_MODULE_PATH变量表示的路径下去找Find<name>.cmake文件;

如果失败,则在CMAKE安装目录/share/cmake-x.y/Modules目录下查找Find<name>.cmake文件

如果上一步失败,则查找<Name>Config.cmake或者<lower-case-name>-config.cmake文件。按8大顺序查找你想要的包,如果前一个里面找到了就不去后面的找,还可以通过变量关闭某个查找顺序项

比如现在要找opencv的包。那么它的查找顺序是(都是在寻找<Name>Config.cmake或者<lower-case-name>-config.cmake):

  1. CMAKE_PREFIX_PATH变量所表示的路径下寻找。

    换言之,CMAKE_PREFIX_PATH有最高的查找优先级。

    find_package()参数列表中填写NO_CMAKE_PATH则跳过该查找项。

  2. 在cmake特有的环境变量中查找。包括:

<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH

对于OpenCV,就是OpenCV_DIR了。

find_package()参数列表中填写NO_CMAKE_ENVIRONMENT_PATH跳过该查找项。

  1. find_package()的HINTS参数指定

  2. 系统环境变量PATH里寻找。

    find_package()参数列表中填写NO_SYSTEM_ENVIRONMENT_PATH跳过该查找项。

  3. 搜索在CMake GUI中最新配置过的工程的构建树。在find_package()参数列表中填写NO_CMAKE_BUILDS_PATH跳过该查找项。

  4. 搜索存储在CMake用户包注册表(User Package Registry)中的路径。

    find_package()参数列表中填写NO_CMAKE_PACKAGE_REGISTRY或者设定CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY变量值为TRUE跳过该查找项。(似乎Linux下没啥用!)

    (update@2018-07-31 00:47:33 今天被这个User Package Registry坑惨了!具体实例和解决方法看SO上的一个问答:how-to-avoid-cmake-to-read-in-its-system-cache-home-cmake。简单说,Caffe的cmake脚本中有一句export Caffe,这会向User Package Registry写东西,在ubuntu下的表现就是在/.cmake/package/Caffe路径下写入一个文件,文件名字是一个hash值,文件内容是cmake编译的caffe的路径。一旦有多个版本的caffe存在并且都用了cmake编译,而如果前面15的设置路径有错误,那么就加载这个~/.cmake/package/Caffe/xxx文件中的路径。很坑!)

  5. 搜索在当前系统的平台文件中定义的cmake变量:

CMAKE_SYSTEM_PREFIX_PATH
CMAKE_SYSTEM_FRAMEWORK_PATH
CMAKE_SYSTEM_APPBUNDLE_PATH

find_package()参数列表中填写NO_CMAKE_SYSTEM_PATH选项跳过这些路径。

注意 这里测试发现,CMAKE_SYSTEM_PREFIX_PATH/usr/local;/usr;/;/usr;/usr/local,如果前面的查找顺序项都失败或者被关闭了,那么在这一查找项上,会在/usr/local这样的路径下,查找opencv开头的目录,比如/usr/local/opencv-git-master会被找到;而假如我把opencv的路径换成不以opencv开头,比如/usr/local/what-opencv则不能找到opencv。

  1. find_package()参数列表中用PATHS指定搜索路径。这些路径一般是硬编码的参考路径。。。。(太长而且个人觉得没啥用,想看的去找手册好了)

写了这么多查找顺序,其实就记住一个好了,先设定定CMAKE_PREFIX_PATH变量,再用find_package()去找包,保证万事大吉:

list(APPEND CMAKE_PREFIX_PATH "/opt/opencv-git-master") #引号里是我的opencv安装路径
find_package(OpenCV)

成功查找到包后,产生这些变量吗?

按照cmake手册的说法,find_package()执行后会产生几个变量:

_FOUND

_INCLUDE_DIRS 或者 _INCLUDES

_LIBRARIES 或者 _LIBS

_DEFINITIONS


但尝试找opencv的包时,无论是apt装的opencv还是自行编译的opencv,都是一样:并非这几个变量都有值:

CMAKE_MODULE_PATH is:

-- Found OpenCV: /usr/local/opencv-git-master (found version "3.2.0")

OpenCV_FOUND is : 1

OpenCV_INCLUDE_DIRS is : /usr/local/opencv-git-master/include;/usr/local/opencv-git-master/include/opencv

OpenCV_INCLUDES is :

OpenCV_LIBRARIES is opencv_calib3d;opencv_core;opencv_features2d;opencv_flann;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_shape;opencv_stitching;opencv_superres;opencv_video;opencv_videoio;opencv_videostab;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_datasets;opencv_dnn;opencv_dnn_modern;opencv_dpm;opencv_face;opencv_freetype;opencv_fuzzy;opencv_hdf;opencv_line_descriptor;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_reg;opencv_rgbd;opencv_saliency;opencv_stereo;opencv_structured_light;opencv_surface_matching;opencv_text;opencv_tracking;opencv_xfeatures2d;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto

OpenCV_LIBS is : opencv_calib3d;opencv_core;opencv_features2d;opencv_flann;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_shape;opencv_stitching;opencv_superres;opencv_video;opencv_videoio;opencv_videostab;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_datasets;opencv_dnn;opencv_dnn_modern;opencv_dpm;opencv_face;opencv_freetype;opencv_fuzzy;opencv_hdf;opencv_line_descriptor;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_reg;opencv_rgbd;opencv_saliency;opencv_stereo;opencv_structured_light;opencv_surface_matching;opencv_text;opencv_tracking;opencv_xfeatures2d;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto

OpenCV_DEFINITIONS is :


## 引用第三方库
比如读取jpeg图像,并转化到Lab空间以及灰度图像。使用到opencv库,利用`find_package()`进行查找。代码如下: **main.cc**
```c++
#include <iostream>
#include <opencv2/opencv.hpp> using cv::Mat;
using cv::imread;
using cv::imshow;
using cv::waitKey;
using cv::cvtColor;
using cv::COLOR_BGR2Lab;
using cv::COLOR_BGR2GRAY; int main(){
// Load image
Mat srcImage = imread("cat.jpg", -1);
Mat dstImage; imshow("RGB Space", srcImage); // Convert to other color space
cvtColor(srcImage, dstImage, COLOR_BGR2Lab);
imshow("Lab Space", dstImage); cvtColor(srcImage, dstImage, COLOR_BGR2GRAY);
imshow("Gray Scale", dstImage); waitKey(); return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.2)

project(hello-cmake)

list(APPEND CMAKE_PREFIX_PATH "/usr/share/OpenCV")  # apt装的opencv
#list(APPEND CMAKE_PREFIX_PATH "/usr/local/opencv-git-master") #自行编译的opencv
message("CMAKE_MODULE_PATH is: ${CMAKE_MODULE_PATH}")
find_package(OpenCV
#NO_CMAKE_PATH
#NO_CMAKE_ENVIRONMENT_PATH
#NO_SYSTEM_ENVIRONMENT_PATH
#NO_CMAKE_PACKAGE_REGISTRY
#NO_CMAKE_SYSTEM_PATH
)
message("OpenCV_FOUND is : ${OpenCV_FOUND}")
message("OpenCV_INCLUDE_DIRS is : ${OpenCV_INCLUDE_DIRS}")
message("OpenCV_INCLUDES is : ${OpenCV_INCLUDES}")
message("OpenCV_LIBRARIES is ${OpenCV_LIBRARIES}")
message("OpenCV_LIBS is : ${OpenCV_LIBS}")
message("OpenCV_DEFINITIONS is : ${OpenCV_DEFINITIONS}") add_executable(hello main.cc) target_link_libraries(hello ${OpenCV_LIBS})

build.sh

#!/bin/bash

set -x
set -e LOG="log.build"
touch $LOG
rm $LOG exec &> >(tee -a "$LOG") echo "Logging to $LOG" BUILD_ROOT=build
if [ -d $BUILD_ROOT ]; then
rm -rf $BUILD_ROOT
fi mkdir -p $BUILD_ROOT
cd $BUILD_ROOT echo "building root folder is $BUILD_ROOT" echo "Now do cmake"
cmake .. make -j8 echo "Done"

编写自己的库

利用add_library()生成库文件。

main.cc

#include <iostream>
using namespace std; void smile(){
cout << "Nice smile" << endl;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.2)

message("BUILD_SHARED_LIBS is ${BUILD_SHARED_LIBS}")
#set(BUILD_SHARED_LIBS ON) # 设定BUILD_SHARED_LIBS来表示add_library构建共享库(shared)还是静态库(static)
message("BUILD_SHARED_LIBS is ${BUILD_SHARED_LIBS}") add_library(smile STATIC main.cc) #不过,add_library()显示地设定SHARED和STATIC,更直观

build.sh

其实每次我的build.sh都是一样的:)

#!/bin/bash

set -x
set -e LOG="log.build"
touch $LOG
rm $LOG exec &> >(tee -a "$LOG") echo "Logging to $LOG" BUILD_ROOT=build
if [ -d $BUILD_ROOT ]; then
rm -rf $BUILD_ROOT
fi mkdir -p $BUILD_ROOT
cd $BUILD_ROOT echo "building root folder is $BUILD_ROOT" echo "Now do cmake"
cmake .. make -j8 echo "Done"

现在,自己的库写好了,怎么用呢?一种方法是make install,另一种方法是提供配置文件,比如mylibrary-config.cmake这种,后者需要配合.cmake.in文件进行生成,可以参考官方wiki:https://cmake.org/Wiki/CMake/Tutorials/How_to_create_a_ProjectConfig.cmake_file

===================

2018年8月16日 20点46分

这里插播一个实际遇到的情况,挺有意思,领教了CMAKE_CXX_COMPILER变量的厉害(采坑)

小伙伴的ubuntu上要编译Caffe,官方源码下载后用CMake构建,到95%左右,convert_mnist_siamse_data.o这里会报错,说DSO Missing,具体指向的是libcstdc++.

开始时百思不得其解,因为查看g++和cmake,以及protobuf什么的,都是apt装的或者系统自带的,为啥缺库呢。

后来有人指出是链接阶段没有链接libstdc++.so.6。但是为啥要明确链接它?

我的Debug方法:利用message( )函数(相当于C/C++里的printf( ))暴力输出各种链接库的名字,还是不能发现问题,逐步溯源到CMake的输出,发现CMAKE_CXX_COMPILER这个变量的取值出了问题。

CMAKE_CXX_COMPILER

CXX这个环境变量被设定了,设定的值为/usr/bin/gcc-5

CMake会读取这个$CXX 然后设定CMAKE_CXX_COMPILER为这个值,也就是用gcc-5替代了g++

所以后续编译的话都缺少stdc++这个库

在终端里,unset CXX,或者把你的bashrc/zshrc里面的export CXX=/usr/bin/gcc-5注释掉并退出重新进入shell,就可以正常使用CMAKE_CXX_COMPILER这一变量来编译Caffe了。

cmake变量

这篇写的还可以:https://chaopei.github.io/blog/2018/10/cmake-variable.html

这篇更详细一些:https://riptutorial.com/zh-CN/cmake/example/11821/变量和全局变量缓存

如果希望cmake -Dvar=value的方式,临时设定变量的值,则必须用set(VAR "some value" CACHE STRING "ignore this" [FORCE])的方式

cmake简明使用指南的更多相关文章

  1. cmake编译opencv指南

    目录 cmake编译opencv指南 用包管理器安装 查看opencv相关的包 执行安装 编译安装 为什么编译安装 下载源码 编译脚本 执行编译脚本.解决3rdparty下载 编译后的设定-环境变量 ...

  2. Ubuntu16.04+Tensorflow+CUDA9.0+cuDNN7.0 环境简明搭建指南

    最近在研究风格化得内容,发现搭建环境实在是很头疼的事情,虽然网上已经有各路大神总结整理好了很多搭建指南,各种问题的解决方案都已经罗列出来供大家参考.然后参考终究是参考,真正自己上手,发现仍旧是各种坑, ...

  3. 初创互联网公司简明创业指南 - YC新掌门Sam Altman

    本文只是一个创业指南的简明版 - 更详细的版本请查看:http://startupclass.samaltman.com 创业之前,你更应该去拥有一个好的创意,而不是一个公司.如果开始前你拥有一个好的 ...

  4. Git简明使用指南[转]

    git - 简易指南 助你开始使用 git 的简易指南,木有高深内容,;). Tweet 作者:罗杰·杜德勒 感谢:@tfnico, @fhd and Namics 其他语言 english, deu ...

  5. <简明>Markdown指南

    什么是Markdown?Markdown是一种轻量级的「标记语言」,通常为程序员群体所用,目前它已是全球最大的技术分享网站 GitHub 和技术问答网站 StackOverFlow 的御用书写格式. ...

  6. 【软件工具】easyExcel简明使用指南

    easyExcel简介 Java领域解析.生成Excel比较有名的框架有Apache poi.jxl等.但他们都存在一个严重的问题就是非常的耗内存.如果你的系统并发量不发的话可能还行,但是一旦并发上来 ...

  7. 【开发工具】IDEA简明使用指南

    目录 1. 搭建idea的开发环境 2. 调试技巧 3. 常用快捷键(小技巧) 4. 插件推荐 工欲善其事,必先利其器.在Java开发中挑选一款好的Ide环境能大大提升我们的开发效率,IntelliJ ...

  8. Linux下CMake简明教程

    转载地址:https://blog.csdn.net/whahu1989/article/details/82078563 CMake是开源.跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本 ...

  9. C语言简明数据类型指南

    一.常用的数据类型 char:字符在计算机的存储器中以字符编码的形式保存,字符编码是一个数字,因此在计算机看来,A与数字65完全一样(65是A的ASCII码). int:如果要保存一个整数,通常可以使 ...

随机推荐

  1. elasticsearch中head插件中的定制增加用户名密码范例

    在head插件目录下一般 在 elasticsearch目录下的 plugins\head目录 下 在 或 plugins\head\site目录下 有 一个index.html文件.把这个文件用下面 ...

  2. 我眼中的Adaboost

    步骤: def buildStump(dataArr,classLabels,D): 1.循环取出数据集中的一个特征(一列)输入 (for:) 2.循环调整阀值threshVal  (for:) 3, ...

  3. 分析web.xml

    <?xml version="1.0" encoding="UTF-8"?>  //xml的版本:1.0 和 编码:utf-8 <web-ap ...

  4. 制作OpenStack使用的windows镜像

    1 安装vmware14 2 创建ubuntu-desktop-16.04虚拟机 选择自定义安装 选择ubuntu-16.04-desktop.iso 内存要大于2G,推荐4G. 磁盘要大于50G 关 ...

  5. JavaScript数据类型检测 数组(Array)检测方式

    前言 对于确定某个对象是不是数组,一直是数组的一个经典问题.本文专门将该问题择出来,介绍什么才是正确的javascript数组检测方式 typeof 首先,使用最常用的类型检测工具--typeof运算 ...

  6. uCosII中的任务

    任务基本概念 任务是一个接受操作系统管理的独立运行单元,在uCosII中类似与普通平台上的main()函数,需要自己来保护其因调用或中断二产生的断点,所以需要一个自己的私有堆栈,即任务堆栈: 任务有两 ...

  7. JGUI源码:Tab组件实现(9)

    程序界面效果如下 Tab组件由多个TabItem组成,超出部分隐藏,可以通过左右按钮滑动显示出来 1.封装 // 初始化内容 $(function () { J.JTab($(".jgui- ...

  8. jmeter中的参数化

    1.那些场景需要参数化? 1.登陆认证信息 2.一些和时间相关的,违反时间约束的[时间点和当前时间不一致的情况等等] 3.一些受其他字段约束的[例如字段的一些限制条件] 4.一些来自于其他数据源[例如 ...

  9. Koa与Node.js开发实战(2)——使用Koa中间件获取响应时间(视频演示)

    学习架构: 在实战项目中,经常需要记录下服务器的响应时间,也就是从服务器接收到HTTP请求,到最终返回给客户端之间所耗时长.在Koa应用中,利用中间件机制可以很方便的实现这一功能.代码如下所示: 01 ...

  10. 最短路径(Dijkstra算法)

    算法局限性:边的权值不能为负. 需要两个辅助数组dist[],path[],分别记录起点到各点的最短距离和最短路径 算法步骤: 1.根据起点v0初始化dist[]和path[]数组. 2.在剩下的点中 ...