I have a CodeLite Workspace containing two projects. The first project consists of one *.c and one *.h file. They contain C-language global constants, variables, and functions. This project is compiled into a dll. The second project is a C++ main program. It is compiled into an exe. The main program references the variables and calls the functions in the dll.
My problem is that I get "undefined reference" error messages for the variables, but not for the constants (#defines) and functions. The constants and functions appear to be fine. Why am I getting those errors for the variables, but not the constants and functions? And how do I get rid of the errors?
There are many posts on Stack Overflow and on the CodeLite forums from people with similar situations. When I understand the answers to their posts, and I implement the solutions to those posts, either they don't fix my problem, or they make it worse.
Here are my files and other data.
Software Versions:
CodeLite: 9.1.8
tdm-gcc: 5.1.0.3
Windows 7: 6.1
wxCrafter: 2.5
wxWidgets: 3.1.0
Target platform: 32-bit
Target build: debug
g_memory.c
#include <limits.h>
#include <string.h>
#include "g_memory.h"
// Set Up Compiler Options
#define CALL_TYPE __stdcall
#ifndef UNICODE
#define UNICODE
#endif
int g_Carbon;
char g_Element_Name [g_ST_LENGTH];
int g_Periodic_Table [g_QTY_ELEMENTS];
// *************************************************************************
// G e t _ g _ P e r i o d i c _ T a b l e
// *************************************************************************
DllExport void CALL_TYPE Get_g_Periodic_Table (int New_Values [], int Length)
{
int i = 0;
for (i = 0; i < Length; ++i)
New_Values [i] = g_Periodic_Table [i];
}
DllExport void CALL_TYPE Set_g_Periodic_Table (int New_Values [], int Length)
{
int i = 0;
for (i = 0; i < Length; ++i)
g_Periodic_Table [i] = New_Values [i];
}
// *************************************************************************
// G e t _ g _ E l e m e n t _ N a m e
// *************************************************************************
// DllExport char CALL_TYPE Get_g_Element_Name (void) { return (g_Element_Name); }
// DllExport void CALL_TYPE Set_g_Element_Name (char * New_Value) { g_Element_Name = New_Value; }
//
// char g_Element_Name [g_ST_LENGTH];
// *************************************************************************
G e t _ g _ C a r b o n
// *************************************************************************
DllExport int CALL_TYPE Get_g_Carbon (void) { return (g_Carbon); }
DllExport void CALL_TYPE Set_g_Carbon (int New_Value) { g_Carbon = New_Value; }
// *************************************************************************
// g _ S u m
// *************************************************************************
DllExport int CALL_TYPE g_Sum (int n1, int n2)
{
int Sum = 0;
long long l_Sum = 0;
l_Sum = (long long) n1 + (long long) n2;
if ((l_Sum < INT_MIN) || (INT_MAX < l_Sum))
Sum = 0; // out of range = true
else
Sum = (int) l_Sum; // sum is in range
return (Sum);
}
// *************************************************************************
// g _ I n i t i a l i z e
// *************************************************************************
DllExport int CALL_TYPE g_Initialize (int *g_Carbon,
char g_Element_Name [],
int Debug_ST_LENGTH,
int g_Periodic_Table [],
int Periodic_Table_Length)
{
int i = 0;
*g_Carbon = 3;
memset (g_Element_Name, '\0', Debug_ST_LENGTH);
strcpy (g_Element_Name, "abc");
for (i = 0; i < Periodic_Table_Length; ++i)
g_Periodic_Table [i] = i * 2 + 6;
return ((int) g_ZERO);
}
g_memory.h
#ifndef G_MEMORY_H
#define G_MEMORY_H
#define DllImport __declspec(dllimport)
#define DllExport __declspec(dllexport)
#define CALL_TYPE __stdcall
#define g_ST_LENGTH 255
#define g_QTY_ELEMENTS 5
#define g_ZERO 0
// Variable declarations. ------------------------------------------------------
extern int g_Carbon;
extern char g_Element_Name [g_ST_LENGTH];
extern int g_Periodic_Table [g_QTY_ELEMENTS];
// Function declarations. ------------------------------------------------------
#ifdef __cplusplus
extern "C"
{
#endif // begin C-language declarations
extern DllExport int CALL_TYPE g_Sum (int n1, int n2);
extern DllExport int CALL_TYPE g_Initialize (int *g_Carbon,
char g_Element_Name [],
int Debug_ST_LENGTH,
int g_Periodic_Table [],
int Periodic_Table_Length);
extern DllExport void CALL_TYPE Get_g_Periodic_Table (int New_Values [], int Length);
extern DllExport void CALL_TYPE Set_g_Periodic_Table (int New_Values [], int Length);
extern DllExport int CALL_TYPE Get_g_Carbon (void);
extern DllExport void CALL_TYPE Set_g_Carbon (int New_Value);
#ifdef __cplusplus
}
#endif // end of C-language declarations
#endif // G_MEMORY_H
main.cpp
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "g_memory.h"
int main(int argc, char **argv)
{
int A1 = g_ZERO;
int A2 = g_ZERO;
int i = g_ZERO;
int rc = g_ZERO;
int Sum = g_ZERO;
int local_Periodic_Table [g_QTY_ELEMENTS];
printf("You're doing great!!!\n");
// -------------------------------------------------------------------------
// Part 1: Testing the Variables and #defines.
// -------------------------------------------------------------------------
Set_g_Carbon (g_ZERO);
printf("\nAFTER STEP 1: global variable g_Carbon = %d (should be 0).\n", Get_g_Carbon());
rc = g_Initialize (&g_Carbon,
g_Element_Name,
g_ST_LENGTH,
g_Periodic_Table,
g_QTY_ELEMENTS);
printf("\nAFTER STEP 2: rc from g_Initialize = %d; global variable g_Carbon = %d (should be 3).\n", rc, Get_g_Carbon());
for (i = 0; i < g_QTY_ELEMENTS; ++i)
{
local_Periodic_Table [i] = g_QTY_ELEMENTS - i;
printf (" local_Periodic_Table [%d] = %d.\n", i, local_Periodic_Table [i]);
}
// Set the global array to the contents of the local array.
Set_g_Periodic_Table(local_Periodic_Table, g_QTY_ELEMENTS);
for (i = 0; i < g_QTY_ELEMENTS; ++i)
{
g_Periodic_Table [i] = g_QTY_ELEMENTS - i;
printf (" g_Periodic_Table [%d] = %d.\n", i, g_Periodic_Table [i]);
}
// Set the global array to the contents of the local array.
Set_g_Periodic_Table(local_Periodic_Table, g_QTY_ELEMENTS);
memset (local_Periodic_Table, 0, sizeof(int) * g_QTY_ELEMENTS); // Clear the local array.
printf ("\nAfter clearing local_Periodic_Table to g_ZERO, here's what's in it:\n");
for (i = 0; i < g_QTY_ELEMENTS; ++i)
{
printf (" local_Periodic_Table [%d] = %d.\n", i, local_Periodic_Table [i]);
}
// Put the global array contents into the local array.
Get_g_Periodic_Table(local_Periodic_Table, g_QTY_ELEMENTS);
printf ("\nAfter loading local_Periodic_Table with the contents of g_Periodic_Table, here's what's in local_Periodic_Table:\n");
for (i = 0; i < g_QTY_ELEMENTS; ++i)
{
printf (" local_Periodic_Table [%d] = %d.\n", i, local_Periodic_Table [i]);
}
Set_g_Carbon (7);
printf("\nAFTER STEP 3: global variable g_Carbon = %d (should be 7).\n", Get_g_Carbon());
Set_g_Carbon (Get_g_Carbon() + 4);
printf("\nAFTER STEP 4: global variable g_Carbon = %d (should be 11).\n", Get_g_Carbon());
// g_Element_Name [0] = 'o';
// g_Element_Name [1] = 'k';
// g_Element_Name [2] = '!';
// g_Element_Name [3] = '\0';
// printf("\n\nglobal variable g_Element_Name = <%s>.\n\n", g_Element_Name);
// fflush(stdout);
// Part 2: Testing the function calls.
A1 = 5;
A2 = 11;
printf ("--- Ordinary Math Check -------------------------------------\n");
Sum = g_Sum(A1, A2);
printf("%d + %d = %d\n\n", A1, A2, Sum);
// Underflow check 1: the sum == Minimum value (valid)
//
// ---O==================================|---
// min max
A1 = -INT_MAX;
A2 = -1;
printf ("--- Underflow Check 1: valid --------------------------------\n");
Sum = g_Sum(A1, A2);
printf("%d + %d = %d\n\n", A1, A2, Sum);
// Underflow check 2: the sum < Minimum value (invalid)
//
// --O|==================================|---
// min max
A2 = -2;
printf ("--- Underflow Check 2: invalid ------------------------------\n");
Sum = g_Sum(A1, A2);
printf("%d + %d = %d\n\n", A1, A2, Sum);
// Overflow check 1: the sum == Maximum value (valid)
//
// ---|==================================O---
// min max
A1 = INT_MAX;
A2 = 1;
printf ("--- Overflow Check 1: valid ---------------------------------\n");
Sum = g_Sum(A1, A2);
printf("%d + %d = %d\n\n", A1, A2, Sum);
// Overflow check 2: the sum > Maximum value (invalid)
//
// ---|==================================|O--
// min max
A2 = 2;
printf ("--- Overflow Check 2: invalid -------------------------------\n");
Sum = g_Sum(A1, A2);
printf("%d + %d = %d\n\n", A1, A2, Sum);
fflush(stdout);
return 0;
}
Results of Compile and Link
C:\Windows\system32\cmd.exe /C C:/TDM-GCC-32/bin/mingw32-make.exe -e -f "Globals.mk" MakeIntermediateDirs && C:/TDM-GCC-32/bin/mingw32-make.exe -e -f "Globals.mk" all
----------Building project:[ Globals - Debug ]----------
C:/TDM-GCC-32/bin/gcc.exe -c "F:/Prototypes_CPP_Console_Only/GlobalVariableTests2/Globals/g_memory.c" -g -O0 -Wall -o ./Debug/g_memory.c.o -I. -I../include/ -I. -I../include/
gcc -shared -fPIC -o ../RunFromHere/Globals.dll @"Globals.txt" -L. -L../RunFromHere/
====0 errors, 0 warnings====
C:\Windows\system32\cmd.exe /C C:/TDM-GCC-32/bin/mingw32-make.exe -e -f "MainProg.mk" MakeIntermediateDirs && C:/TDM-GCC-32/bin/mingw32-make.exe -e -f "MainProg.mk" all
----------Building project:[ MainProg - Debug ]----------
C:/TDM-GCC-32/bin/g++.exe -c "F:/Prototypes_CPP_Console_Only/GlobalVariableTests2/MainProg/main.cpp" -g -O0 -Wall -o ./Debug/main.cpp.o -I. -I../include/ -I.
C:/TDM-GCC-32/bin/mingw32-g++.exe -o ../RunFromHere/MainProg @"MainProg.txt" -L. -L../RunFromHere/ -L. -L../RunFromHere/ -lGlobals
./Debug/main.cpp.o: In function `main':
F:/Prototypes_CPP_Console_Only/GlobalVariableTests2/MainProg/main.cpp:29: undefined reference to `g_Periodic_Table'
F:/Prototypes_CPP_Console_Only/GlobalVariableTests2/MainProg/main.cpp:29: undefined reference to `g_Element_Name'
F:/Prototypes_CPP_Console_Only/GlobalVariableTests2/MainProg/main.cpp:29: undefined reference to `g_Carbon'
F:/Prototypes_CPP_Console_Only/GlobalVariableTests2/MainProg/main.cpp:44: undefined reference to `g_Periodic_Table'
F:/Prototypes_CPP_Console_Only/GlobalVariableTests2/MainProg/main.cpp:45: undefined reference to `g_Periodic_Table'
collect2.exe: error: ld returned 1 exit status
mingw32-make.exe: *** [../RunFromHere/MainProg] Error 1
MainProg.mk:81: recipe for target '../RunFromHere/MainProg' failed
====5 errors, 0 warnings====
Thank you in advance!