I have some table of structs that get compiled differently depending on what driver I am using. I want to be able to check if a certain driver has been compiled (or by relation, if its table is defined).
I've look all over but I can't seem to find a way to determine if a declared extern variable has been defined or if there's some way to check if a c source file has been compiled (and linked) within a given application. I had looked at using some macro magic like the container_of macro however I've so far come up short.
for example say I have the following:
checkFile.c
#include "neutral.h"
#include "fileA.h"
#include "fileB.h"
bool setTable(int type, someStruct_t *table) {
/*
This doesn't work
fails to compile with:
undefined reference to fileA_Table
ironically this is what I'm trying to check
*/
switch (type) {
case FILEA:
if (fileA_Table) {
someTable = &fileA_Table;
return true;
}
else {
someTable = NULL;
return false;
}
break;
case FILEB:
if (fileB_Table) {
someTable = &fileB_Table;
return true;
}
else {
someTable = NULL;
return false;
}
break;
default:
someTable = NULL;
return false;
}
}
neutral.h
typedef struct {
int memberA;
bool memberB;
} someStruct_t;
extern someStruct_t fileA_table[];
extern someStruct_t fileB_table[];
fileA.c
#include "neutral.h"
someStruct_t fileA_table[] = {
{
.memberA = 0;
.memberB = false;
},
{
.memberA = 5;
.memberB = false;
}
}
fileB.c
#include "neutral.h"
someStruct_t fileB_table[] = {
{
.memberA = 14;
.memberB = true;
},
{
.memberA = 5;
.memberB = true;
}
}
I'm not even sure that this is something that I can do in C and really the fundamental problem I'm trying to solve is initializing some type of interface that relies on fileA or fileB and ensuring which arrays are available to use from fileA and/or fileB. Note this
Ideally I'd actually like if I could just use file_table but I don't think that's possible if both fileA and fileB are compiled.
Note this should work regardless of if fileA or fileB or both files are compiled.
Any help is much appreciated.
Based on Bill Lynch's suggestion I looked into strong and weak symbols here and here and found an appealing solution. Roughly this is what I came up with.
checkFile.c
#include "neutral.h"
#include "fileA.h"
#include "fileB.h"
bool setTable(int type, someStruct_t *table) {
/*
* This will compile and if fileA_table has not been
* defined in fileA then it will evaluate to 0
*/
switch (type) {
case FILEA:
if (fileA_Table) {
someTable = &fileA_Table;
return true;
}
else {
someTable = NULL;
return false;
}
break;
case FILEB:
if (fileB_Table) {
someTable = &fileB_Table;
return true;
}
else {
someTable = NULL;
return false;
}
break;
default:
someTable = NULL;
return false;
}
}
neutral.h
typedef struct {
int memberA;
bool memberB;
} someStruct_t;
__attribute__((weak)) extern someStruct_t fileA_table[];
__attribute__((weak)) extern someStruct_t fileB_table[];
fileA.c
#include "neutral.h"
someStruct_t fileA_table[] = {
{
.memberA = 0;
.memberB = false;
},
{
.memberA = 5;
.memberB = false;
}
}
fileB.c
#include "neutral.h"
someStruct_t fileB_table[] = {
{
.memberA = 14;
.memberB = true;
},
{
.memberA = 5;
.memberB = true;
}
}
I like this since it meant I could get the results I want with minimal impact to my interface and no impact to compiler options/commands.
I would have liked to use the same symbol for fileA and fileB to make the generic interface layer and the neutral header cleaner to get something like this:
neutral.h
typedef struct {
int memberA;
bool memberB;
} someStruct_t;
__attribute__((weak)) extern someStruct_t file_table[];
checkFile.c
#include "neutral.h"
#include "fileA.h"
#include "fileB.h"
bool setTable(int type, someStruct_t *table) {
if (file_Table) {
someTable = &file_table;
return true;
}
someTable = NULL;
return false;
}
This could be done so long as we compile the interface starting at checkFile.c as two seperate binaries. Once linking with fileA.c and once with fileB.c. This does add some complexity in build options, increases code size, and I'm not sure of the impact to performance however it makes the code more maintainable and much more so should there be several potential files and several types of tables that need to be checked.