1. 程式人生 > >編譯caffe錯誤及方法總結

編譯caffe錯誤及方法總結

錯誤一
CXX src/caffe/util/hdf5.cpp
CXX src/caffe/util/im2col.cpp
In file included from src/caffe/util/signal_handler.cpp:7:0:
./include/caffe/util/signal_handler.h:4:34: fatal error: caffe/proto/caffe.pb.h: 沒有那個檔案或目錄
compilation terminated.
Makefile:563: recipe for target ‘.build_release/src/caffe/util/signal_handler.o’ failed
make: *

[.build_release/src/caffe/util/signal_handler.o] Error 1
make: * 正在等待未完成的任務….
CXX src/caffe/util/cudnn.cpp

解決一:重新make clean,再make all -j8

錯誤二:
CXX/LD -o .build_release/examples/cifar10/convert_cifar_data.bin
//home/jc/anaconda2/lib///home/jc/anaconda2/lib/libpng16.so.16:對‘[email protected]_1.2.9’未定義的引用
collect2: error: ld returned 1 exit status
libpng16.so.16:對‘

[email protected]:607: recipe for target ‘.build_release/tools/upgrade_net_proto_binary.bin’ failed
make: * [.build_release/tools/upgrade_net_proto_binary.bin] Error 1
make: * 正在等待未完成的任務….
ZLIB_1.2.9’未定義的引用
collect2: error: ld returned 1 exit status
Makefile:607: recipe for target ‘.build_release/tools/upgrade_solver_proto_text.bin’ failed
make: *
[.build_release/tools/upgrade_solver_proto_text.bin] Error 1
//home/jc/anaconda2/lib/libpng16.so.16:對‘[email protected]_1.2.9’未定義的引用
collect2: error: ld returned 1 exit status
Makefile:607: recipe for target ‘.build_release/tools/compute_image_mean.bin’ failed
make: * [.build_release/tools/compute_image_mean.bin] Error 1
//home/jc/anaconda2/lib/libpng16.so.16:對‘[email protected]_1.2.9’未定義的引用
collect2: error: ld returned 1 exit status
Makefile:612: recipe for target ‘.build_release/examples/cifar10/convert_cifar_data.bin’ failed
make: * [.build_release/examples/cifar10/convert_cifar_data.bin] Error 1
//home/jc/anaconda2/lib/libpng16.so.16:對‘[email protected]_1.2.9’未定義的引用
collect2: error: ld returned 1 exit status
Makefile:607: recipe for target ‘.build_release/tools/caffe.bin’ failed
make: * [.build_release/tools/caffe.bin] Error 1
//home/jc/anaconda2/lib/libpng16.so.16:對‘[email protected]_1.2.9’未定義的引用
collect2: error: ld returned 1 exit status
Makefile:607: recipe for target ‘.build_release/tools/extract_features.bin’ failed
make: * [.build_release/tools/extract_features.bin] Error 1
//home/jc/anaconda2/lib/libpng16.so.16:對‘[email protected]_1.2.9’未定義的引用
collect2: error: ld returned 1 exit status
Makefile:607: recipe for target ‘.build_release/tools/upgrade_net_proto_text.bin’ failed
make: * [.build_release/tools/upgrade_net_proto_text.bin] Error 1
//home/jc/anaconda2/lib/libpng16.so.16:對‘[email protected]_1.2.9’未定義的引用
collect2: error: ld returned 1 exit status
Makefile:607: recipe for target ‘.build_release/tools/convert_imageset.bin’ failed
make: * [.build_release/tools/convert_imageset.bin] Error 1
解決二:
正確解決方法:
在 Makefile.config 中,加入下一句
LINKFLAGS := -Wl,-rpath,$(HOME)/anaconda2/lib
問題三:
make runtest出現問題:

    Warning! ***HDF5 library version mismatched error***  
    The HDF5 header files used to compile this application do not match  
    the version used by the HDF5 library to which this application is linked.  
    Data corruption or segmentation faults may occur if the application continues.  
    This can happen when an application was compiled by one version of HDF5 but  
    linked with a different version of static or shared HDF5 library.  
    You should recompile the application or check your shared library related  
    settings such as 'LD_LIBRARY_PATH'.  
    You can, at your own risk, disable this warning by setting the environment  
    variable 'HDF5_DISABLE_VERSION_CHECK' to a value of '1'.  
    Setting it to 2 or higher will suppress the warning messages totally.  
    Headers are 1.8.17, library is 1.10.1  
        SUMMARY OF THE HDF5 CONFIGURATION  
        =================================  

    General Information:  
    -------------------  
                       HDF5 Version: 1.10.1  
                      Configured on: Wed May 10 20:46:51 BST 2017  
                      Configured by: [email protected].local  
                        Host system: x86_64-apple-darwin16.5.0  
                  Uname information: Darwin Sierra.local 16.5.0 Darwin Kernel Version 16.5.0: Fri Mar 3 16:52:33 PST 2017; root:xnu-3789.51.2~3/RELEASE_X86_64 x86_64  
                           Byte sex: little-endian  
                 Installation point: /usr/local/Cellar/hdf5/1.10.1  

    Compiling Options:  
    ------------------  
                         Build Mode: production  
                  Debugging Symbols: no  
                            Asserts: no  
                          Profiling: no  
                 Optimization Level: high  

    Linking Options:  
    ----------------  
                          Libraries: static, shared  
      Statically Linked Executables:   
                            LDFLAGS:   
                         H5_LDFLAGS:   
                         AM_LDFLAGS: -L/usr/lib -L/usr/local/opt/szip/lib  
                    Extra libraries: -lsz -lz -ldl -lm   
                           Archiver: ar  
                             Ranlib: ranlib  

    Languages:  
    ----------  
                                  C: yes  
                         C Compiler: /usr/local/Homebrew/Library/Homebrew/shims/super/clang ( Apple LLVM version 8.1.0 )  
                           CPPFLAGS:   
                        H5_CPPFLAGS:   -DNDEBUG -UH5_DEBUG_API  
                        AM_CPPFLAGS: -I/usr/include -I/usr/local/opt/szip/include  
                            C Flags:   
                         H5 C Flags:       
                         AM C Flags:   
                   Shared C Library: yes  
                   Static C Library: yes  


                            Fortran: no  

                                C++: yes  
                       C++ Compiler: /usr/local/Homebrew/Library/Homebrew/shims/super/clang++ ( Apple LLVM version 8.1.0 )  
                          C++ Flags:   
                       H5 C++ Flags:      
                       AM C++ Flags:   
                 Shared C++ Library: yes  
                 Static C++ Library: yes  

                               Java: no  


    Features:  
    ---------  
                      Parallel HDF5: no  
                 High-level library: yes  
                       Threadsafety: no  
                Default API mapping: v110  
     With deprecated public symbols: yes  
             I/O filters (external): deflate(zlib),szip(encoder)  
                                MPE: no  
                         Direct VFD: no  
                            dmalloc: no  
     Packages w/ extra debug output: none  
                        API tracing: no  
               Using memory checker: no  
    Memory allocation sanity checks: no  
                Metadata trace file: no  
             Function stack tracing: no  
          Strict file format checks: no  
       Optimization instrumentation: no  
    Bye...  
    *** Aborted at 1499695537 (unix time) try "date -d @1499695537" if you are using GNU date ***  
    PC: @     0x7fff8cab1d42 __pthread_kill  
    *** SIGABRT (@0x7fff8cab1d42) received by PID 48362 (TID 0x7fff9589d3c0) stack trace: ***  
        @     0x7fff8cb92b3a _sigtramp  
        @        0x100000001 (unknown)  
        @     0x7fff8ca17420 abort  
        @        0x10a008f61 H5check_version  
        @        0x10ab096de caffe::HDF5DataLayer<>::LoadHDF5FileData()  
        @        0x10ab08a4c caffe::HDF5DataLayer<>::LayerSetUp()  
        @        0x10ab65a97 caffe::Net<>::Init()  
        @        0x10ab647fe caffe::Net<>::Net()  
        @        0x10ab7c1fa caffe::Solver<>::InitTrainNet()  
        @        0x10ab7b5d1 caffe::Solver<>::Init()  
        @        0x10ab7b2d5 caffe::Solver<>::Solver()  
        @        0x1096e4596 caffe::SGDSolver<>::SGDSolver()  
        @        0x1096f2f3b caffe::NesterovSolverTest<>::InitSolver()  
        @        0x1096df96a caffe::GradientBasedSolverTest<>::InitSolverFromProtoString()  
        @        0x1096e0568 caffe::GradientBasedSolverTest<>::RunLeastSquaresSolver()  
        @        0x1096dfdf5 caffe::GradientBasedSolverTest<>::TestLeastSquaresUpdate()  
        @        0x10989ebe7 testing::internal::HandleExceptionsInMethodIfSupported<>()  
        @        0x10989ea4a testing::Test::Run()  
        @        0x10989fbbe testing::TestInfo::Run()  
        @        0x1098a04b7 testing::TestCase::Run()  
        @        0x1098a60b7 testing::internal::UnitTestImpl::RunAllTests()  
        @        0x1098a5b93 testing::internal::HandleExceptionsInMethodIfSupported<>()  
        @        0x1098a5af9 testing::UnitTest::Run()  
        @        0x1095d1fc5 main  
        @     0x7fff8c983235 start  
    make: *** [runtest] Abort trap: 6  

問題四:
import caffe出錯:

import caffe
Traceback (most recent call last):
File “”, line 1, in
File “/home/jc/caffe-master/python/caffe/init.py”, line 1, in
from .pycaffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver, NCCL, Timer
File “/home/jc/caffe-master/python/caffe/pycaffe.py”, line 13, in
from ._caffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, \
ImportError: No module named _caffe
解決:
安裝caffe時make pycaffe出現問題,重新make pycaffe
問題五:
import caffe時出現錯誤:importError:No module named cv2.
解決/:
pip install opencv-python
問題六:
Traceback (most recent call last):
File “”, line 1, in
File “/home/jc/caffe-master/python/caffe/init.py”, line 1, in
from .pycaffe import Net, SGDSolver, NesterovSolver, AdaGradSolver, RMSPropSolver, AdaDeltaSolver, AdamSolver, NCCL, Timer
File “/home/jc/caffe-master/python/caffe/pycaffe.py”, line 15, in
import caffe.io
File “/home/jc/caffe-master/python/caffe/io.py”, line 8, in
from caffe.proto import caffe_pb2
File “/home/jc/caffe-master/python/caffe/proto/caffe_pb2.py”, line 6, in
from google.protobuf.internal import enum_type_wrapper
ImportError: No module named google.protobuf.internal
解決:
https://blog.csdn.net/wuzuyu365/article/details/52431062

上我的makefile.config和makefile
makefile.config

## Refer to http://caffe.berkeleyvision.org/installation.html
# Contributions simplifying and improving our build system are welcome!

# cuDNN acceleration switch (uncomment to build with cuDNN).
USE_CUDNN := 1

# CPU-only switch (uncomment to build without GPU support).
# CPU_ONLY := 1

# uncomment to disable IO dependencies and corresponding data layers
USE_OPENCV := 1
# USE_LEVELDB := 0
# USE_LMDB := 0

# uncomment to allow MDB_NOLOCK when reading LMDB files (only if necessary)
#   You should not set this flag if you will be reading LMDBs with any
#   possibility of simultaneous read and write
# ALLOW_LMDB_NOLOCK := 1

# Uncomment if you're using OpenCV 3
OPENCV_VERSION := 3

# To customize your choice of compiler, uncomment and set the following.
# N.B. the default for Linux is g++ and the default for OSX is clang++
# CUSTOM_CXX := g++

# CUDA directory contains bin/ and lib/ directories that we need.
CUDA_DIR := /usr/local/cuda
# On Ubuntu 14.04, if cuda tools are installed via
# "sudo apt-get install nvidia-cuda-toolkit" then use this instead:
# CUDA_DIR := /usr

# CUDA architecture setting: going with all of them.
# For CUDA < 6.0, comment the *_50 lines for compatibility.
CUDA_ARCH := -gencode arch=compute_61,code=sm_61 \
        -gencode arch=compute_61,code=compute_61

# BLAS choice:
# atlas for ATLAS (default)
# mkl for MKL
# open for OpenBlas
BLAS := atlas
# Custom (MKL/ATLAS/OpenBLAS) include and lib directories.
# Leave commented to accept the defaults for your choice of BLAS
# (which should work)!
# BLAS_INCLUDE := /path/to/your/blas
# BLAS_LIB := /path/to/your/blas

# Homebrew puts openblas in a directory that is not on the standard search path
# BLAS_INCLUDE := $(shell brew --prefix openblas)/include
# BLAS_LIB := $(shell brew --prefix openblas)/lib

# This is required only if you will compile the matlab interface.
# MATLAB directory should contain the mex binary in /bin.
# MATLAB_DIR := /usr/local
# MATLAB_DIR := /Applications/MATLAB_R2012b.app

# NOTE: this is required only if you will compile the python interface.
# We need to be able to find Python.h and numpy/arrayobject.h.
# PYTHON_INCLUDE := /usr/include/python2.7 \
        # /usr/lib/python2.7/dist-packages/numpy/core/include
# Anaconda Python distribution is quite popular. Include path:
# Verify anaconda location, sometimes it's in root.
ANACONDA_HOME := $(HOME)/anaconda2
PYTHON_INCLUDE := $(ANACONDA_HOME)/include \
          $(ANACONDA_HOME)/include/python2.7 \
          $(ANACONDA_HOME)/lib/python2.7/site-packages/numpy/core/include

# Uncomment to use Python 3 (default is Python 2)
# PYTHON_LIBRARIES := boost_python3 python3.5m
# PYTHON_INCLUDE := /usr/include/python3.5m \
#                 /usr/lib/python3.5/dist-packages/numpy/core/include

# We need to be able to find libpythonX.X.so or .dylib.
# PYTHON_LIB := /usr/lib
PYTHON_LIB := $(ANACONDA_HOME)/lib

# Homebrew installs numpy in a non standard path (keg only)
# PYTHON_INCLUDE += $(dir $(shell python -c 'import numpy.core; print(numpy.core.__file__)'))/include
# PYTHON_LIB += $(shell brew --prefix numpy)/lib

# Uncomment to support layers written in Python (will link against Python libs)
WITH_PYTHON_LAYER := 1

# Whatever else you find you need goes here.
INCLUDE_DIRS := $(PYTHON_INCLUDE) /usr/local/include /usr/include/hdf5/serial
LIBRARY_DIRS := $(PYTHON_LIB) /usr/local/lib /usr/lib

# If Homebrew is installed at a non standard location (for example your home directory) and you use it for general dependencies
# INCLUDE_DIRS += $(shell brew --prefix)/include
# LIBRARY_DIRS += $(shell brew --prefix)/lib

# Uncomment to use `pkg-config` to specify OpenCV library paths.
# (Usually not necessary -- OpenCV libraries are normally installed in one of the above $LIBRARY_DIRS.)
# USE_PKG_CONFIG := 1

BUILD_DIR := build
DISTRIBUTE_DIR := distribute

# Uncomment for debugging. Does not work on OSX due to https://github.com/BVLC/caffe/issues/171
# DEBUG := 1

# The ID of the GPU that 'make runtest' will use to run unit tests.
TEST_GPUID := 0

# enable pretty build (comment to see full commands)
Q ?= @
LINKFLAGS := -Wl,-rpath,$(HOME)/anaconda2/lib

makefile

PROJECT := caffe

CONFIG_FILE := Makefile.config
# Explicitly check for the config file, otherwise make -k will proceed anyway.
ifeq ($(wildcard $(CONFIG_FILE)),)
$(error $(CONFIG_FILE) not found. See $(CONFIG_FILE).example.)
endif
include $(CONFIG_FILE)

BUILD_DIR_LINK := $(BUILD_DIR)
ifeq ($(RELEASE_BUILD_DIR),)
    RELEASE_BUILD_DIR := .$(BUILD_DIR)_release
endif
ifeq ($(DEBUG_BUILD_DIR),)
    DEBUG_BUILD_DIR := .$(BUILD_DIR)_debug
endif

DEBUG ?= 0
ifeq ($(DEBUG), 1)
    BUILD_DIR := $(DEBUG_BUILD_DIR)
    OTHER_BUILD_DIR := $(RELEASE_BUILD_DIR)
else
    BUILD_DIR := $(RELEASE_BUILD_DIR)
    OTHER_BUILD_DIR := $(DEBUG_BUILD_DIR)
endif

# All of the directories containing code.
SRC_DIRS := $(shell find * -type d -exec bash -c "find {} -maxdepth 1 \
    \( -name '*.cpp' -o -name '*.proto' \) | grep -q ." \; -print)

# The target shared library name
LIBRARY_NAME := $(PROJECT)
LIB_BUILD_DIR := $(BUILD_DIR)/lib
STATIC_NAME := $(LIB_BUILD_DIR)/lib$(LIBRARY_NAME).a
DYNAMIC_VERSION_MAJOR       := 1
DYNAMIC_VERSION_MINOR       := 0
DYNAMIC_VERSION_REVISION    := 0-rc3
DYNAMIC_NAME_SHORT := lib$(LIBRARY_NAME).so
#DYNAMIC_SONAME_SHORT := $(DYNAMIC_NAME_SHORT).$(DYNAMIC_VERSION_MAJOR)
DYNAMIC_VERSIONED_NAME_SHORT := $(DYNAMIC_NAME_SHORT).$(DYNAMIC_VERSION_MAJOR).$(DYNAMIC_VERSION_MINOR).$(DYNAMIC_VERSION_REVISION)
DYNAMIC_NAME := $(LIB_BUILD_DIR)/$(DYNAMIC_VERSIONED_NAME_SHORT)
COMMON_FLAGS += -DCAFFE_VERSION=$(DYNAMIC_VERSION_MAJOR).$(DYNAMIC_VERSION_MINOR).$(DYNAMIC_VERSION_REVISION)

##############################
# Get all source files
##############################
# CXX_SRCS are the source files excluding the test ones.
CXX_SRCS := $(shell find src/$(PROJECT) ! -name "test_*.cpp" -name "*.cpp")
# CU_SRCS are the cuda source files
CU_SRCS := $(shell find src/$(PROJECT) ! -name "test_*.cu" -name "*.cu")
# TEST_SRCS are the test source files
TEST_MAIN_SRC := src/$(PROJECT)/test/test_caffe_main.cpp
TEST_SRCS := $(shell find src/$(PROJECT) -name "test_*.cpp")
TEST_SRCS := $(filter-out $(TEST_MAIN_SRC), $(TEST_SRCS))
TEST_CU_SRCS := $(shell find src/$(PROJECT) -name "test_*.cu")
GTEST_SRC := src/gtest/gtest-all.cpp
# TOOL_SRCS are the source files for the tool binaries
TOOL_SRCS := $(shell find tools -name "*.cpp")
# EXAMPLE_SRCS are the source files for the example binaries
EXAMPLE_SRCS := $(shell find examples -name "*.cpp")
# BUILD_INCLUDE_DIR contains any generated header files we want to include.
BUILD_INCLUDE_DIR := $(BUILD_DIR)/src
# PROTO_SRCS are the protocol buffer definitions
PROTO_SRC_DIR := src/$(PROJECT)/proto
PROTO_SRCS := $(wildcard $(PROTO_SRC_DIR)/*.proto)
# PROTO_BUILD_DIR will contain the .cc and obj files generated from
# PROTO_SRCS; PROTO_BUILD_INCLUDE_DIR will contain the .h header files
PROTO_BUILD_DIR := $(BUILD_DIR)/$(PROTO_SRC_DIR)
PROTO_BUILD_INCLUDE_DIR := $(BUILD_INCLUDE_DIR)/$(PROJECT)/proto
# NONGEN_CXX_SRCS includes all source/header files except those generated
# automatically (e.g., by proto).
NONGEN_CXX_SRCS := $(shell find \
    src/$(PROJECT) \
    include/$(PROJECT) \
    python/$(PROJECT) \
    matlab/+$(PROJECT)/private \
    examples \
    tools \
    -name "*.cpp" -or -name "*.hpp" -or -name "*.cu" -or -name "*.cuh")
LINT_SCRIPT := scripts/cpp_lint.py
LINT_OUTPUT_DIR := $(BUILD_DIR)/.lint
LINT_EXT := lint.txt
LINT_OUTPUTS := $(addsuffix .$(LINT_EXT), $(addprefix $(LINT_OUTPUT_DIR)/, $(NONGEN_CXX_SRCS)))
EMPTY_LINT_REPORT := $(BUILD_DIR)/.$(LINT_EXT)
NONEMPTY_LINT_REPORT := $(BUILD_DIR)/$(LINT_EXT)
# PY$(PROJECT)_SRC is the python wrapper for $(PROJECT)
PY$(PROJECT)_SRC := python/$(PROJECT)/_$(PROJECT).cpp
PY$(PROJECT)_SO := python/$(PROJECT)/_$(PROJECT).so
PY$(PROJECT)_HXX := include/$(PROJECT)/layers/python_layer.hpp
# MAT$(PROJECT)_SRC is the mex entrance point of matlab package for $(PROJECT)
MAT$(PROJECT)_SRC := matlab/+$(PROJECT)/private/$(PROJECT)_.cpp
ifneq ($(MATLAB_DIR),)
    MAT_SO_EXT := $(shell $(MATLAB_DIR)/bin/mexext)
endif
MAT$(PROJECT)_SO := matlab/+$(PROJECT)/private/$(PROJECT)_.$(MAT_SO_EXT)

##############################
# Derive generated files
##############################
# The generated files for protocol buffers
PROTO_GEN_HEADER_SRCS := $(addprefix $(PROTO_BUILD_DIR)/, \
        $(notdir ${PROTO_SRCS:.proto=.pb.h}))
PROTO_GEN_HEADER := $(addprefix $(PROTO_BUILD_INCLUDE_DIR)/, \
        $(notdir ${PROTO_SRCS:.proto=.pb.h}))
PROTO_GEN_CC := $(addprefix $(BUILD_DIR)/, ${PROTO_SRCS:.proto=.pb.cc})
PY_PROTO_BUILD_DIR := python/$(PROJECT)/proto
PY_PROTO_INIT := python/$(PROJECT)/proto/__init__.py
PROTO_GEN_PY := $(foreach file,${PROTO_SRCS:.proto=_pb2.py}, \
        $(PY_PROTO_BUILD_DIR)/$(notdir $(file)))
# The objects corresponding to the source files
# These objects will be linked into the final shared library, so we
# exclude the tool, example, and test objects.
CXX_OBJS := $(addprefix $(BUILD_DIR)/, ${CXX_SRCS:.cpp=.o})
CU_OBJS := $(addprefix $(BUILD_DIR)/cuda/, ${CU_SRCS:.cu=.o})
PROTO_OBJS := ${PROTO_GEN_CC:.cc=.o}
OBJS := $(PROTO_OBJS) $(CXX_OBJS) $(CU_OBJS)
# tool, example, and test objects
TOOL_OBJS := $(addprefix $(BUILD_DIR)/, ${TOOL_SRCS:.cpp=.o})
TOOL_BUILD_DIR := $(BUILD_DIR)/tools
TEST_CXX_BUILD_DIR := $(BUILD_DIR)/src/$(PROJECT)/test
TEST_CU_BUILD_DIR := $(BUILD_DIR)/cuda/src/$(PROJECT)/test
TEST_CXX_OBJS := $(addprefix $(BUILD_DIR)/, ${TEST_SRCS:.cpp=.o})
TEST_CU_OBJS := $(addprefix $(BUILD_DIR)/cuda/, ${TEST_CU_SRCS:.cu=.o})
TEST_OBJS := $(TEST_CXX_OBJS) $(TEST_CU_OBJS)
GTEST_OBJ := $(addprefix $(BUILD_DIR)/, ${GTEST_SRC:.cpp=.o})
EXAMPLE_OBJS := $(addprefix $(BUILD_DIR)/, ${EXAMPLE_SRCS:.cpp=.o})
# Output files for automatic dependency generation
DEPS := ${CXX_OBJS:.o=.d} ${CU_OBJS:.o=.d} ${TEST_CXX_OBJS:.o=.d} \
    ${TEST_CU_OBJS:.o=.d} $(BUILD_DIR)/${MAT$(PROJECT)_SO:.$(MAT_SO_EXT)=.d}
# tool, example, and test bins
TOOL_BINS := ${TOOL_OBJS:.o=.bin}
EXAMPLE_BINS := ${EXAMPLE_OBJS:.o=.bin}
# symlinks to tool bins without the ".bin" extension
TOOL_BIN_LINKS := ${TOOL_BINS:.bin=}
# Put the test binaries in build/test for convenience.
TEST_BIN_DIR := $(BUILD_DIR)/test
TEST_CU_BINS := $(addsuffix .testbin,$(addprefix $(TEST_BIN_DIR)/, \
        $(foreach obj,$(TEST_CU_OBJS),$(basename $(notdir $(obj))))))
TEST_CXX_BINS := $(addsuffix .testbin,$(addprefix $(TEST_BIN_DIR)/, \
        $(foreach obj,$(TEST_CXX_OBJS),$(basename $(notdir $(obj))))))
TEST_BINS := $(TEST_CXX_BINS) $(TEST_CU_BINS)
# TEST_ALL_BIN is the test binary that links caffe dynamically.
TEST_ALL_BIN := $(TEST_BIN_DIR)/test_all.testbin

##############################
# Derive compiler warning dump locations
##############################
WARNS_EXT := warnings.txt
CXX_WARNS := $(addprefix $(BUILD_DIR)/, ${CXX_SRCS:.cpp=.o.$(WARNS_EXT)})
CU_WARNS := $(addprefix $(BUILD_DIR)/cuda/, ${CU_SRCS:.cu=.o.$(WARNS_EXT)})
TOOL_WARNS := $(addprefix $(BUILD_DIR)/, ${TOOL_SRCS:.cpp=.o.$(WARNS_EXT)})
EXAMPLE_WARNS := $(addprefix $(BUILD_DIR)/, ${EXAMPLE_SRCS:.cpp=.o.$(WARNS_EXT)})
TEST_WARNS := $(addprefix $(BUILD_DIR)/, ${TEST_SRCS:.cpp=.o.$(WARNS_EXT)})
TEST_CU_WARNS := $(addprefix $(BUILD_DIR)/cuda/, ${TEST_CU_SRCS:.cu=.o.$(WARNS_EXT)})
ALL_CXX_WARNS := $(CXX_WARNS) $(TOOL_WARNS) $(EXAMPLE_WARNS) $(TEST_WARNS)
ALL_CU_WARNS := $(CU_WARNS) $(TEST_CU_WARNS)
ALL_WARNS := $(ALL_CXX_WARNS) $(ALL_CU_WARNS)

EMPTY_WARN_REPORT := $(BUILD_DIR)/.$(WARNS_EXT)
NONEMPTY_WARN_REPORT := $(BUILD_DIR)/$(WARNS_EXT)

##############################
# Derive include and lib directories
##############################
CUDA_INCLUDE_DIR := $(CUDA_DIR)/include

CUDA_LIB_DIR :=
# add <cuda>/lib64 only if it exists
ifneq ("$(wildcard $(CUDA_DIR)/lib64)","")
    CUDA_LIB_DIR += $(CUDA_DIR)/lib64
endif
CUDA_LIB_DIR += $(CUDA_DIR)/lib

INCLUDE_DIRS += $(BUILD_INCLUDE_DIR) ./src ./include
ifneq ($(CPU_ONLY), 1)
    INCLUDE_DIRS += $(CUDA_INCLUDE_DIR)
    LIBRARY_DIRS += $(CUDA_LIB_DIR)
    LIBRARIES := cudart cublas curand
endif

LIBRARIES += glog gflags protobuf boost_system boost_filesystem m hdf5_serial_hl hdf5_serial

# handle IO dependencies
USE_LEVELDB ?= 1
USE_LMDB ?= 1
USE_OPENCV ?= 1

ifeq ($(USE_LEVELDB), 1)
    LIBRARIES += leveldb snappy
endif
ifeq ($(USE_LMDB), 1)
    LIBRARIES += lmdb
endif
ifeq ($(USE_OPENCV), 1)
    LIBRARIES += opencv_core opencv_highgui opencv_imgproc 

    ifeq ($(OPENCV_VERSION), 3)
        LIBRARIES += opencv_imgcodecs
    endif

endif
PYTHON_LIBRARIES ?= boost_python python2.7
WARNINGS := -Wall -Wno-sign-compare

##############################
# Set build directories
##############################

DISTRIBUTE_DIR ?= distribute
DISTRIBUTE_SUBDIRS := $(DISTRIBUTE_DIR)/bin $(DISTRIBUTE_DIR)/lib
DIST_ALIASES := dist
ifneq ($(strip $(DISTRIBUTE_DIR)),distribute)
        DIST_ALIASES += distribute
endif

ALL_BUILD_DIRS := $(sort $(BUILD_DIR) $(addprefix $(BUILD_DIR)/, $(SRC_DIRS)) \
    $(addprefix $(BUILD_DIR)/cuda/, $(SRC_DIRS)) \
    $(LIB_BUILD_DIR) $(TEST_BIN_DIR) $(PY_PROTO_BUILD_DIR) $(LINT_OUTPUT_DIR) \
    $(DISTRIBUTE_SUBDIRS) $(PROTO_BUILD_INCLUDE_DIR))

##############################
# Set directory for Doxygen-generated documentation
##############################
DOXYGEN_CONFIG_FILE ?= ./.Doxyfile
# should be the same as OUTPUT_DIRECTORY in the .Doxyfile
DOXYGEN_OUTPUT_DIR ?= ./doxygen
DOXYGEN_COMMAND ?= doxygen
# All the files that might have Doxygen documentation.
DOXYGEN_SOURCES := $(shell find \
    src/$(PROJECT) \
    include/$(PROJECT) \
    python/ \
    matlab/ \
    examples \
    tools \
    -name "*.cpp" -or -name "*.hpp" -or -name "*.cu" -or -name "*.cuh" -or \
        -name "*.py" -or -name "*.m")
DOXYGEN_SOURCES += $(DOXYGEN_CONFIG_FILE)


##############################
# Configure build
##############################

# Determine platform
UNAME := $(shell uname -s)
ifeq ($(UNAME), Linux)
    LINUX := 1
else ifeq ($(UNAME), Darwin)
    OSX := 1
endif

# Linux
ifeq ($(LINUX), 1)
    CXX ?= /usr/bin/g++
    GCCVERSION := $(shell $(CXX) -dumpversion | cut -f1,2 -d.)
    # older versions of gcc are too dumb to build boost with -Wuninitalized
    ifeq ($(shell echo | awk '{exit $(GCCVERSION) < 4.6;}'), 1)
        WARNINGS += -Wno-uninitialized
    endif
    # boost::thread is reasonably called boost_thread (compare OS X)
    # We will also explicitly add stdc++ to the link target.
    LIBRARIES += boost_thread stdc++
    VERSIONFLAGS += -Wl,-soname,$(DYNAMIC_VERSIONED_NAME_SHORT) -Wl,-rpath,$(ORIGIN)/../lib
endif

# OS X:
# clang++ instead of g++
# libstdc++ for NVCC compatibility on OS X >= 10.9 with CUDA < 7.0
ifeq ($(OSX), 1)
    CXX := /usr/bin/clang++
    ifneq ($(CPU_ONLY), 1)
        CUDA_VERSION := $(shell $(CUDA_DIR)/bin/nvcc -V | grep -o 'release \d' | grep -o '\d')
        ifeq ($(shell echo | awk '{exit $(CUDA_VERSION) < 7.0;}'), 1)
            CXXFLAGS += -stdlib=libstdc++
            LINKFLAGS += -stdlib=libstdc++
        endif
        # clang throws this warning for cuda headers
        WARNINGS += -Wno-unneeded-internal-declaration
    endif
    # gtest needs to use its own tuple to not conflict with clang
    COMMON_FLAGS += -DGTEST_USE_OWN_TR1_TUPLE=1
    # boost::thread is called boost_thread-mt to mark multithreading on OS X
    LIBRARIES += boost_thread-mt
    # we need to explicitly ask for the rpath to be obeyed
    DYNAMIC_FLAGS := -install_name @rpath/libcaffe.so
    ORIGIN := @loader_path
    VERSIONFLAGS += -Wl,-install_name,$(DYNAMIC_VERSIONED_NAME_SHORT) -Wl,-rpath,$(ORIGIN)/../../build/lib
else
    ORIGIN := \$$ORIGIN
endif

# Custom compiler
ifdef CUSTOM_CXX
    CXX := $(CUSTOM_CXX)
endif

# Static linking
ifneq (,$(findstring clang++,$(CXX)))
    STATIC_LINK_COMMAND := -Wl,-force_load $(STATIC_NAME)
else ifneq (,$(findstring g++,$(CXX)))
    STATIC_LINK_COMMAND := -Wl,--whole-archive $(STATIC_NAME) -Wl,--no-whole-archive
else
  # The following line must not be indented with a tab, since we are not inside a target
  $(error Cannot static link with the $(CXX) compiler)
endif

# Debugging
ifeq ($(DEBUG), 1)
    COMMON_FLAGS += -DDEBUG -g -O0
    NVCCFLAGS += -G
else
    COMMON_FLAGS += -DNDEBUG -O2
endif

# cuDNN acceleration configuration.
ifeq ($(USE_CUDNN), 1)
    LIBRARIES += cudnn
    COMMON_FLAGS += -DUSE_CUDNN
endif

# configure IO libraries
ifeq ($(USE_OPENCV), 1)
    COMMON_FLAGS += -DUSE_OPENCV
endif
ifeq ($(USE_LEVELDB), 1)
    COMMON_FLAGS += -DUSE_LEVELDB
endif
ifeq ($(USE_LMDB), 1)
    COMMON_FLAGS += -DUSE_LMDB
ifeq ($(ALLOW_LMDB_NOLOCK), 1)
    COMMON_FLAGS += -DALLOW_LMDB_NOLOCK
endif
endif

# CPU-only configuration
ifeq ($(CPU_ONLY), 1)
    OBJS := $(PROTO_OBJS) $(CXX_OBJS)
    TEST_OBJS := $(TEST_CXX_OBJS)
    TEST_BINS := $(TEST_CXX_BINS)
    ALL_WARNS := $(ALL_CXX_WARNS)
    TEST_FILTER := --gtest_filter="-*GPU*"
    COMMON_FLAGS += -DCPU_ONLY
endif

# Python layer support
ifeq ($(WITH_PYTHON_LAYER), 1)
    COMMON_FLAGS += -DWITH_PYTHON_LAYER
    LIBRARIES += $(PYTHON_LIBRARIES)
endif

# BLAS configuration (default = ATLAS)
BLAS ?= atlas
ifeq ($(BLAS), mkl)
    # MKL
    LIBRARIES += mkl_rt
    COMMON_FLAGS += -DUSE_MKL
    MKL_DIR ?= /opt/intel/mkl
    BLAS_INCLUDE ?= $(MKL_DIR)/include
    BLAS_LIB ?= $(MKL_DIR)/lib $(MKL_DIR)/lib/intel64
else ifeq ($(BLAS), open)
    # OpenBLAS
    LIBRARIES += openblas
else
    # ATLAS
    ifeq ($(LINUX), 1)
        ifeq ($(BLAS), atlas)
            # Linux simply has cblas and atlas
            LIBRARIES += cblas atlas
        endif
    else ifeq ($(OSX), 1)
        # OS X packages atlas as the vecLib framework
        LIBRARIES += cblas
        # 10.10 has accelerate while 10.9 has veclib
        XCODE_CLT_VER := $(shell pkgutil --pkg-info=com.apple.pkg.CLTools_Executables | grep 'version' | sed 's/[^0-9]*\([0-9]\).*/\1/')
        XCODE_CLT_GEQ_6 := $(shell [ $(XCODE_CLT_VER) -gt 5 ] && echo 1)
        ifeq ($(XCODE_CLT_GEQ_6), 1)
            BLAS_INCLUDE ?= /System/Library/Frameworks/Accelerate.framework/Versions/Current/Frameworks/vecLib.framework/Headers/
            LDFLAGS += -framework Accelerate
        else
            BLAS_INCLUDE ?= /System/Library/Frameworks/vecLib.framework/Versions/Current/Headers/
            LDFLAGS += -framework vecLib
        endif
    endif
endif
INCLUDE_DIRS += $(BLAS_INCLUDE)
LIBRARY_DIRS += $(BLAS_LIB)

LIBRARY_DIRS += $(LIB_BUILD_DIR)

# Automatic dependency generation (nvcc is handled separately)
CXXFLAGS += -MMD -MP

# Complete build flags.
COMMON_FLAGS += $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir))
CXXFLAGS += -pthread -fPIC $(COMMON_FLAGS) $(WARNINGS)
NVCCFLAGS += -ccbin=$(CXX) -Xcompiler -fPIC $(COMMON_FLAGS)
# mex may invoke an older gcc that is too liberal with -Wuninitalized
MATLAB_CXXFLAGS := $(CXXFLAGS) -Wno-uninitialized
LINKFLAGS += -pthread -fPIC $(COMMON_FLAGS) $(WARNINGS)

USE_PKG_CONFIG ?= 0
ifeq ($(USE_PKG_CONFIG), 1)
    PKG_CONFIG := $(shell pkg-config opencv --libs)
else
    PKG_CONFIG :=
endif
LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) $(PKG_CONFIG) \
        $(foreach library,$(LIBRARIES),-l$(library))
PYTHON_LDFLAGS := $(LDFLAGS) $(foreach library,$(PYTHON_LIBRARIES),-l$(library))

# 'superclean' target recursively* deletes all files ending with an extension
# in $(SUPERCLEAN_EXTS) below.  This may be useful if you've built older
# versions of Caffe that do not place all generated files in a location known
# to the 'clean' target.
#
# 'supercleanlist' will list the files to be deleted by make superclean.
#
# * Recursive with the exception that symbolic links are never followed, per the
# default behavior of 'find'.
SUPERCLEAN_EXTS := .so .a .o .bin .testbin .pb.cc .pb.h _pb2.py .cuo

# Set the sub-targets of the 'everything' target.
EVERYTHING_TARGETS := all py$(PROJECT) test warn lint
# Only build matcaffe as part of "everything" if MATLAB_DIR is specified.
ifneq ($(MATLAB_DIR),)
    EVERYTHING_TARGETS += mat$(PROJECT)
endif

##############################
# Define build targets
##############################
.PHONY: all lib test clean docs linecount lint lintclean tools examples $(DIST_ALIASES) \
    py mat py$(PROJECT) mat$(PROJECT) proto runtest \
    superclean supercleanlist supercleanfiles warn everything

all: lib tools examples

lib: $(STATIC_NAME) $(DYNAMIC_NAME)

everything: $(EVERYTHING_TARGETS)

linecount:
    cloc --read-lang-def=$(PROJECT).cloc \
        src/$(PROJECT) include/$(PROJECT) tools examples \
        python matlab

lint: $(EMPTY_LINT_REPORT)

lintclean:
    @ $(RM) -r $(LINT_OUTPUT_DIR) $(EMPTY_LINT_REPORT) $(NONEMPTY_LINT_REPORT)

docs: $(DOXYGEN_OUTPUT_DIR)
    @ cd ./docs ; ln -sfn ../$(DOXYGEN_OUTPUT_DIR)/html doxygen

$(DOXYGEN_OUTPUT_DIR): $(DOXYGEN_CONFIG_FILE) $(DOXYGEN_SOURCES)
    $(DOXYGEN_COMMAND) $(DOXYGEN_CONFIG_FILE)

$(EMPTY_LINT_REPORT): $(LINT_OUTPUTS) | $(BUILD_DIR)
    @ cat $(LINT_OUTPUTS) > [email protected]
    @ if [ -s "[email protected]" ]; then \
        cat [email protected]; \
        mv [email protected] $(NONEMPTY_LINT_REPORT); \
        echo "Found one or more lint errors."; \
        exit 1; \
      fi; \
      $(RM) $(NONEMPTY_LINT_REPORT); \
      echo "No lint errors!";

$(LINT_OUTPUTS): $(LINT_OUTPUT_DIR)/%.lint.txt : % $(LINT_SCRIPT) | $(LINT_OUTPUT_DIR)
    @ mkdir -p $(dir [email protected])
    @ python $(LINT_SCRIPT) $< 2>&1 \
        | grep -v "^Done processing " \
        | grep -v "^Total errors found: 0" \
        > [email protected] \
        || true

test: $(TEST_ALL_BIN) $(TEST_ALL_DYNLINK_BIN) $(TEST_BINS)

tools: $(TOOL_BINS) $(TOOL_BIN_LINKS)

examples: $(EXAMPLE_BINS)

py$(PROJECT): py

py: $(PY$(PROJECT)_SO) $(PROTO_GEN_PY)

$(PY$(PROJECT)_SO): $(PY$(PROJECT)_SRC) $(PY$(PROJECT)_HXX) | $(DYNAMIC_NAME)
    @ echo CXX/LD -o [email protected] $<
    $(Q)$(CXX) -shared -o [email protected] $(PY$(PROJECT)_SRC) \
        -o [email protected] $(LINKFLAGS) -l$(LIBRARY_NAME) $(PYTHON_LDFLAGS) \
        -Wl,-rpath,$(ORIGIN)/../../build/lib

mat$(PROJECT): mat

mat: $(MAT$(PROJECT)_SO)

$(MAT$(PROJECT)_SO): $(MAT$(PROJECT)_SRC) $(STATIC_NAME)
    @ if [ -z "$(MATLAB_DIR)" ]; then \
        echo "MATLAB_DIR must be specified in $(CONFIG_FILE)" \
            "to build mat$(PROJECT)."; \
        exit 1; \
    fi
    @ echo MEX $<
    $(Q)$(MATLAB_DIR)/bin/mex $(MAT$(PROJECT)_SRC) \
            CXX="$(CXX)" \
            CXXFLAGS="\$$CXXFLAGS $(MATLAB_CXXFLAGS)" \
            CXXLIBS="\$$CXXLIBS $(STATIC_LINK_COMMAND) $(LDFLAGS)" -output [email protected]
    @ if [ -f "$(PROJECT)_.d" ]; then \
        mv -f $(PROJECT)_.d $(BUILD_DIR)/${MAT$(PROJECT)_SO:.$(MAT_SO_EXT)=.d}; \
    fi

runtest: $(TEST_ALL_BIN)
    $(TOOL_BUILD_DIR)/caffe
    $(TEST_ALL_BIN) $(TEST_GPUID) --gtest_shuffle $(TEST_FILTER)

pytest: py
    cd python; python -m unittest discover -s caffe/test

mattest: mat
    cd matlab; $(MATLAB_DIR)/bin/matlab -nodisplay -r 'caffe.run_tests(), exit()'

warn: $(EMPTY_WARN_REPORT)

$(EMPTY_WARN_REPORT): $(ALL_WARNS) | $(BUILD_DIR)
    @ cat $(ALL_WARNS) > [email protected]
    @ if [ -s "[email protected]" ]; then \
        cat [email protected]; \
        mv [email protected] $(NONEMPTY_WARN_REPORT); \
        echo "Compiler produced one or more warnings."; \
        exit 1; \
      fi; \
      $(RM) $(NONEMPTY_WARN_REPORT); \
      echo "No compiler warnings!";

$(ALL_WARNS): %.o.$(WARNS_EXT) : %.o

$(BUILD_DIR_LINK): $(BUILD_DIR)/.linked

# Create a target ".linked" in this BUILD_DIR to tell Make that the "build" link
# is currently correct, then delete the one in the OTHER_BUILD_DIR in case it
# exists and $(DEBUG) is toggled later.
$(BUILD_DIR)/.linked:
    @ mkdir -p $(BUILD_DIR)
    @ $(RM) $(OTHER_BUILD_DIR)/.linked
    @ $(RM) -r $(BUILD_DIR_LINK)
    @ ln -s $(BUILD_DIR) $(BUILD_DIR_LINK)
    @ touch [email protected]

$(ALL_BUILD_DIRS): | $(BUILD_DIR_LINK)
    @ mkdir -p [email protected]

$(DYNAMIC_NAME): $(OBJS) | $(LIB_BUILD_DIR)
    @ echo LD -o [email protected]
    $(Q)$(CXX) -shared -o [email protected] $(OBJS) $(VERSIONFLAGS) $(LINKFLAGS) $(LDFLAGS) $(DYNAMIC_FLAGS)
    @ cd $(BUILD_DIR)/lib; rm -f $(DYNAMIC_NAME_SHORT);   ln -s $(DYNAMIC_VERSIONED_NAME_SHORT) $(DYNAMIC_NAME_SHORT)

$(STATIC_NAME): $(OBJS) | $(LIB_BUILD_DIR)
    @ echo AR -o [email protected]
    $(Q)ar rcs [email protected] $(OBJS)

$(BUILD_DIR)/%.o: %.cpp | $(ALL_BUILD_DIRS)
    @ echo CXX $<
    $(Q)$(CXX) $< $(CXXFLAGS) -c -o [email protected] 2> [email protected]$(WARNS_EXT) \
        || (cat [email protected]$(WARNS_EXT); exit 1)
    @ cat [email protected]$(WARNS_EXT)

$(PROTO_BUILD_DIR)/%.pb.o: $(PROTO_BUILD_DIR)/%.pb.cc $(PROTO_GEN_HEADER) \
        | $(PROTO_BUILD_DIR)
    @ echo CXX $<
    $(Q)$(CXX) $< $(CXXFLAGS) -c -o [email protected] 2> [email protected]$(WARNS_EXT) \
        || (cat [email protected]$(WARNS_EXT); exit 1)
    @ cat [email protected]$(WARNS_EXT)

$(BUILD_DIR)/cuda/%.o: %.cu | $(ALL_BUILD_DIRS)
    @ echo NVCC $<
    $(Q)$(CUDA_DIR)/bin/nvcc $(NVCCFLAGS) $(CUDA_ARCH) -M $< -o ${@:.o=.d} \
        -odir $(@D)
    $(Q)$(CUDA_DIR)/bin/nvcc $(NVCCFLAGS) $(CUDA_ARCH) -c $< -o [email protected] 2> [email protected]$(WARNS_EXT) \
        || (cat [email protected]$(WARNS_EXT); exit 1)
    @ cat [email protected]$(WARNS_EXT)

$(TEST_ALL_BIN): $(TEST_MAIN_SRC) $(TEST_OBJS) $(GTEST_OBJ) \
        | $(DYNAMIC_NAME) $(TEST_BIN_DIR)
    @ echo CXX/LD -o [email protected] $<
    $(Q)$(CXX) $(TEST_MAIN_SRC) $(TEST_OBJS) $(GTEST_OBJ) \
        -o [email protected] $(LINKFLAGS) $(LDFLAGS) -l$(LIBRARY_NAME) -Wl,-rpath,$(ORIGIN)/../lib

$(TEST_CU_BINS): $(TEST_BIN_DIR)/%.testbin: $(TEST_CU_BUILD_DIR)/%.o \
    $(GTEST_OBJ) | $(DYNAMIC_NAME) $(TEST_BIN_DIR)
    @ echo LD $<
    $(Q)$(CXX) $(TEST_MAIN_SRC) $< $(GTEST_OBJ) \
        -o [email protected] $(LINKFLAGS) $(LDFLAGS) -l$(LIBRARY_NAME) -Wl,-rpath,$(ORIGIN)/../lib

$(TEST_CXX_BINS): $(TEST_BIN_DIR)/%.testbin: $(TEST_CXX_BUILD_DIR)/%.o \
    $(GTEST_OBJ) | $(DYNAMIC_NAME) $(TEST_BIN_DIR)
    @ echo LD $<
    $(Q)$(CXX) $(TEST_MAIN_SRC) $< $(GTEST_OBJ) \
        -o [email protected] $(LINKFLAGS) $(LDFLAGS) -l$(LIBRARY_NAME) -Wl,-rpath,$(ORIGIN)/../lib

# Target for extension-less symlinks to tool binaries with extension '*.bin'.
$(TOOL_BUILD_DIR)/%: $(TOOL_BUILD_DIR)/%.bin | $(TOOL_BUILD_DIR)
    @ $(RM) [email protected]
    @ ln -s $(notdir $<) [email protected]

$(TOOL_BINS): %.bin : %.o | $(DYNAMIC_NAME)
    @ echo CXX/LD -o [email protected]
    $(Q)$(CXX) $< -o [email protected] $(LINKFLAGS) -l$(LIBRARY_NAME) $(LDFLAGS) \
        -Wl,-rpath,$(ORIGIN)/../lib

$(EXAMPLE_BINS): %.bin : %.o | $(DYNAMIC_NAME)
    @ echo CXX/LD -o [email protected]
    $(Q)$(CXX) $< -o [email protected] $(LINKFLAGS) -l$(LIBRARY_NAME) $(LDFLAGS) \
        -Wl,-rpath,$(ORIGIN)/../../lib

proto: $(PROTO_GEN_CC) $(PROTO_GEN_HEADER)

$(PROTO_BUILD_DIR)/%.pb.cc $(PROTO_BUILD_DIR)/%.pb.h : \
        $(PROTO_SRC_DIR)/%.proto | $(PROTO_BUILD_DIR)
    @ echo PROTOC $<
    $(Q)protoc --proto_path=$(PROTO_SRC_DIR) --cpp_out=$(PROTO_BUILD_DIR) $<

$(PY_PROTO_BUILD_DIR)/%_pb2.py : $(PROTO_SRC_DIR)/%.proto \
        $(PY_PROTO_INIT) | $(PY_PROTO_BUILD_DIR)
    @ echo PROTOC \(python\) $<
    $(Q)protoc --proto_path=$(PROTO_SRC_DIR) --python_out=$(PY_PROTO_BUILD_DIR) $<

$(PY_PROTO_INIT): | $(PY_PROTO_BUILD_DIR)
    touch $(PY_PROTO_INIT)