I want to allow the redefinition of a function in a .c file that is already defined in a header file. According to GCC manual on the weakref attribute:
The effect is equivalent to moving all references to the alias to a separate translation unit, renaming the alias to the aliased symbol, declaring it as weak, compiling the two separate translation units and performing a reloadable link on them.
Which sounds like exactly what I want to do.
However, the following example does not compile with error:
tpp.c:18:13: error: redefinition of ‘foo’
tpp.c:6:13: note: previous definition of ‘foo’ was here
#include <sys/types.h>
#include <stdio.h>
/* this will be in a header file */
static void foo(void) __attribute__ ((weakref ("_foo")));
static void _foo(void)
{
printf("default foo\n");
}
/* in a .c file #including the header mentioned above */
#define CUSTOM_FOO
#ifdef CUSTOM_FOO
static void foo(void)
{
printf("user defined foo.\n");
}
#endif
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
Am I using this correctly? What am I missing?
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
As far as I understand that you need to define that function as extern.
Then it work for me as follows:
user#horst:$ cat weakref.c
#include <sys/types.h>
#include <stdio.h>
/* this will be in a header file */
extern void foo(void) __attribute__ ((weak, alias ("_foo")));
void _foo(void)
{
printf("default foo\n");
}
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
user#horst:$ gcc weakref.c
user#horst:$ ./a.out
calling foo.
default foo
user#horst:$ cat weakrefUser.c
#include <stdio.h>
/* in a .c file #including the header mentioned above */
#define CUSTOM_FOO
#ifdef CUSTOM_FOO
void foo(void)
{
printf("user defined foo.\n");
}
#endif
user#horst:$ gcc -c weakrefUser.c
user#horst:$ gcc -c weakref.c
user#horst:$ gcc weakref.o weakrefUser.o
user#horst:$ ./a.out
calling foo.
user defined foo.
Note1: It does not work with static functions, for the weak attribute, it need to be global.
Note2: Weak symbols are "only" supported for ELF targets.
Since I wanted to use weak or weakref, and the existing answer seemed incomplete, I decided to write up the options, and try to explain.
There are apparently three basic options:
Use weakref. In this case, you write a static definition of a different name referencing the name you want, and it may or may not be null. You need to test the function before calling it. In this case, the alias option must be included either explicitly or as a parameter on weakref.
Use weak without alias. In this case, things are simple and public. Again, it may or may not be null, and you must test it before calling it.
Use weak and alias. In this case, the call and the declared alias must (apparently) be in the same source file. In this case, there is always a definition for the symbol, so you don't need to test for it. If there is an external definition of the name, you will get that in leiu of the alias.
In C++, when providing an alias name, the name must be the mangled form. (This was relevant to me, not to OP.)
My test sources are:
cat weakref.c :
#include <stdio.h>
static void fooref(void) __attribute__((weakref("foo")));
int main(int argc, char **argv)
{
if (fooref) {
printf("calling foo.\n");
fooref();
} else {
printf("no foo to call. (do something default-ish)\n");
}
}
cat weak.c :
#include <stdio.h>
#include "header.h"
int main(int argc, char **argv)
{
if (foo) {
printf("calling foo.\n");
foo();
} else {
printf("no foo to call. (do something default-ish)\n");
}
}
cat weakalias.c :
#include <stdio.h>
#include "header.h"
extern void foo(void) __attribute__ ((weak, alias ("defaultfoo")));
void defaultfoo(void)
{
printf("default foo\n");
}
int main(int argc, char **argv)
{
printf("calling foo.\n");
foo();
}
cat header.h :
extern void foo(void) __attribute__ ((weak));
cat Makefile :
EXES = weakref weakreffoo weakalias weakaliasfoo weak weakfoo
all : ${EXES}
clean :
-rm ${EXES} *.o
weakref : weakref.o
gcc -o $# $^
weakreffoo : weakref.o foo.o
gcc -o $# $^
weakalias : weakalias.o header.h
gcc -o $# $^
weakaliasfoo : weakalias.o foo.o header.h
gcc -o $# $^
weak : weak.o header.h
gcc -o $# $^
weakfoo : weak.o foo.o header.h
gcc -o $# $^
cat foo.c :
#include <sys/types.h>
#include <stdio.h>
void foo(void)
{
printf("custom foo\n");
}
My output reads:
$ ./weakref
no foo to call. (do something default-ish)
$ ./weakreffoo
calling foo.
custom foo
$ ./weak
no foo to call. (do something default-ish)
$ ./weakfoo
calling foo.
custom foo
$ ./weakalias
calling foo.
default foo
$ ./weakaliasfoo
calling foo.
custom foo
$
I initially decided on weakref, but am now leaning towards weak.
Related
My file1.c is as follows
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("x = %d\n", x);
return 0;
}
And file2.c is as follows
int x = 12;
When I compile both files with gcc -std=c17 file1.c file2.c, I get the error.
error: ‘x’ undeclared (first use in this function)
Now, in my file2.c, x is a global variable. So, even if I don't declare it in file1.c, it should be seen in file1.c. So, why am I getting this error ?
x is a global variable. So, even if I don't declare it in file1.c, it
should be seen in file1.c. So, why am I getting this error ?
No, code in file1.c does not know anything about code in the file2.c. Global variables are visible only in one compilation unit (ie file).
In file1.c you need to add (before main)
extern int x;
This declaration will tell the compiler that somewhere in the project there is a definition of the variable x having the type int
#include <stdio.h>
extern int x;
int main(int argc, char *argv[])
{
printf("x = %d\n", x);
return 0;
}
Like #0___________ said above you need to declare the symbol x so my answer is just spelling it out in a bit more detail. It is customary to move declarations into a file2.h file so it's easy to reference in multiple places (especially if there is more than one symbol):
#ifndef FILE2_H
#define FILE2_H
extern int x;
#endif
Then modify file1.c and file2.c to include it:
#include <stdio.h>
#include "file2.h"
int main() {
printf("x = %d\n", x);
return 0;
}
#include "file2.h"
int x = 12;
Finally, you compile (-std=c17 makes not difference in this sample) and link the two files. Subsequently execute the binary::
$ gcc -std=c17 file1.c file2.c && ./a.out
x = 12
If you prefer a Makefile:
.PHONY: all clean
CFLAGS = -std=c17
all: a.out
clean:
rm -f a.out file1.o file2.o
a.out: file1.o file2.o
$(CC) $^ -o $#
file1.o: file2.h
file2.o: file2.h
and it's then:
$ make && ./a.out
x = 12
I'm trying to understand Makefile. I understand the hole concept of the dependency tree, but why do we include .h files for the .o targets that include certain header file. Here is an example:
// main.c
#include <stdio.h>
#include "math.h"
int main() {
printf("%d\n", magic_number);
printf("%d\n", square(5));
}
// foo.h
const int magic_number = 10;
int square(int);
// foo.c
int square(int value) {
return value*value;
}
# -*- Makefile -*-
all: main
main: main.o foo.o
gcc main.o foo.o -o main
main.o: main.c #foo.h <-----------
gcc -c main.c
foo.o: foo.c
gcc -c foo.c
I commented the part out where I would add the header file. Because that's my question, why does it have to be there? I did some testing and added some more const int variables to the header. Just looking at the Makefile (with commented out foo.h) it would only recompile the main.c file. There it would then access a variable from the header. So why does it look into the header file even thought it's not in the Makefile?
Makefiles track dependencies - in this case it is an explicit dependency.
Specifying that main.o depends on both main.c and foo.h means that any time either file changes, main.o will be rebuilt.
If you didn't have that explicit dependency chain, then you could change foo.h in a way which renders main.c uncompilable, but Make wouldn't know about it so would not rebuild it when it should.
There are tons of ways that a header file can change in such a way that a source file doesn't need to also change, but yet the program is malformed if the source file is not rebuilt. Here's one simple example: say we have this source:
// foo.h
struct foo {
int f;
};
int getfoo(const struct foo* f);
// foo.c
#include "foo.h"
int getfoo(const struct foo* f)
{
return f->f;
}
// main.c
#include "foo.h"
int main()
{
struct foo f = {1};
return getfoo(&f);
}
You compile everything and all is well. Now suppose you modify foo.h like this:
// foo.h
struct foo {
const char* val; // added value
int f;
};
int getfoo(const struct foo* f);
And you modify main.c like this:
// main.c
#include "foo.h"
int main()
{
struct foo f = {"hello", 1};
return getfoo(&f);
}
Now you run make and since you've modified main.c it is recompiled, but since you haven't modified foo.c it is not recompiled.
Now your program will certainly return a bogus value since foo.o thinks that the structure it was passed contains just a single integer, but the structure it was really passed from main() actually has a pointer plus an integer.
I'm using Cmocka to write a unit testing suite for a shared object written in C, but I'm having some issue. Since I cannot share the source code, I have written a minimum "not-working" example to show what is the issue:
my program is composed 5 files: foo.c, foo.h bar.c bar.h main.c.
bar.* files define a bar() function, which simply returns the argument multiplied by 2
foo.* files declare a foo() function that uses the bar() function defined by bar.h
main.c contains a simple cmocka test and a __wrap_bar()
function, returning the argument multiplied by 3.
I compile the program by producing a libfootest.so object (foo+bar) and then I link this object with main.o passing the -Wl,--wrap=bar flag to the compiler. In this configuration libfootest is the module under test and main is the tester program. I expect the __wrap__bar to be called (failing the test), but the standard bar() is called(test is passed). How can I solve this problem? Below you find all the code I'm using.
bar.c:
#include "bar.h"
int bar(int val) {
return val*2;
}
bar.h:
int bar(int val);
foo.h:
#include <stdio.h>
int foo(int val);
foo.c:
#include "foo.h"
#include "bar.h"
int foo(int val) {
int ret;
ret = bar(val);
printf("RET: %d", ret);
return ret;
}
main.c:
#include <stdio.h>
//required include for CMOCKA
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <setjmp.h>
#include <cmocka.h>
//library under test
#include "foo.h"
int __wrap_bar(int val) {
return 3*val;
}
static void test_foo(void **state) {
int ret = foo(5);
assert_int_equal(ret, 10);
}
int main (int argc, char** argv) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_foo),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
Makefile:
CMOCKA_LIB_DIR=../../cmocka-1.1.5/build/src
CXXFLAGS+=-g -Og -fPIC
CFLAGS+=-g -Og -std=c99 -fPIC
CC=gcc
CXX=g++
all: main.o ./libfootest.so
gcc -o linux-test -g -L. -L$(CMOCKA_LIB_DIR) $(filter %.o, $^) -lcmocka -lfootest -Wl,-rpath=. -Wall -Wl,--wrap=bar -Wl,-rpath=$(CMOCKA_LIB_DIR)
./libfootest.so: foo.o bar.o
$(CC) -shared -o $# -g $^ -pedantic -Wall
clean:
rm -f *.o
rm -f *.so
The problem is your build of the library. You don't create a link library as commonly done, with separated modules. Instead you link all given modules and place the resulting single module in the target library.
That's why the linker resolved the call to bar() already, and it is no longer unresolved when linking the test program.
The option --wrap works only for unresolved references between modules.
The solution is to build the library from separated modules. Use the tool ar for this:
ar r libfootest.a foo.o bar.o
The code is as follows:
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
#include <stdio.h>
int test;
void test_fun(void);
#endif
global.c
#include "global.h"
void test_fun()
{
printf("%d\n", test);
}
main.c
#include "global.h"
int main(void)
{
test_fun();
test = 1;
printf("%d\n", test);
}
Makefile using gcc compiler
main: main.o global.o
gcc -o main main.o global.o
main.o: main.c global.h
gcc -c main.c
global.o: global.c global.h
gcc -c global.c
clean:
rm -f global.o main.o main
This works well.
However, when I change my code to C++, as follows:
global.h
#ifndef GLOBAL_H
#define GLOBAL_H
#include <iostream>
int test;
void test_fun(void);
#endif
global.cpp
#include "global.h"
void test_fun()
{
cout << test
}
main.cpp
#include "global.h"
int main(void)
{
test_fun();
test = 1;
std::cout << test;
}
Makefile using g++ compiler
main: main.o global.o
g++ -o main main.o global.o
main.o: main.cpp global.h
g++ main.cpp
global.o: global.cpp global.h
g++ global.cpp
clean:
rm -f global.o main.o main
The code above throws the output:
global.o:(.bss+0x0): multiple definition of `test'
What makes the different here?
You've int test; in a header which is included in 2 TUs, hence the error. Both the translation units main.c (or .cpp depending upon the compiler used) and global.c have global.h included, which leads to two definitions of the same variable in two object files, thus the linker error.
Pass test as an arguement to test_fun, thereby avoiding the usage of a global.
If you absolutely have to share the variable between the TUs, then remove int test; from global.h and in main.cpp do
int test;
and in global.cpp do
extern int test;
As an aside, since it's a global variable, test would be initialized to 0 and hence in main when you test_fun();, it should print 0 and then after setting it to 1, it'll print 1.
It's illegal in both C and C++ from a language standpoint, but as for why it works with a C compilers (like GCC) is because they implement a common extension, a legacy cruft.
... You are using a different programming language
I have the following two files:
file1.c
int main(){
foo();
return 0;
}
file2.c
void foo(){
}
Can I compile and link the two files together so the file1.c will recognize the foo function without adding extern?
Updated the prototype.
gcc file1.c file2.c throws: warning: implicit declaration of function foo.
The correct way is as follows:
file1.c
#include <stdio.h>
#include "file2.h"
int main(void){
printf("%s:%s:%d \n", __FILE__, __FUNCTION__, __LINE__);
foo();
return 0;
}
file2.h
void foo(void);
file2.c
#include <stdio.h>
#include "file2.h"
void foo(void) {
printf("%s:%s:%d \n", __FILE__, __func__, __LINE__);
return;
}
output
$
$ gcc file1.c file2.c -o file -Wall
$
$ ./file
file1.c:main:6
file2.c:foo:6
$
You don't need an extern, but file1.c must see a declaration that foo() exists. Usually this declaration is in a header file.
To add a forward declaration without using a header file, simply modify file1.c to:
int foo(); // add this declaration
int main(){
foo();
return 0;
}
You can, but you shouldn't.
Use a header file, file2.h:
// file2.h
void foo(); // prototype for function foo()
Then add:
#include "file2.h"
in file1.c
To compile:
$ gcc -Wall file1.c file2.c -o foo
As a general rule it's better (more robust) to use a header file to define the interface of each module rather than ad hoc prototypes within dependent modules. This is sometimes known as the SPOT (Single Point Of Truth) principle.
It's ugly, but using gcc, you could:
gcc -include file2.c file1.c
-include is a flag to the preprocessor which will include the contents of file2.c at the very top of file1.c. Having said that, it's a poor choice, and breaks down for all but the simplest of programs.