extern variables in static library, using Objective-C - c

I've built a static library, to be linked in my iPhone apps. This library uses some global variables and functions, like in C. My problem is, when using for example:
extern
void do_stuff (const int a)
{
return a*a;
}
extern const int a_variable;
extern const int an_array[DEFINED_VALUE];
When I use this function, or access these variables, anywhere in my code, the compiler tells me
"_do_stuff" referenced from:
-[Object testMethod] in tests.o
"_a_variable" referenced from:
-[Object testMethod] in tests.o
"_an_array" referenced from:
-[Object testMethod] in tests.o
Symbol(s) not found
Collect2: Id returned 1 exit status
Has anyone ever faced this problem before? I know I'm doing something stupid, I'm missing some key Objective-C or C concept, but I can't really see what. So I was hoping someone could help me. Thanks in advance.

These are linker errors, telling you that the referenced entities can't be found. Probably this means that you haven't added your library to the project.
As an aside, you probably should distinguish between the place where you declare these things, where they should indeed be declared as extern, and the place where you define them, where they shouldn't be. That is, you might have a header file that includes:
extern void do_stuff (const int a);
extern const int a_variable;
extern const int an_array[];
And then an implementation file that has something like:
void do_stuff (const int a)
{
return a*a;
}
const int a_variable = 42;
const int an_array[DEFINED_VALUE] = { 1, 2, 3, 4 };
As another aside, calling something a_variable when it's actually a const is a bit misleading!

#walkytalky Well I ran nm on the .a filtered with grep to see if those symbols were exported.
host-006:Release-iphonesimulator <username>$ nm -g libCardLib.a | grep CP_
nm: no name list
U _CP_BACK
U _CP_FILE_EXTENSION_SUFFIX
U _CP_FILE_PATH
U _CP_SUIT_PREFIX
U _CP_VALUE_PREFIX
00002020 D _CP_BACK
00002018 D _CP_FILE_EXTENSION_SUFFIX
0000201c D _CP_FILE_PATH
00002024 D _CP_FRONT
00002108 D _CP_SUIT_PREFIX
0000210c D _CP_VALUE_PREFIX
nm: no name list
nm: no name list
nm: no name list
So it seems that for each symbol there's an undefined copy?

Related

Why does global variable definition in C header file work? [duplicate]

This question already has answers here:
What happens if I define the same variable in each of two .c files without using "extern"?
(3 answers)
Closed 2 years ago.
From what I saw across many many stackoverflow questions among other places, the way to define globals is to define them in exactly one .c file, then declare it as an extern in a header file which then gets included in the required .c files.
However, today I saw in a codebase global variable definition in the header file and I got into arguing, but he insisted it will work. Now, I had no idea why, so I created a small project to test it out real quick:
a.c
#include <stdio.h>
#include "a.h"
int main()
{
p1.x = 5;
p1.x = 4;
com = 6;
change();
printf("p1 = %d, %d\ncom = %d\n", p1.x, p1.y, com);
return 0;
}
b.c
#include "a.h"
void change(void)
{
p1.x = 7;
p1.y = 9;
com = 1;
}
a.h
typedef struct coord{
int x;
int y;
} coord;
coord p1;
int com;
void change(void);
Makefile
all:
gcc -c a.c -o a.o
gcc -c b.c -o b.o
gcc a.o b.o -o run.out
clean:
rm a.o b.o run.out
Output
p1 = 7, 9
com = 1
How is this working? Is this an artifact of the way I've set up the test? Is it that newer gcc has managed to catch this condition? Or is my interpretation of the whole thing completely wrong? Please help...
This relies on so called "common symbols" which are an extension to standard C's notion of tentative definitions (https://port70.net/~nsz/c/c11/n1570.html#6.9.2p2), except most UNIX linkers make it work across translation units too (and many even with shared dynamic libaries)
AFAIK, the feature has existed since pretty much forever and it had something to do with fortran compatibility/similarity.
It works by the compiler placing giving uninitialized (tentative) globals a special "common" category (shown in the nm utility as "C", which stands for "common").
Example of data symbol categories:
#!/bin/sh -eu
(
cat <<EOF
int common_symbol; //C
int zero_init_symbol = 0; //B
int data_init_symbol = 4; //D
const int const_symbol = 4; //R
EOF
) | gcc -xc - -c -o data_symbol_types.o
nm data_symbol_types.o
Output:
0000000000000004 C common_symbol
0000000000000000 R const_symbol
0000000000000000 D data_init_symbol
0000000000000000 B zero_init_symbol
Whenever a linker sees multiple redefinitions for a particular symbol, it usually generates linkers errors.
But when those redefinitions are in the common category, the linker will merge them into one.
Also, if there are N-1 common definitions for a particular symbol and one non-tentative definition (in the R,D, or B category), then all the definitions are merged into the one nontentative definition and also no error is generated.
In other cases you get symbol redefinition errors.
Although common symbols are widely supported, they aren't technically standard C and relying on them is theoretically undefined behavior (even though in practice it often works).
clang and tinycc, as far as I've noticed, do not generate common symbols (there you should get a redefinition error). On gcc, common symbol generation can be disabled with -fno-common.
(Ian Lance Taylor's serios on linkers has more info on common symbols and it also mentions how linkers even allow merging differently sized common symbols, using the largest size for the final object: https://www.airs.com/blog/archives/42 . I believe this weird trick was once used by libc's to some effect)
That program should not compile (well it should compile, but you'll have double definition errors in your linking phase) due to how the variables are defined in your header file.
A header file informs the compiler about external environment it normally cannog guess by itself, as external variables defined in other modules.
As your question deals with this, I'll try to explain the correct way to define a global variable in one module, and how to inform the compiler about it in other modules.
Let's say you have a module A.c with some variable defined in it:
A.c
int I_am_a_global_variable; /* you can even initialize it */
well, normally to make the compiler know when compiling other modules that you have that variable defined elsewhere, you need to say something like (the trick is in the extern keyword used to say that it is not defined here):
B.c
extern int I_am_a_global_variable; /* you cannot initialize it, as it is defined elsewhere */
As this is a property of the module A.c, we can write a A.h file, stating that somewhere else in the program, there's a variable named I_am_a_global_variable of type int, in order to be able to access it.
A.h
extern int I_am_a_global_variable; /* as above, you cannot initialize the variable here */
and, instead of declaring it in B.c, we can include the file A.h in B.c to ensure that the variable is declared as the author of B.c wanted to.
So now B.c is:
B.c
#include "A.h"
void some_function() {
/* ... */
I_am_a_global_variable = /* some complicated expression */;
}
this ensures that if the author of B.c decides to change the type or the declaration of the variable, he can do changing the file A.h and all the files that #include it should be recompiled (you can do this in the Makefile for example)
A.c
#include "A.h" /* extern int I_am_a_global_variable; */
int I_am_a_global_variable = 27;
In order to prevent errors, it is good that A.c also #includes the file A.h, so the declaration
extern int I_am_a_global_variable; /* as above, you cannot initialize the variable here */
and the final definition (that is included in A.c):
int I_am_a_global_variable = 23; /* I have initialized it to a non-default value to show how to do it */
are consistent between them (consider the author changes the type of I_am_a_global_variable to double and forgets to change the declaration in A.h, the compiler will complaint about non-matching declaration and definition, when compiling A.c (which now includes A.h).
Why I say that you will have double definition errors when linking?
Well, if you compile several modules with the statement (result of #includeing the file A.h in several modules) with the statement:
#include "A.h" /* this has an extern int I_am_a_global_variable; that informs the
* compiler that the variable is defined elsewhere, but see below */
int I_am_a_global_variable; /* here is _elsewhere_ :) */
then all those modules will have a global variable I_m_a_global_variable, initialized to 0, because the compiler defined it in every module (you don't say that the variable is defined elsewhere, you are stating it to declare and define it in this compilation unit) and when you link all the modules together you'll end with several definitions of a variable with the same name at several places, and the references from other modules using this variable will don't know which one is to be used.
The compiler doesn't know anything of other compilations for an application when it is compiling module A, so you need some means to tell it what is happening around. The same as you use function prototypes to indicate it that there's a function somewhere that takes some number of arguments of types A, B, C, etc. and returns a value of type Z, you need to tell it that there's a variable defined elsewhere that has type X, so all the accesses you do to it in this module will be compiled correctly.

Pointer to a static variable inside a function. C

I have 3 files in my directory:
ex22.h, ex22.c. ex22_main.c
ex22.h:
#ifndef _ex22_h
#define _ex22_h
extern double* v;
...
#endif
ex22.c:
#include <stdio.h>
#include "ex22.h"
double* v;
/*a function that accepts a new_variable, changes a
static variable inside of it while keeping track of
what the static variable was before the change. The
purpose of the function is to update the static
variable and print what it was right before the
updating.*/
double update_variable(double new_variable)
{
static double variable = 1.0;
double old_variable = variable;
variable = new_variable;
v = &variable;
return old_variable;
}
...
ex22_main.c:
#include "ex22.h"
#include "dbg.h"
...
int main(void)
{
//test if it is possible
printf("Variable at first: %f", update_variable(2.0);
printf("Access 'variable' inside update_variable: %f", *v);
}
Compiller (ubuntu) gives me those error messages:
cc ex22_main.c -o ex22_main
/tmp/ccGLFiXP.o: In function `main':
...
ex22_main.c:(.text+0x1f4): undefined reference to `update_variable'
ex22_main.c:(.text+0x222): undefined reference to `r'
collect2: error: ld returned 1 exit status
<builtin>: recipe for target 'ex22_main' failed
make: *** [ex22_main] Error 1
Hope you understood what I'm trying to achieve. My goal is to access the static variable inside a function (which is not possible) by making a pointer to it. I'm just curious if it works that way?
EDIT:
There were some stupid bugs in my code but the idea of accessing a static variable inside a function by it's pointer is completely feasible.
Avoid my mistakes:
1) Make sure files are linked
2) Watch out for variable names
My goal is to access the static variable inside a function (which is not possible) by making a pointer to it. I'm just curious if it works that way?
Yes, it does. static has a different meaning for variables declared inside functions than for those declared at file scope, but but both varieties exist and have the same address for the entire lifetime of the program. A pointer to such a variable can be used to access its value anywhere in the program, without regard to whether the variable can be accessed via its declared identifier at the point of access-via-pointer.
Your compilation issue is unrelated. Your other answer explains the nature of that problem.
The compiler, or more precisely the linker, can't find the definitions of update_variable or r because you didn't compile and link ex22.c which contains those definitions.
You need to compile both files and link them together.
cc -o ex22_main ex22_main.c ex22.c

Extern Variables seemingly not working "symbols not found for architecture x86_64"

I've been searching through Stackoverflow and the web for the answer and it seems like I'm doing this correctly, however I can't get it to work.
I made a test program for using extern, (it's on xCode using the projects feature if that makes a difference). I'm trying to declare a variable, that I can access anywhere in my program, whenever I change the value of that variable, I want to be able to access the changed value.
What I've done so far is I have a header file
externFile.h
and a
externFile.c
and of course my
main.c
In externFile.h I defined:
extern int ply;
In main.c I have:
int main()
{
int ply;
ply = 5;
printPly();
}
In externFile.c I have:
void printPly(){
printf("%d is ply.\n", ply);
}
However I'm getting this error:
_ply referenced from _printPly
ld symbols not found for architecture x86_64
Does anyone have any sort of ideas about this?
You haven't actually defined ply globally:
int main(void)
{
int ply;
ply = 5;
printPly();
}
Here, ply is a local variable, not a global, since it is defined inside of a function. The extern line in your header file does not define the global, but declares it. It says "this variable exists somewhere", but it doesn't create it. Because there is no global defined, you get an undefined reference error.
Global variables must be defined at file scope, i.e. outside of a function:
int ply = 5;
int main(void)
{
printPly();
}

Compilation Error for extern variable initialized in other file

I have these two different program where I want to access the static variable declared in program1 from program2.
Program1. (
/* file a.c */)
#include<stdio.h>
static int a = 100; /* global static variable not visible outside this file.*/
int *b = &a; /* global int pointer, pointing to global static*/
Program2
#include<stdio.h>
/* file b.c */
extern int *b; /* only declaration, b is defined in other file.*/
int main()
{
printf("%d\n",*b); /* dereferencing b will give the value of variable a in file a.c */
return 0;
}
While I compile program1 , gcc a.c , no compilation error, but while I compile program2 ( gcc b.c) I am getting compilation error .
test_b.c:(.text+0x7): undefined reference to `b'
collect2: error: ld returned 1 exit status
Why there is compile error ? Here is the link of program static
Thanks in advance.
EDIT 1:
My intention to use static variable from other program. I thought every .c program must have main() function and only .h program have declaration , I am wrong at that point. So I remove main() function from a.c program and instead of compiling two different program separately , now I compile only once using gcc a.c b.c as per suggestion of Filip. Now it's working fine. Thanks all of you.
You have to link against a.c while compiling b.c:
gcc a.c b.c
You can't expect the linker to magically find the C file where b is defined. extern means it is defined elsewhere - you have to say where. By compiling and linking with a.c, the linker can now find a declaration for b.
Of course, you can't have 2 main() functions.
Well, your code already said it. b.cpp only has a declaration, not a definition, of the symbol in question.
Since these are clearly meant to be source files from two separate projects, I would suggest moving your definition to its own .cpp file which may then be shared between the two projects.
$ gcc a.c myIntPointerIsHere.c
$ gcc b.c myIntPointerIsHere.c
However, there are clearer ways to share code between two different projects.
The both modules contain the definition of main. It seems that the compiler did not include the first module in your project. Otherwise I think it would issue an error that main was redefined.

Qt C error duplicate symbol _function_names in juicy_lucy.o and main.o for architectures x86_64

I am working on a C console project in Qt (Mac) because client does not want C++
With everything in a single C file everything was working well but, of course,
it started getting too big.
So I created a new juicy_lucy.h and juicy_lucy.c file and, to start with, just transferred some stuff from main.c to juicy_lucy.h which now looks like this
#ifndef JUICY_LUCY_H
#define JUICY_LUCY_H
#define command_count 14
char *function_names[command_count] = {
"CLEAR_LCD", "PUT_LCD", "SET_VAR", "ADC_READ",
"BIT_WRITE", "BIT_READ", "BIT_WAIT",
"FAIL_LESS", "FAIL_MORE", "FAIL_HIGH","FAIL_LOW",
"AVR_PROG","AVR_READ_SERIAL","AVR_WRITE_SERIAL"
};
int param_count[command_count] = {0,3,2,1,2,1,2,2,2,1,1,1,1,1};
#endif // JUICY_LUCY_H
and, of course, include the header in both main.c and juicy_lucy.c
Now when I build I get
duplicate symbol _function_names in juicy_lucy.o and main.o for architectures x86_64
Can anybody suggest what may be wrong?
You must declare function_names as
const char* const function_names[] = ...
Then the symbol function_names should not appear twice in your linked application.
In your .h:
extern char *function_names[command_count];
extern int param_count[command_count];
In one of your .c files:
char *function_names[command_count] = {
"CLEAR_LCD", "PUT_LCD", "SET_VAR", "ADC_READ",
"BIT_WRITE", "BIT_READ", "BIT_WAIT",
"FAIL_LESS", "FAIL_MORE", "FAIL_HIGH","FAIL_LOW",
"AVR_PROG","AVR_READ_SERIAL","AVR_WRITE_SERIAL"
};
int param_count[command_count] = {0,3,2,1,2,1,2,2,2,1,1,1,1,1};

Resources