Example: Using External C/C++ Functions

Write a C/C++ function that computes distances to the Event Stream Processor interface. After compiling the function to a shared library, declare it using the CREATE LIBRARY statement, and call the function as needed in your CCL project.

Prerequisites
Know the syntax and requirements for writing C/C++ functions to the interface of the Event Stream Processor.
Task
  1. Write the function, ensuring it conforms to the Event Stream Processor interface.

    For example, this function computes distance:

    #include math.h
    double distance(int numvals, double * vals){
    	double sum = 0.0;
    	for (int i=0; i<numvals; i++){
    		sum += vals[i]*vals[i];
    	}
    return sqrt(sum);
    }

    To conform to the interface of the Event Stream Processor, write the function as:

    #include <math.h>
    #include <vector>
    #include "DataValue.hpp"
    
    using namespace std;
    
    #ifdef _WIN32
    	#define __DLLEXPORT__ __declspec(dllexport)
    #else
    	#define __DLLEXPORT__
    #endif
    
    /**************************************************************
     * This function computes the distance using the given
     * arguments.
     * @numargs  - Number of arguments to this function.
     * @top      - Points to the last argument. Also holds the 
     *             return value from this function.
     * @nextArgs - The remaining arguments in the order provided.
     * @arena    - Anything assigned to the arena is freed by the
     *             the server.  NOTE: Do not assign return values
     *             to the arena.  Also anything to be freed must
     *             be allocated using malloc only (DO NOT USE new).
    *****************************************************************/
    extern "C" __DLLEXPORT__
    int32_t distance(int numargs, DataTypes::DataValue * top,
            DataTypes::DataValue * nextArgs,
            std::vector<void *>& arena){
    
        double sum = 0.0;
        if (numargs <= 0){
    		//Return value
            top->setDouble(0.0);
    
    		//Return code.
            return 0;
        }
    
    	//If any of the arguments is null result is null.
        if(top->null) return 0;
    	
    	//Top of the stack points to the last argument.
        double dist = top->val.doublev * top->val.doublev;
    
    	//Processes the arguments from last to first.
        for(int i=numargs-2; i>=0; i--){
    
    		//If any of the arguments is null result is null
            if((nextArgs+i)->null){
                top->null = true;
                return 0;
            }
    
    		//accumulate the square of the distances.
            dist +=(nextArgs + i)->val.doublev * (nextArgs + i)->val.doublev;
        }
    
    	//Return value
        top->setDouble(sqrt(dist));
    
    	//Return code.
        return 0;
    }
    
    Note: Use the setX function to set the return value, where X is the return type of the return value. Using the setX function ensures that the null flag is set to false. To set the return value to NULL, say top->null = true.

    The extern declaration ensures the function has the same name within the library and not the C++ function name.

    The __DLLEXPORT__ preprocessor macro must be defined under Windows to make the external function available to ESP.

  2. Compile the function to a shared library.
    For example, using the gcc compiler, these commands create a shared library named distance.so:
    gcc -fPIC -shared -m64 -I.. -c -o distance.o distance.cpp
    gcc -fPIC -shared -m64 distance.o -o distance.so
  3. Declare the function in the CCL project using the CREATE LIBRARY statement.
    CREATE LIBRARY DistanceLib LANGUAGE C FROM 'distance.so'(
    	float distance(float, float, float);
    );
    Note: When searching for shared libraries (.dll files), Windows checks the path of the application. If the .dll file is not found in that directory, other directories are searched, culminating in the directories specified in the PATH environment variable.

    Ensure the name of the function matches the name of the function in the library.

  4. Call the distance function in the project using DistanceLib.distance(arg1, arg2, arg3).