Caffe: Could not find PROTOBUF Compiler(Profobuf 3.0 above)

在用cmake生成Caffe工程文件的时候,如果你使用Protobuf 3.0以上的版本,cmake可能会产生如下的报错:

CMake Error at cmake/ProtoBuf.cmake:18 (message): Could not find PROTOBUF Compiler Call Stack (most recent call first): cmake/Dependencies.cmake:48 (include) CMakeLists.txt:81 (include)

解决办法

通过设置protobuf_MODULE_COMPATIBLE=on指定打开Protobuf的兼容模式。 注意区分大小写

设置protobuf_MODULE_COMPATIBLE=on也有两种办法:

命令行添加

cmake生成Makefile时命令行添加-Dprotobuf_MODULE_COMPATIBLE=on,指定打开Protobuf兼容模式,类似下面的命令行:

d:\caffe> cmake -G "Visual Studio 12 2013 Win64"  . -Dprotobuf_MODULE_COMPATIBLE=on 

这个办法的好处是不用修改caffe的代码

修改CMakeLists.txt

也可以在直接修改Caffe根目录下的CMakeLists.txt 打开CMakeLists.txt,查找是否有类型下面这行代码

caffe_option(protobuf_MODULE_COMPATIBLE "Make the protobuf-config.cmake compatible with the module mode" ON IF MSVC)

如果有,直接把后面的 IF MSVC删除,强制将protobuf_MODULE_COMPATIBLE 置为ON。

如果没有,就在# ---[ Options后面添加一行,下面三种写法任选一行就可以

# 写法1
caffe_option(protobuf_MODULE_COMPATIBLE "Make the protobuf-config.cmake compatible with the module mode" ON)
# 写法2
set (protobuf_MODULE_COMPATIBLE on CACHE BOOL "CMake build-in FindProtobuf.cmake module compatible" )
# 写法3
option(protobuf_MODULE_COMPATIBLE "CMake build-in FindProtobuf.cmake module compatible" ON)

“”包含的字符串只是描述信息,内容是什么不重要

问题溯源

产生这个问题的根本原因是Protobuf3.0以后的版本的cmake脚本默认不向下兼容。需要设置protobuf_MODULE_COMPATIBLE=on开启兼容模式。 进一步我们分析caffe_folder/cmake/ProtuBuf.cmake分析,如下代码,就能看到”Could not find PROTOBUF Compiler”这个错误信息的输出位置:

find_package( Protobuf REQUIRED NO_MODULE)
set(PROTOBUF_INCLUDE_DIR ${PROTOBUF_INCLUDE_DIRS})
list(APPEND Caffe_INCLUDE_DIRS PUBLIC ${PROTOBUF_INCLUDE_DIR})
list(APPEND Caffe_LINKER_LIBS PUBLIC ${PROTOBUF_LIBRARIES})


# As of Ubuntu 14.04 protoc is no longer a part of libprotobuf-dev package
# and should be installed separately as in: sudo apt-get install protobuf-compiler
if(EXISTS ${PROTOBUF_PROTOC_EXECUTABLE})
  message(STATUS "Found PROTOBUF Compiler: ${PROTOBUF_PROTOC_EXECUTABLE}")
else()
  # 没有找到 protoc(.exe)可执行文件,就报错
  message(FATAL_ERROR "Could not find PROTOBUF Compiler")
endif()

为什么PROTOBUF_PROTOC_EXECUTABLE会没有定义呢? 进一步我们追踪到protobuf_installation/cmake/protobuf-config.cmake,就能找到protobuf_MODULE_COMPATIBLE这个变量真正起作用的位置(protobuf_installation是你的ProtuBuf安装的位置):

# User options
include("${CMAKE_CURRENT_LIST_DIR}/protobuf-options.cmake")

# Depend packages


# Imported targets
include("${CMAKE_CURRENT_LIST_DIR}/protobuf-targets.cmake")

# CMake FindProtobuf module compatible file
if(protobuf_MODULE_COMPATIBLE)
  # 加载 兼容旧版本的脚本,生成MODULE模式下的变量PROTOBUF_INCLUDE_DIRS PROTOBUF_LIBRARIES...等等
  # 参见 https://cmake.org/cmake/help/v3.8/module/FindProtobuf.html
  # 也就是protobuf-module.cmake 这个脚本才会定义 Protobuf_PROTOC_EXECUTABLE 这个变量
  include("${CMAKE_CURRENT_LIST_DIR}/protobuf-module.cmake")
endif()

延伸阅读 : Imported Target

那么你也许会问,如果不设置protobuf_MODULE_COMPATIBLE=on要如何使用ProtoBuf 3.0的库呢? Protobuf 3.0以后的版本采用imported target这种新的形式来为应用软件提供library和include dir. 以libprotobuf-lite库为例说明, 打开protobuf_installation/cmake/protobuf-targets.cmake,你会发现文件中有如下的代码

add_library(protobuf::libprotobuf-lite STATIC IMPORTED)
set_target_properties(protobuf::libprotobuf-lite PROPERTIES
  # 指定 include 文件夹
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
)

打开protobuf_installation/cmake/protobuf-targets-release.cmake,进一步还能找到如下的代码

# Import target "protobuf::libprotobuf-lite" for configuration "release"
set_property(TARGET protobuf::libprotobuf-lite APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(protobuf::libprotobuf-lite PROPERTIES
  IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX"
  # 指定 library 的位置
  IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libprotobuf-lite.lib"
  )

这两段代码定义了一个IMPORTED 类型的target,名字叫 protobuf::libprotobuf-lite,target的属性中定义了include文件夹的位置以及库的位置。

那么应用程序要使用libprotobuf-lite库,只需像以前一样调用 target_link_libraries将protobuf::libprotobuf-lite添加 到依赖库列表中就可以了。

target_link_libraries( your_target,protobuf::libprotobuf-lite)

也许你会问那还需要调用include_directories添加protobuf的include_dir么? 不需要了,your_target指定连接一个imported target时,会自动把imported target的INTERFACE_INCLUDE_DIRECTORIES 属性指定的include文件夹加到your_target的include文件夹列表中的。

关于imported-target的详细说明,参见 imported-targets

参考资料

《Using find_package(Protobuf) with 3.0.0》 《imported-targets》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏wOw的Android小站

[Android][Framework] 从一个小问题了解STK加载内容的方式

这个界面从哪来的? 实际上,我们插入SIM卡,手机就会显示SimToolKit,打开就能看到一些和运营商相关的菜单。换了不同的卡菜单也会变。所以大概可以猜到,S...

391
来自专栏JMCui

SpringBoot 之基础学习篇.

    SpringBoot 的关键词是“约定俗成”,它根据长久以来的 Spring 开发配置经验,整理出一套适用、普遍、大家都认可的配置方案。所以 Sprin...

873
来自专栏10km的专栏

mysql/jdbc:设置useInformationSchema=true读取表注释信息(table_comment)

问题描述 今天在读取表的注释信息(COMMENT)时,发现返回的REMARKS字段返回居然是null. 以下是代码示例: DatabaseMetaData...

2047
来自专栏码匠的流水账

spring security动态配置url权限

对于使用spring security来说,存在一种需求,就是动态去配置url的权限,即在运行时去配置url对应的访问角色。这里简单介绍一下。

642
来自专栏Java3y

从零开始写项目第一篇【搭建环境】

使用Maven搭建SSM环境 SSM需要的基础jar包有哪些??整理一下: c3p0数据连接池 springMVC的JSON springAOP springC...

38610
来自专栏Java成神之路

Java企业微信开发_09_身份验证之移动端网页授权(有完整项目源码)

在开始使用网页授权之前,需要先设置一下授权回调域。这里瞬间想到之前做JSSDK的时候,也设置过一个域名。二者本质上都是设置可信域名。

1162
来自专栏开发技术

从源码来理解slf4j的绑定,以及logback对配置文件的加载

  项目中的日志系统使用的是slf4j + logback。slf4j作为一个简单日志门面,为各种loging APIs(像java.util.logging,...

1254
来自专栏跟着阿笨一起玩NET

如何创建一个RESTful WCF Service

原创地址:http://www.cnblogs.com/jfzhu/p/4044813.html

411
来自专栏Jaycekon

Spring-Boot:6分钟掌握SpringBoot开发

 构建项目 从技术角度来看,我们要用Spring MVC来处理Web请求,用Thymeleaf来定义Web视图,用Spring Data JPA来把阅读列表持久...

3746
来自专栏Java Web

学生管理系统(SSM简易版)总结

之前用 Servlet + JSP 实现了一个简易版的学生管理系统,在学习了 SSM 框架之后,我们来对之前写过的项目重构一下! 技术准备 为了完成这个项目,...

5174

扫码关注云+社区