Search code examples
cmacoslinkerldunix-ar

OS X linker unable to find symbols from a C file which only contains variables


I am having problems with the linker when porting a C library from Linux (Ubuntu) to OS X. The C code is auto-generated from Matlab, so ideally I don't want to change the code itself.

The problem seems to be in a C file which contains ONLY uninitialised variable declarations, which are then EXTERNed by other C files to implement the Matlab algorithms. The OS X linker is apparently unable to recognise symbols from this file. The same source code works fine on Linux, so I want to understand how the OS X linker is behaving differently, and whether there is a flag I can pass to it to change the behaviour.

The static library builds without errors/warnings. But when building an application which references the static library, the following error message (on OS X) is thrown:

Undefined symbols for architecture x86_64:
  "_my_var", referenced from:
      _algorithm in libtestlibrary.a(algorithm.o)
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status

An 'nm' shows that libtestlibrary.a does indeed contain symbol _my_var.

A much simplified version of the code from Matlab follows below.

Library code:

// DATA.C : declaration of data
#include "data.h"
int my_var;

// DATA.H - extern declaration of data
#ifndef H_DATA
#define H_DATA
extern int my_var;
#endif

// ALGORITHM.C - performs the calculation
#include "data.h"
int algorithm(int x) {
  my_var += x;
  return my_var;
}

//ALGORITHM.H - declaration of library API
#ifndef H_ALGORITHM
#define H_ALGORITHM
int algorithm(int x);
#endif

Library build commands:

gcc -c algorithm.c
gcc -c data.c
ar rcs libtestlibrary.a data.o algorithm.o

Application code:

// MAIN.C : Code which calls into the static library
#include "algorithm.h"
int main() {
  int x = 1;
  x = algorithm(x);
  return 0;
}

Application build commands:

gcc -c main.c
gcc -o testapp main.o -ltestlibrary

If I change the definition in data.c to 'int my_var=0', so that the variable is initialised, then the library and application build correctly on both Linux and OS X. However, as I said above, I don't want to change the code because it is auto-generated from Matlab.

Thanks in advance for your help!


Solution

  • Your problem is that you do not initialise may_var.

    If you do not initialise a data symbol and put it into a static library then it will be created as a common symbol. Those are not recognised my the OS X linker when linking static libraries.

    If you initialise it (data.c):

    #include "data.h"
    int my_var = 0;
    

    Then the compiler will put it into a different section and it will properly link in a static library.

    Edit:

    Alternatively you can pass the -fno-common option to gcc

    gcc -c data.c -fno-common
    

    Then this will instruct gcc not to generate common symbols for uninitialised variables and then you can link them in libraries.

    This is an issue with the Mach-O executable format on OS X and is described here.