# C++ Tutorial - Build the Sample > > > Prerequisites > > > - The Qualcomm® Neural Processing SDK has been set up following the [Qualcomm (R) Neural Processing SDK > Setup](https://docs.qualcomm.com/doc/80-63442-2/topic/setup.html) chapter. > - The [Tutorials Setup](https://docs.qualcomm.com/doc/80-63442-2/topic/tutorial_setup.html) has been > completed. > > > > Introduction > > > This tutorial demonstrates how to build a C++ sample > application that can execute neural network models on the PC or > target device. Please note, while this sample code does not do any error > checking, it is strongly recommended that users check for > errors when using the Qualcomm® Neural Processing SDK APIs. > > > Most applications will follow the following pattern while using > a neural network: > > 1. [Get Available Runtime](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#get-available-runtime) > 2. [Load Network](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#load-network) > 3. [Load UDO](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#load-udo) > 4. [Set Network Builder Options](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#set-network-builder-options) > 5. [Load Network Inputs](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#load-network-inputs) > > 1. [Using User Buffers](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#load-using-user-buffers) > 2. [Using ITensors](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#load-using-itensors) > 6. [Execute the Network & Process Output](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#execute-the-network-process-output) > > 1. [Using User Buffers](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#execute-using-user-buffers) > 2. [Using ITensors](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#execute-using-itensors) > 7. [Using IOBufferDataTypeMap](https://docs.qualcomm.com/doc/80-63442-2/topic/cplus_plus_tutorial.html#using-iobufferdatatypemap) > > > > static zdl::DlSystem::Runtime_t runtime = checkRuntime(); > std::unique_ptr container = loadContainerFromFile(dlc); > std::unique_ptr snpe = setBuilderOptions(container, runtime, useUserSuppliedBuffers); > std::unique_ptr inputTensor = loadInputTensor(snpe, fileLine); // ITensor > loadInputUserBuffer(applicationInputBuffers, snpe, fileLine); // User Buffer > executeNetwork(snpe , inputTensor, OutputDir, inputListNum); // ITensor > executeNetwork(snpe, inputMap, outputMap, applicationOutputBuffers, OutputDir, inputListNum); // User Buffer > Copy to clipboard > > > The sections below describe how to implement each step > described above. For more details, please refer to the > collection of source code files located at > $SNPE\_ROOT/examples/SNPE/NativeCpp/SampleCode\_CPP. > > > Get Available Runtime > > > The code excerpt below illustrates how to check if a specific > runtime is available using the native APIs (the GPU runtime is > used as an example). > > > zdl::DlSystem::Runtime_t checkRuntime() > { > static zdl::DlSystem::Version_t Version = zdl::SNPE::SNPEFactory::getLibraryVersion(); > static zdl::DlSystem::Runtime_t Runtime; > std::cout << "Qualcomm (R) Neural Processing SDK Version: " << Version.asString().c_str() << std::endl; //Print Version number > if (zdl::SNPE::SNPEFactory::isRuntimeAvailable(zdl::DlSystem::Runtime_t::GPU)) { > Runtime = zdl::DlSystem::Runtime_t::GPU; > } else { > Runtime = zdl::DlSystem::Runtime_t::CPU; > } > return Runtime; > } > Copy to clipboard > > > Load Network > > > The code excerpt below illustrates how to load a network from > the Qualcomm® Neural Processing SDK container file (DLC). > > > std::unique_ptr loadContainerFromFile(std::string containerPath) > { > std::unique_ptr container; > container = zdl::DlContainer::IDlContainer::open(containerPath); > return container; > } > Copy to clipboard > > > Load UDO > > > The code excerpt below illustrates how to load UDO package(s). > > > bool loadUDOPackage(const std::string& UdoPackagePath) > { > std::vector udoPkgPathsList; > split(udoPkgPathsList, UdoPackagePath, ','); > for (const auto &u : udoPkgPathsList) > { > if (false == zdl::SNPE::SNPEFactory::addOpPackage(u)) > { > std::cerr << "Error while loading UDO package: "<< u << std::endl; > return false; > } > } > return true; > } > Copy to clipboard > > > Qualcomm® Neural Processing SDK can execute network with user-defined operations (UDO). > Please refer to [UDO Tutorial](https://docs.qualcomm.com/doc/80-63442-2/topic/tutorial_inceptionv3_udo.html) for implementing > an UDO. The UDO can be specified to snpe-sample using “-u” option. > > > Set Network Builder Options > > > The following code demonstrates how to instantiate a SNPE > Builder object, which will be used to execute the network with > the given parameters. > > > std::unique_ptr setBuilderOptions(std::unique_ptr& container, > zdl::DlSystem::RuntimeList runtimeList, > bool useUserSuppliedBuffers) > { > std::unique_ptr snpe; > zdl::SNPE::SNPEBuilder snpeBuilder(container.get()); > snpe = snpeBuilder.setOutputLayers({}) > .setRuntimeProcessorOrder(runtimeList) > .setUseUserSuppliedBuffers(useUserSuppliedBuffers) > .build(); > return snpe; > } > Copy to clipboard > > > Load Network Inputs > > > Network inputs and outputs can be either user-backed buffers or > ITensors (built-in Qualcomm® Neural Processing SDK buffers), but not both. The advantage > of using user-backed buffers is that it eliminates an extra > copy from user buffers to create ITensors. Both methods of > loading network inputs are shown below. > > > Using User Buffers > > > Qualcomm® Neural Processing SDK can create its network inputs and outputs from user-backed > buffers. Note that Qualcomm® Neural Processing SDK expects the values of the buffers to be > present and valid during the duration of its execution. > > > Here is a function for creating a Qualcomm® Neural Processing SDK UserBuffer from a > user-backed buffer and storing it in a > zdl::DlSystem::UserBufferMap > These maps are a convenient collection of all input or output > user buffers that can be passed to Qualcomm® Neural Processing SDK to execute the network. > > > Disclaimer: The strides of the buffer should already be known > by the user and should not be calculated as shown below. The > calculation shown is solely used for executing the example > code. > > > void createUserBuffer(zdl::DlSystem::UserBufferMap& userBufferMap, > std::unordered_map>& applicationBuffers, > std::vector>& snpeUserBackedBuffers, > std::unique_ptr& snpe, > const char * name) > { > // get attributes of buffer by name > auto bufferAttributesOpt = snpe->getInputOutputBufferAttributes(name); > if (!bufferAttributesOpt) throw std::runtime_error(std::string("Error obtaining attributes for input tensor ") + name); > // calculate the size of buffer required by the input tensor > const zdl::DlSystem::TensorShape& bufferShape = (*bufferAttributesOpt)->getDims(); > // Calculate the stride based on buffer strides, assuming tightly packed. > // Note: Strides = Number of bytes to advance to the next element in each dimension. > // For example, if a float tensor of dimension 2x4x3 is tightly packed in a buffer of 96 bytes, then the strides would be (48,12,4) > // Note: Buffer stride is usually known and does not need to be calculated. > std::vector strides(bufferShape.rank()); > strides[strides.size() - 1] = sizeof(float); > size_t stride = strides[strides.size() - 1]; > for (size_t i = bufferShape.rank() - 1; i > 0; i--) > { > stride *= bufferShape[i]; > strides[i-1] = stride; > } > const size_t bufferElementSize = (*bufferAttributesOpt)->getElementSize(); > size_t bufSize = calcSizeFromDims(bufferShape.getDimensions(), bufferShape.rank(), bufferElementSize); > // set the buffer encoding type > zdl::DlSystem::UserBufferEncodingFloat userBufferEncodingFloat; > // create user-backed storage to load input data onto it > applicationBuffers.emplace(name, std::vector(bufSize)); > // create Qualcomm (R) Neural Processing SDK user buffer from the user-backed buffer > zdl::DlSystem::IUserBufferFactory& ubFactory = zdl::SNPE::SNPEFactory::getUserBufferFactory(); > snpeUserBackedBuffers.push_back(ubFactory.createUserBuffer(applicationBuffers.at(name).data(), > bufSize, > strides, > &userBufferEncodingFloat)); > // add the user-backed buffer to the inputMap, which is later on fed to the network for execution > userBufferMap.add(name, snpeUserBackedBuffers.back().get()); > } > Copy to clipboard > > > The following function then shows how to load input data from > file(s) to user buffers. Note that the input values are simply > loaded onto user-backed buffers, on top of which Qualcomm® Neural Processing SDK can > create Qualcomm® Neural Processing SDK UserBuffers, as shown above. > > > void loadInputUserBuffer(std::unordered_map>& applicationBuffers, > std::unique_ptr& snpe, > const std::string& fileLine) > { > // get input tensor names of the network that need to be populated > const auto& inputNamesOpt = snpe->getInputTensorNames(); > if (!inputNamesOpt) throw std::runtime_error("Error obtaining input tensor names"); > const zdl::DlSystem::StringList& inputNames = *inputNamesOpt; > assert(inputNames.size() > 0); > // treat each line as a space-separated list of input files > std::vector filePaths; > split(filePaths, fileLine, ' '); > if (inputNames.size()) std::cout << "Processing DNN Input: " << std::endl; > for (size_t i = 0; i < inputNames.size(); i++) { > const char* name = inputNames.at(i); > std::string filePath(filePaths[i]); > // print out which file is being processed > std::cout << "\t" << i + 1 << ") " << filePath << std::endl; > // load file content onto application storage buffer, > // on top of which, Qualcomm (R) Neural Processing SDK has created a user buffer > loadByteDataFile(filePath, applicationBuffers.at(name)); > }; > } > Copy to clipboard > > > Using ITensors > > > std::unique_ptr loadInputTensor (std::unique_ptr & snpe , std::string& fileLine) > { > std::unique_ptr input; > const auto &strList_opt = snpe->getInputTensorNames(); > if (!strList_opt) throw std::runtime_error("Error obtaining Input tensor names"); > const auto &strList = *strList_opt; > // Make sure the network requires only a single input > assert (strList.size() == 1); > // If the network has a single input, each line represents the input file to be loaded for that input > std::string filePath(fileLine); > std::cout << "Processing DNN Input: " << filePath << "\n"; > std::vector inputVec = loadFloatDataFile(filePath); > /* Create an input tensor that is correctly sized to hold the input of the network. Dimensions that have no fixed size will be represented with a value of 0. */ > const auto &inputDims_opt = snpe->getInputDimensions(strList.at(0)); > const auto &inputShape = *inputDims_opt; > /* Calculate the total number of elements that can be stored in the tensor so that we can check that the input contains the expected number of elements. > With the input dimensions computed create a tensor to convey the input into the network. */ > input = zdl::SNPE::SNPEFactory::getTensorFactory().createTensor(inputShape); > /* Copy the loaded input file contents into the networks input tensor.SNPE's ITensor supports C++ STL functions like std::copy() */ > std::copy(inputVec.begin(), inputVec.end(), input->begin()); > return input; > } > Copy to clipboard > > > Execute the Network & Process Output > > > The following snippets of code use the native API to execute > the network (in UserBuffer or ITensor mode) and show how to > iterate through the newly populated output tensor. > > > Using User Buffers > > > void executeNetwork(std::unique_ptr& snpe, > zdl::DlSystem::UserBufferMap& inputMap, > zdl::DlSystem::UserBufferMap& outputMap, > std::unordered_map>& applicationOutputBuffers, > const std::string& outputDir, > int num) > { > // Execute the network and store the outputs in user buffers specified in outputMap > snpe->execute(inputMap, outputMap); > // Get all output buffer names from the network > const zdl::DlSystem::StringList& outputBufferNames = outputMap.getUserBufferNames(); > // Iterate through output buffers and print each output to a raw file > std::for_each(outputBufferNames.begin(), outputBufferNames.end(), [&](const char* name) > { > std::ostringstream path; > path << outputDir << "/Result_" << num << "/" << name << ".raw"; > SaveUserBuffer(path.str(), applicationOutputBuffers.at(name)); > }); > } > // The following is a partial snippet of the function > void SaveUserBuffer(const std::string& path, const std::vector& buffer) { > ... > std::ofstream os(path, std::ofstream::binary); > if (!os) > { > std::cerr << "Failed to open output file for writing: " << path << "\n"; > std::exit(EXIT_FAILURE); > } > if (!os.write((char*)(buffer.data()), buffer.size())) > { > std::cerr << "Failed to write data to: " << path << "\n"; > std::exit(EXIT_FAILURE); > } > } > Copy to clipboard > > > Using ITensors > > > void executeNetwork(std::unique_ptr& snpe, > std::unique_ptr& input, > std::string OutputDir, > int num) > { > //Execute the network and store the outputs that were specified when creating the network in a TensorMap > static zdl::DlSystem::TensorMap outputTensorMap; > snpe->execute(input.get(), outputTensorMap); > zdl::DlSystem::StringList tensorNames = outputTensorMap.getTensorNames(); > //Iterate through the output Tensor map, and print each output layer name > std::for_each( tensorNames.begin(), tensorNames.end(), [&](const char* name) > { > std::ostringstream path; > path << OutputDir << "/" > << "Result_" << num << "/" > << name << ".raw"; > auto tensorPtr = outputTensorMap.getTensor(name); > SaveITensor(path.str(), tensorPtr); > }); > } > // The following is a partial snippet of the function > void SaveITensor(const std::string& path, const zdl::DlSystem::ITensor* tensor) > { > ... > std::ofstream os(path, std::ofstream::binary); > if (!os) > { > std::cerr << "Failed to open output file for writing: " << path << "\n"; > std::exit(EXIT_FAILURE); > } > for ( auto it = tensor->cbegin(); it != tensor->cend(); ++it ) > { > float f = *it; > if (!os.write(reinterpret_cast(&f), sizeof(float))) > { > std::cerr << "Failed to write data to: " << path << "\n"; > std::exit(EXIT_FAILURE); > } > } > } > Copy to clipboard > > > Using IOBufferDataTypeMap > > - The IOBufferDataTypeMap is used to specify the intended data > type for input/output of a network. The data type values > include > zdl::DlSystem::IOBufferDataType\_t::FLOATING\_POINT\_32, > zdl::DlSystem::IOBufferDataType\_t::FIXED\_POINT\_8 and > zdl::DlSystem::IOBufferDataType\_t::FIXED\_POINT\_16. > - If the output of a network is of type FIXED\_POINT\_8 and > the user intends to access the output in FLOATING\_POINT\_32 > format, the dequantization operation is performed on the ARM > side. By specifying the data type as FLOATING\_POINT\_32 using > the IOBufferDataTypeMap API, the dequantization operation is > added directly to the graph. > > > > The following snippet of code shows how to specify the data > type for a buffer using the native API. > > > void setBufferDataType(zdl::DlSystem::IOBufferDataTypeMap& bufferDataTypeMap, std::string bufferName, zdl::DlSystem::IOBufferDataType_t dataType) > { > bufferDataTypeMap.add(bufferName.c_str(), dataType); > } > setBufferDataType(bufferDataTypeMap, "output_1", zdl::DlSystem::IOBufferDataType_t::FLOATING_POINT_32); > zdl::SNPE::SNPEBuilder snpeBuilder(container.get()); > snpeBuilder.setBufferDataType(bufferDataTypeMap); > Copy to clipboard > > > Building the C++ Application > > > Building and Running on x86 Linux and Embedded > Linux > > > Start by going to the snpe-sample base directory. > > > cd $SNPE_ROOT/examples/SNPE/NativeCpp/SampleCode_CPP > Copy to clipboard > > > Note the different makefiles associated with the different > Linux platform. Note that the $CXX would need to be set > according to the target platform. Here is a table of the > supported targets, and their corresponding settings for $CXX > and the Makefiles to use. > > > > > > > | Target | Makefile | Possible CXX value | Output Location | > | --- | --- | --- | --- | > | aarch64-oe-linux-gcc8.2 | Makefile.aarch64-oe-linux-gcc8.2 | aarch64-oe-linux-g++ | aarch64-oe-linux-gcc8.2 | > | aarch64-oe-linux-gcc9.3 | Makefile.aarch64-oe-linux-gcc9.3 | aarch64-oe-linux-g++ | aarch64-oe-linux-gcc9.3 | > | aarch64-oe-linux-gcc11.2 | Makefile.aarch64-oe-linux-gcc11.2 | aarch64-oe-linux-g++ | aarch64-oe-linux-gcc11.2 | > | aarch64-ubuntu-gcc9.4 | Makefile.aarch64-ubuntu-gcc9.4 | aarch64-linux-gnu-g++ | aarch64-ubuntu-gcc9.4 | > | x86\_64-linux | Makefile.x86\_64-linux-clang | g++ | x86\_64-linux-clang | > > > > export CXX= > make -f > Copy to clipboard > > > **Note:** Ensure that the path to the compiler binary is > already set in $PATH. > > > Along with the sample executable, all other libraries need to > be pushed onto their respective targets. The $LD\_LIBRARY\_PATH > may also need to be updated to point to the support libraries. > You can run the executable with -h argument to see its > description. > > > snpe-sample -h > Copy to clipboard > > > The description should look like the following: > > > DESCRIPTION: > ------------ > Example application demonstrating how to load and execute a neural network > using the SNPE C++ API. > > > REQUIRED ARGUMENTS: > ------------------- > -d Path to the DL container containing the network. > -i Path to a file listing the inputs for the network. > -o Path to directory to store output results. > > OPTIONAL ARGUMENTS: > ------------------- > -b Type of buffers to use [USERBUFFER_FLOAT, USERBUFFER_TF8, ITENSOR, USERBUFFER_TF16] (ITENSOR is default). > -q Specifies to use static quantization parameters from the model instead of input specific quantization [true, false]. Used in conjunction with USERBUFFER_TF8. > -r The runtime to be used [gpu, dsp, aip, cpu] (cpu is default). > -u Path to UDO package with registration library for UDOs. > Optionally, user can provide multiple packages as a comma-separated list. > -z The maximum number that resizable dimensions can grow into. > Used as a hint to create UserBuffers for models with dynamic sized outputs. Should be a positive integer and is not applicable when using ITensor. > -c Enable init caching to accelerate the initialization process of SNPE. Defaults to disable. > -l Specifies the order of precedence for runtime e.g cpu_float32, dsp_fixed8_tf etc. Valid values are:- > cpu_float32 (Snapdragon CPU) = Data & Math: float 32bit > gpu_float32_16_hybrid (Adreno GPU) = Data: float 16bit Math: float 32bit > dsp_fixed8_tf (Hexagon DSP) = Data & Math: 8bit fixed point Tensorflow style format > gpu_float16 (Adreno GPU) = Data: float 16bit Math: float 16bit > cpu (Snapdragon CPU) = Same as cpu_float32 > gpu (Adreno GPU) = Same as gpu_float32_16_hybrid > dsp (Hexagon DSP) = Same as dsp_fixed8_tf > Copy to clipboard > > > Running the snpe-sample assumes [Running the > Inception v3 Model](https://docs.qualcomm.com/doc/80-63442-2/topic/tutorial_inceptionv3.html) has been > previously setup. > > > Run **snpe-sample** with the AlexNet model: > > > cd $SNPE_ROOT/examples/Models/InceptionV3/data > $SNPE_ROOT/examples/SNPE/NativeCpp/SampleCode_CPP/obj/local/x86_64-linux-clang/snpe-sample -b ITENSOR -d ../dlc/inception_v3.dlc -i target_raw_list.txt -o output > Copy to clipboard > > > The results are stored in the output directory. To process the > output run the following script to generate the classifiscation > results. > > > python3 $SNPE_ROOT/examples/Models/InceptionV3/scripts/show_inceptionv3_classifications.py -i target_raw_list.txt -o output/ -l imagenet_slim_labels.txt > Classification results > cropped/notice_sign.raw 0.167454 459 brass > cropped/plastic_cup.raw 0.990612 648 measuring cup > cropped/chairs.raw 0.382222 832 studio couch > cropped/trash_bin.raw 0.684572 413 ashcan > Copy to clipboard > > > Building and Running on ARM Android > > > **Prerequisite:** You will need the Android NDK to build the > Android C++ executable. The tutorial assumes that you can > invoke ‘ndk-build’ from the shell. > > > To build snpe-sample with clang Qualcomm® Neural Processing SDK binaries (i.e., > aarch64-android), use the following command: > > > cd $SNPE_ROOT/examples/SNPE/NativeCpp/SampleCode_CPP > ndk-build NDK_TOOLCHAIN_VERSION=clang APP_STL=c++_static NDK_PROJECT_PATH=. NDK_APPLICATION_MK=Application.mk APP_BUILD_SCRIPT=Android.mk > Copy to clipboard > > > The ndk-build command will build arm64-v8a binaries of snpe-sample. > > - $SNPE\_ROOT/examples/SNPE/NativeCpp/SampleCode\_CPP/obj/local/arm64-v8a/**snpe-sample** > > > > To run the Android C++ executable, push the appropriate Qualcomm® Neural Processing SDK > libraries and the executable onto the Android target. > > > export SNPE_TARGET_ARCH=aarch64-android > export SNPE_TARGET_DSPARCH=hexagon-v73 > adb shell "mkdir -p /data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/bin" > adb shell "mkdir -p /data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/lib" > adb shell "mkdir -p /data/local/tmp/snpeexample/dsp/lib" > adb push $SNPE_ROOT/lib/$SNPE_TARGET_ARCH/*.so /data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/lib > adb push $SNPE_ROOT/lib/$SNPE_TARGET_DSPARCH/unsigned/*.so /data/local/tmp/snpeexample/dsp/lib > adb push $SNPE_ROOT/examples/SNPE/NativeCpp/SampleCode_CPP/obj/local/arm64-v8a/snpe-sample /data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/bin > Copy to clipboard > > > Run **snpe-sample** with the Inception v3 model on the target. This > assumes that you have done the setup steps for running [Run on > Android Target](https://docs.qualcomm.com/doc/80-63442-2/topic/tutorial_inceptionv3.html#run-on-target-platform) > to push to the target all the sample data files and Alexnet > model. > > > adb shell > export SNPE_TARGET_ARCH=aarch64-android > export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/lib > export PATH=$PATH:/data/local/tmp/snpeexample/$SNPE_TARGET_ARCH/bin > cd /data/local/tmp/inception_v3 > snpe-sample -b ITENSOR -d inception_v3.dlc -i target_raw_list.txt -o output_sample > exit > Copy to clipboard > > > Pull the target output into a host side output directory. > > > cd $SNPE_ROOT/examples/Models/InceptionV3 > adb pull /data/local/tmp/inception_v3/output_sample output_sample > Copy to clipboard > > > Again, we can run the interpret script to see the classification results. > > > python3 $SNPE_ROOT/examples/Models/InceptionV3/scripts/show_inceptionv3_classifications.py -i data/target_raw_list.txt -o output_sample/ -l data/imagenet_slim_labels.txt > Classification results > cropped/notice_sign.raw 0.167454 459 brass > cropped/plastic_cup.raw 0.990612 648 measuring cup > cropped/chairs.raw 0.382221 832 studio couch > cropped/trash_bin.raw 0.684573 413 ashcan > Copy to clipboard > > > Building and running on Linux (Yocto Based) > > > > - **Prerequisite:** This assumes that [Tutorials Setup](https://docs.qualcomm.com/doc/80-63442-2/topic/tutorial_setup.html) has been completed. > - For those devices which have Yocto based Linux OS, GCC compiler needs to be used to build the sample source code. > To support Yocto Kirkstone based devices, libraries are compiled with gcc11.2. Please refer below steps for building SNPE sample app: > > > > > export SNPE_ROOT=/path/to/extracted/snpe-sdk > cd ${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode_CPP/ > export AARCH64_LINUX_OE_GCC_112=/path/to/extracted/toolchain > make CXX="/tmp/sysroots/x86_64/usr/bin/aarch64-qcom-linux/aarch64-qcom-linux-g++ > --sysroot=/tmp/sysroots/qcm6490" -f Makefile.aarch64-oe-linux-gcc11.2 > Copy to clipboard > > > After executing make from above, you should be able to see two new folders in the same directory: > > 1. bin: contains *snpe-sample* binaries for each platform within respective directories. > 2. obj: contains all the object files that were used for building and linking the executable. > > > > To delete all the artifacts that were generated in the above step, run: cd ${SNPE_ROOT}/examples/SNPE/NativeCpp/SampleCode_CPP make clean Copy to clipboard To run the snpe-sample C++ executable, push the appropriate Qualcomm® Neural Processing SDK libraries and the executable i.e., aarch64-oe-linux-gcc11.2 onto the target. Run snpe-sample using below command: snpe-sample -b ITENSOR -d -i -o output_sample Copy to clipboard Last Published: Oct 02, 2025 [Previous Topic Code Examples](https://docs.qualcomm.com/bundle/publicresource/80-63442-2/topics/usergroup8.md) [Next Topic C Tutorial - Build the Sample](https://docs.qualcomm.com/bundle/publicresource/80-63442-2/topics/c_tutorial.md)