0

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!

  • Too bad the OP will have no way to ascertain from the duplicate what the solution to her problem is given the complexity of the answer. – KevinDTimm Jun 22 '16 at 13:48
  • You have the following in your `.h` file: `extern int variableName;` This file is included in each of your source files. So, you have declared them `extern` in all source files. At least one source file must leave out the `extern`, so you'll need to have a `#define` in one source file that removes the `extern`. – KevinDTimm Jun 22 '16 at 13:48
  • @Sourav Ghosh: please provide a link to the post that my question is a duplicate of. – Colleen Kobe Jun 22 '16 at 14:02
  • See [this question & answer](http://stackoverflow.com/questions/19373061/what-happens-to-global-and-static-variables-in-a-shared-library-when-it-is-dynam) for exporting global variables. Note the platform dependent territory. – sendaran Jun 22 '16 at 14:05
  • @ColleenKobe See top of the post. Welcome. :) – Sourav Ghosh Jun 22 '16 at 14:31
  • This cannot be quite your *real* code. In `g_memory.c`, the text ` G e t _ g _ C a r b o n` is not within comments and is not legal C. As your problem is a linkage problem, please post compilable source files from which you know it can be reproduced. – Mike Kinghan Jun 22 '16 at 14:34
  • @KevinDTimm, thanks. I made the following changes. I created a new file called g_constantsonly.h I copied the #define statements in g_memory.h into g_constantsonly.h. In g_memory.h: I deleted the #define statements. I added the statement: `#include "g_constantsonly.h"` In g_memory.c: I deleted the statement: `#include "g_memory.h"` I added the statement: `#include "g_constantsonly.h"` I did not modify main.cpp. I "clean"ed the workspace and then ran a Rebuild. I'm still getting the same undefined reference messages. :-( – Colleen Kobe Jun 22 '16 at 15:17
  • There's not room to help you here as your question was closed. If you read every word of the `duplicate` you will see what you're doing wrong. Essentially you need to have an `#define` that allows all files but one to have `extern` defined in your include file and then no `extern` in one source file. Sorry - I know what I want to say but cannot elucidate in this format. Search for a subset of your title using a search engine, you should be able to find a good example that way. – KevinDTimm Jun 22 '16 at 15:56

0 Answers0