Working with Methods > Overview > Using External C Libraries

Using External C Libraries
To use a library in your application, you need to call it from a method or a utility class. Use the External external(String libraryTag) method available in the ApplicationMethod class or the ApplicationLanguageBase class. It returns an object of type External with the following methods:
The syntax could be:
length = external("native1").invoke("stringLength", "Foo");
which assumes a C function declared as int stringLength(char *str). Alternatively, you could use the following code:
External library = external("native");
seven = library.invoke("sum", 3, 4);
two = library.invoke("sum", 3, -1);
library.close();
which assumes a C function declared as int sum(int a, int b). The latter syntax is more efficient if you need to make several calls to the same library.
Supported Argument Types
Methods can have up to six arguments and may (optionally) return an integer (or native pointer) value, which is a 64-bit value on 64-bit platforms. In Java, the return value is always a long.
Not all argument types are supported, and some restrictions apply. In particular, float arguments are converted to double arguments; the native function must not be declared having float arguments. If you need to transfer data of the float type, you can instead use a float array, which is supported.
const char * or
const whcar_t *
char ** or
wchar_t **
For array types, the external function can modify the values in the supplied array. The updated values are transferred back to the Java program. Note that it is not possible for the callee to change the size of a transferred array. The caller and callee are responsible for communicating the size, by using an extra argument or by a convention. If the callee writes or reads memory outside the allocated buffer, the program behavior is undefined but may include an abrupt program exit. Note that for the double array types, only values may be modified, not any pointers.
For arguments of type String[], the program can modify a pointer in the array of pointers to point to a new null-terminated string, which is transferred back to Java. The maximal allowed length of a string is 65,535 characters. Use a byte array to transfer larger amounts of data. It is possible to return a null value to Java by setting the corresponding element in the string array to 0.
More complex types need to be serialized on the Java side to a byte array, which can be deserialized by the callee.
The external function can return an integer (int) or a pointer to some internal object (void *). In Java, this value is returned as a long value, which is sufficiently wide to hold a 64-bit memory address. If you need a String or a double as return value, you must instead pass an array of length one and the right type, which can be filled in by the external function.
Debugging
It may be possible to use a native code debugger (like Microsoft Visual Studio®) when working with applications. First, you need to build the library with debug symbols. Then you import this library into the application, and attach the debugger to the COMSOL process. Put a break point in the native function that you want to debug. Run or test run the application in COMSOL Multiphysics. When COMSOL Multiphysics loads the external library, the debugger should be able to match the source code where you put your breakpoint with the loaded library and to break when the function is called. Please refer to the documentation of your native debugging system for further details.
Notes and Tips For Using External Libraries
Example of an External Function
The following steps show an example of how to create and import a library and then call it in methods:
1
The source code below defines a trivial external function written in C++, which you want to call. The #ifdef statement is intended to make the source code cross-platform compatible, but writing a shared library typically involves compiler-specific settings, so you may need to consult the documentation of your compiler. The header file, test.h, is as follows:
// test.h : Declares the exported function
#ifdef _MSC_VER
  #define TESTDLL_API __declspec(dllexport)
#else
  #define TESTDLL_API __attribute__((__visibility__("default")))
#endif
extern "C" {
  TESTDLL_API int testSum(int a, int b);
}
And the function definition, test.cpp, looks like:
// test.cpp : Defines the exported function for the library
#include "test.h"
 
// This is an example of an exported function.
TESTDLL_API int testSum(int a, int b) {
  return a + b;
}
Using the gcc compiler, you would type something like this in the command shell:
gcc -shared -o test.so -fPIC test.cpp
If you are using a graphical C++ build environment, like Microsoft Visual Studio, it is probably easiest to insert the code above into a DLL project.
2
Add an External C Library node, with tag native1, and import the library created in Step 1 for the right platform.
3
Add a Method node and insert the following code into the execute method body:
long sum = external("native1").invoke("testSum", 1, 2);
alert("1 + 2 = " + sum);
Add a button to the form, and choose the method added above as the command to execute. If you are building the application on the same platform the library is built for, you can click Test Application to test run the method. Otherwise, save the application and run it in a COMSOL Multiphysics session on the correct platform. In any case, when you press the button in the application window, you should see a dialog stating a truism.