(Environment: gcc 4.6, c++11, glibc 2.13, binutils 2.21)
Please consider the follow "linking" demo for background:
foo.h:
#pragma once
#include <iostream>
void foo();
foo1.cpp:
#include "foo.h"
void foo()
{
std::cout << "foo1";
}
foo2.cpp:
#include "foo.h"
void foo()
{
std::cout << "foo2";
}
main.cpp:
#include "foo.h"
int main()
{
foo();
}
Makefile:
compile: main.o foo1.o foo2.o
case1: compile
g++ -o case1.x main.o
case2: compile
g++ -o case2.x main.o foo1.cpp
case3: compile
g++ -o case3.x main.o foo1.o foo2.o
clean:
rm *.o *.x
We have a function declaration as follows:
void foo();
and we have multiple definitions of it, one in foo1.cpp and a different one in foo2.cpp.
We compile the .cpp files into .o files:
$ make compile
No problem, main.o, foo1.o and foo2.o are produced.
Case 1
We then try and link just main.o:
$ make case1
error: undefined reference to 'foo()'
Ok, main.o references foo but no definition has been linked.
Case 2
Now we try and link main.o and foo1.o
$ make case2
There is a single definition of foo in foo1.o, so it links without error.
Case 3
Now we try and link main.o foo1.o and foo2.o
$ make case3
error: multiple definition of 'foo()'
The linker finds two definitions of foo in foo1.o and foo2.o, so rather than taking a random one it fails fast with an error and doesn't link.
Questions
My questions are:
Is it possible to mark the definition of foo1.cpp's version of foo (possibly with some sort of gcc attribute or pragma) as "weak"? Meaning specifically that I want the behavior of case 1 and case 2 to remain the same, while the behavior of case 3 changes to successfully link without warning or error and the definition of foo in foo2.cpp is linked (overriding the "weak" definition in foo1.cpp).
Is it possible to test at runtime (and assign to a boolean variable) whether the weak version of foo was linked, or the strong one (without executing the function obviously). ie implement a function in main as follows.
template<typename FunctionPtr>
bool is_weak_linked(FunctionPtr fp);
is_weak_linked(foo) should return true in case 2 and false in case 3.
To #1:
void foo() __attribute__((weak));
void foo()
{
...
}
To #2: I don't believe so, not with the static linking you're doing. That information is lost at link time.
Edit
You can always abstract your way around #2. Some examples:
// Foo.h
extern void foo();
extern "C" void default_foo();
extern const bool is_weak_foo_linked;
template <void (*)()> bool is_weak_linked();
// Foo1.cc
extern "C" void default_foo() {...}
void foo() __attribute__((weak, alias("default_foo")));
extern const bool __attribute__((weak)) is_weak_foo_linked=true;
template <> bool is_weak_linked<foo>() __attribute__((weak));
template <> bool is_weak_linked<foo>() {return true;}
// Foo2.cc
void foo() {...}
extern const bool is_weak_foo_linked=false;
template <> bool is_weak_linked<foo>() {return false;}
// main.cc
#include "foo.h"
#include <iostream>
int main() {
foo();
std::cout<<is_weak_foo_linked<<std::endl;
std::cout<<is_weak_linked<foo>()<<std::endl;
std::cout<<(foo==default_foo)<<std::endl;
}