Created
April 25, 2025 10:25
Revisions
-
Foadsf created this gist
Apr 25, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,66 @@ # Comparison of Scilab-MinGW C/C++ Integration Methods 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:** 1. [Foadsf/scilab-c-cpp-mingw-example](https://github.com/Foadsf/scilab-c-cpp-mingw-example) 2. [Foadsf/scilab-mingw-c-gateway-mwe](https://github.com/Foadsf/scilab-mingw-c-gateway-mwe) 3. [Foadsf/minimal-scilab-c-gateway](https://github.com/Foadsf/minimal-scilab-c-gateway) 4. [Foadsf/scilab-mingw-module](https://github.com/Foadsf/my_foo6) (Note: URL points to `my_foo6`, seems related) 5. [Foadsf/scilab-mingw-c-call-minimal-example](https://github.com/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. ## Comparison Table | 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. | ## Analysis and Recommendations Based on the comparison, here's an analysis of the different approaches: 1. **`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. 2. **Gateway (`addinter`) Methods (The other four examples)** * **Canonicity:** Using a gateway function (`sci_...`) and registering it via `addinter` 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. 3. **Variations within Gateway Methods:** * **Build Process:** All gateway examples require manual compilation scripts (`.bat`) because `ilib_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` and `minimal-scilab-c-gateway` call `addinter` directly within the main test/usage script. This is simple for minimal examples. * *Generated Loader:* `scilab-mingw-module` (`my_foo6`) uses Scilab's `ilib_gen_loader` to create `loader.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, static `loader.sce`. This avoids the Scilab generation step and is robust, but requires manual updates if function names/DLL paths change. * **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 like `my_foo6` might also need linker stubs (`stubs.c`) to resolve symbols (like `libintl_gettext`) when linking MinGW-compiled code with Scilab's MSVC-built libraries. ## Conclusion * **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 verbose `call()` syntax in Scilab. * **For standard Scilab integration, toolbox development, or handling complex data types:** The **Gateway (`addinter`)** method is necessary. Given the `ilib_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 **direct `addinter` 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. **Recommendation for Future Self / Others:** 1. 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. 2. 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.