I’m developing a C library for parsing configuration (.ini) files, which I plan to dynamically link with a UI created in Lazarus IDE. Currently, my C code heavily relies on global variables, as shown in this simplified example:
// Global variables in C
char nom_fichier_param[MAX_PATH_LENGTH];
char nom_fichier_parametre[MAX_NAME_LENGTH];
double temps_mesure, teta, pre_retard;
int filtre_tot, filtre_coinc;
void lecture_parametres(void) {
char s[MAX_LINE_LENGTH];
FILE *f;
int v_t;
int erreur;
CodeSortie = 0;
// Construct the full file path
snprintf(nom_fichier_param, sizeof(nom_fichier_param), "%s%s%s", chemin_param, nom_fichier_parametre, EXTENSION_PARAM);
f = fopen(nom_fichier_param, "r");
if (f == NULL) {
CodeSortie = 1;
return;
}
// Determine mode based on filename
mode = (strstr(nom_fichier_param, "A.ini") != NULL) ? 'A' : 'P';
// Skip the remaining 5 header lines
for (int l = 0; l < 5; l++) {
if (fgets(s, sizeof(s), f) == NULL) {
fprintf(stderr, "Unexpected end of filen");
fclose(f);
CodeSortie = 1;
return;
}
}
// Process "temps_mesure"
//fgets(s, sizeof(s), f);
erreur = sscanf(DSp(trimRight(strncpy(s, s + 39, 40))), "%lf", &temps_mesure);
if (erreur == 0) {
printf("ERREUR format "temps de mesure"n");
sortie(f);
return;
}
// ...
}
I’m concerned this approach might cause issues during the dynamic linking process, especially considering cross-platform compatibility.
My research suggests using structs instead of globals, but I’m unsure about the implications for Lazarus integration.
Questions:
- What are the potential pitfalls of using global variables in a C library when dynamically linking with Lazarus, particularly across different platforms?
- How can I refactor my code to use structs or another approach that ensures better compatibility and maintainability?
- What are the best practices for writing C code that will be dynamically linked with Lazarus, considering POSIX/XSI standards for portability?
- If I must retain some global variables, how should I declare and access them in Lazarus to ensure proper linking?
I’ve looked into resources on the Lazarus wiki about FFI, but haven’t found specific guidance on handling global state in dynamically linked C libraries.
Any insights, especially from those with experience in cross-platform development involving C and Lazarus, would be greatly appreciated!
Some remarks:
- Lazarus of course already comes with a working INI file library.
- Assuming that a GUI application has a console (using snprintf) is already not portable, e.g. on Windows GUI applications typically don’t have a console.
- bundling the global variables in structs doesn’t fundamentally change the global variable situation. It adds a concern for record/struct packing that must match though.
- POSIX standards have little relevance in Pascal, as they require parsing C headers, which Pascal obviously can’t. Moreover, FPC/Lazarus is portable, and works on Windows without POSIX emulation layers like cygwin/msys.
- Global variables should work see https://www.freepascal.org/docs-html/3.2.0/prog/progsu148.html#x187-1900007.1.2 . But it is probably easier to just define a few functions to set/get to avoid a potential cross platform hazard.
FPC doesn’t rely on (lib)FFI to talk to C, as Pascal is basically on the same level as C, there “just” need to be matching pascal declarations of everything you do in C.
For an more advanced list of issues see How to design a C / C++ library to be usable in many client languages?
2