This Gist compares five different approaches demonstrated in various GitHub repositories for integrating C/C++ code with Scilab on Windows using the MinGW-w64 GCC compiler toolchain. The goal is to understand the trade-offs and identify potentially clean, concise, and canonical methods.
Repositories Analyzed:
- Foadsf/scilab-c-cpp-mingw-example
- Foadsf/scilab-mingw-c-gateway-mwe
- Foadsf/minimal-scilab-c-gateway
- Foadsf/scilab-mingw-module (Note: URL points to
my_foo6
, seems related) - Foadsf/scilab-mingw-c-call-minimal-example
Common Challenge: Scilab's built-in ilib_build
function (as of Scilab 2024.0.0) is primarily designed for MSVC on Windows and does not reliably support MinGW-w64 GCC out-of-the-box. This necessitates manual compilation steps (typically via batch scripts) in most examples.
Feature | scilab-c-cpp-mingw-example |
scilab-mingw-c-gateway-mwe |
minimal-scilab-c-gateway |
scilab-mingw-module (my_foo6 ) |
scilab-mingw-c-call-minimal-example |
---|---|---|---|---|---|
Core Method | C Function + C++ Gateway (api_scilab ) |
C Library + C++ Gateway (api_scilab ) |
C Function + C++ Gateway (api_scilab ) |
C Gateway Function + C++ Entry Point (api_scilab ) |
Direct C Function Call (No Gateway) |
Build Process | Manual (.bat script, gcc /g++ ) |
Manual (.bat script, gcc /g++ ) |
Manual (.bat script, gcc /g++ ) |
Manual (.bat script, gcc /g++ , uses ilib_gen_loader first) |
Manual (.bat script, gcc ) |
Scilab Integration | exec('loader.sce') -> addinter (Static loader.sce ) |
Direct addinter in test script |
Direct addinter in test script |
exec('loader.sce') -> addinter (Generated loader.sce ) |
link() + call() |
Complexity | Moderate | Moderate | Moderate | High (due to build complexity, stubs, many libs) | Low |
Requires C++ Gateway? | Yes | Yes | Yes | Yes (for the entry point build_lib ) |
No |
Dummy Headers Needed? | Yes (sci_mem_alloc.h , gw_macros.h ) |
Yes (sci_mem_alloc.h , gateway_c.h ) |
Yes (sci_mem_alloc.h , gateway_c.h ) |
Yes (sci_mem_alloc.h , gateway_c.h implied via build_lib.h -> c_gateway_prototype.h ) |
No |
Linker Stubs Needed? | No (simple example) | No (simple example) | No (simple example) | Yes (stubs.c for libintl_gettext ) |
No |
Key Files | simple.c , gateway.cpp , loader.sce , build_and_run.bat |
minimal_lib.c , minimal_gateway.cpp , run_example.sce , build_and_run.bat |
simple_c_function.c , gateway.cpp , load_and_test.sce , build_and_run.bat |
sci_foo6.c , build_lib.cpp , stubs.c , generate_loader.sce , build_and_run.bat , test_foo6.sce |
simple_math.c /.h , run_example.sce , build_and_run.bat |
Pros | Clear README, Robust static loader, good troubleshooting notes. | Clean separation of C lib/gateway, direct addinter . |
Similar to mwe , simple example. |
Attempts official toolbox structure, handles complex types (matrices). | Simplest method, no C++ gateway, no Scilab API in C code, minimal linking dependencies for DLL. |
Cons/Notes | Manual build, requires dummy headers, -fpermissive used. |
Manual build, requires dummy headers. | Manual build, requires dummy headers. | ilib_build approach fails, complex manual build, requires linker stubs, links many Scilab libs. |
Requires specific C signature (pass-by-reference, _ suffix), call() syntax verbose. |
Based on the comparison, here's an analysis of the different approaches:
-
link()
/call()
Method (scilab-mingw-c-call-minimal-example
)- Simplicity: This is by far the simplest method. It avoids the Scilab C API (
api_scilab
) entirely within the C code, eliminates the need for a C++ gateway, and requires minimal linking. The build process is straightforward. - Constraints: It imposes strict requirements on the C function signature: Fortran-style naming (trailing underscore) and pass-by-reference for all arguments. The Scilab
call()
syntax is verbose and less intuitive than calling a normally registered function. - Best For: Very simple C functions (like basic math operations) where minimal integration effort is desired, and the constraints on the C signature and the verbose
call()
syntax are acceptable.
- Simplicity: This is by far the simplest method. It avoids the Scilab C API (
-
Gateway (
addinter
) Methods (The other four examples)- Canonicity: Using a gateway function (
sci_...
) and registering it viaaddinter
is the canonical Scilab way to integrate external code, especially for building toolboxes. It allows the C/C++ function to be called in Scilab just like any built-in function. - Flexibility: This approach is much more flexible in handling various Scilab data types (matrices, strings, lists, etc.) and allows for more complex logic within the gateway (argument checking, type conversion, memory management).
- Complexity: Requires understanding the
api_scilab
, writing C++ gateway boilerplate, managing dummy headers (due to MinGW/Scilab distribution limitations), and handling a more complex manual build process involving linking against multiple Scilab libraries.
- Canonicity: Using a gateway function (
-
Variations within Gateway Methods:
- Build Process: All gateway examples require manual compilation scripts (
.bat
) becauseilib_build
fails with MinGW. The complexity varies (my_foo6
being the most complex due to more features and linker issues). - Loader (
addinter
Call):- Direct Call:
scilab-mingw-c-gateway-mwe
andminimal-scilab-c-gateway
calladdinter
directly within the main test/usage script. This is simple for minimal examples. - Generated Loader:
scilab-mingw-module
(my_foo6
) uses Scilab'silib_gen_loader
to createloader.sce
. This aligns more closely with the standard toolbox build process but adds a Scilab execution step to the build. - Static Loader:
scilab-c-cpp-mingw-example
uses a handwritten, staticloader.sce
. This avoids the Scilab generation step and is robust, but requires manual updates if function names/DLL paths change.
- Direct Call:
- Dummy Headers/Stubs: All gateway examples require dummy headers (
sci_mem_alloc.h
,gateway_c.h
/gw_macros.h
) to satisfy includes expected by Scilab's API headers when compiling standalone with MinGW. Complex examples likemy_foo6
might also need linker stubs (stubs.c
) to resolve symbols (likelibintl_gettext
) when linking MinGW-compiled code with Scilab's MSVC-built libraries.
- Build Process: All gateway examples require manual compilation scripts (
- For utmost simplicity and minimal C functions: The
link()
/call()
method (scilab-mingw-c-call-minimal-example
) is the most direct and requires the least effort, provided you adhere to its C function signature constraints and accept the verbosecall()
syntax in Scilab. - For standard Scilab integration, toolbox development, or handling complex data types: The Gateway (
addinter
) method is necessary. Given theilib_build
limitations with MinGW:- A manual build script (
.bat
) is unavoidable. - Dummy headers are required.
- Among the gateway examples:
scilab-c-cpp-mingw-example
offers a well-documented approach with a robust static loader, making it a good, practical starting point.scilab-mingw-c-gateway-mwe
demonstrates the slightly simpler directaddinter
call, suitable if a separate loader script isn't desired for a simple project.scilab-mingw-module
(my_foo6
) shows the complexities encountered when trying to replicate the full toolbox structure manually, including linker stubs, making it a valuable reference for troubleshooting but perhaps overly complex as a starting point.
- A manual build script (
Recommendation for Future Self / Others:
- If the C function is simple and can easily conform to the pass-by-reference/underscore suffix convention, start with
scilab-mingw-c-call-minimal-example
for its simplicity. - Otherwise, for a more standard and flexible Scilab integration, use the gateway approach.
scilab-c-cpp-mingw-example
provides a practical and well-explained template for manual MinGW compilation with a robust static loader. Adapt its build script and gateway structure for your needs. Be prepared to manage dummy headers and potentially linker stubs for more complex dependencies.