Reading Visibility in the GNU wiki, it is clear.
Taking this example from C++ Tutorials
// classes example
#include
using namespace std
Is it possible to customize which functions are exposed by modifying the compilation command above?
No. Compilation option -fvisibility=[default|internal|hidden|protected]
(and note it is not a linkage option) makes the compiler attribute the specified dynamic visibility type to all global symbols
generated in the compilation unit except those that are specifically excluded by having a countervailing __attribute__((visibility(....)))
applied in the source code. Which makes the answer to your other question:
Is it possible to make area() public and set_values(int,int) local as shown in the first link without altering the code?
also No.
How would you change the source code to make Rectangle::area()
dynamically
visible while all other global symbols are hidden for dynamic linkage by -fvisibility=hidden
?
Here is a walk-through:
Let's start with:
rectangle.cpp (1)
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area() {return width*height;}
};
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
and simply compile it to a PIC rectangle.o
so:
$ g++ -Wall -c -fPIC rectangle.cpp
Then check the global symbol table:
$ nm -C rectangle.o
0000000000000000 T Rectangle::set_values(int, int)
Note that Rectangle::area
isn't there. It's not available for
linkage at all, so the question of its dynamic visibility just does not arise.
That is because it is defined inline in the class definition and never called in the compilation unit, so gcc need not even compile its definition. It vanishes from the object file.
Rectangle::set_values
, on the other hand, is not defined inline, so the compiler
emits a global symbol and definition.
To make Rectangle::area
eligible for some visibility type, we first need to make
it a global symbol by not defining it inline:
rectangle.cpp (2)
class Rectangle {
int width, height;
public:
void set_values (int,int);
int area();
};
int Rectangle::area() {return width*height;}
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
Recompile and again check the global symbol table:
$ g++ -Wall -c -fPIC rectangle.cpp
$ nm -C rectangle.o
000000000000001a T Rectangle::set_values(int, int)
0000000000000000 T Rectangle::area()
Good. Now a global definition of Rectangle::area
appears.
Next let's make a shared library librectangle.so
from rectangle.o
:
$ g++ -o librectangle.so --shared rectangle.o
Here are the Rectangle::*
symbols in its global symbol table:
$ nm -C librectangle.so | grep 'Rectangle::'
00000000000005d4 T Rectangle::set_values(int, int)
00000000000005ba T Rectangle::area()
And here are the Rectangle::*
symbols in its dynamic symbol table:
$ nm -CD librectangle.so | grep 'Rectangle::'
00000000000005d4 T Rectangle::set_values(int, int)
00000000000005ba T Rectangle::area()
They're the same.
Now let's hide those symbols for dynamic linkage. We need to recompile rectangle.cpp
then relink the shared library:
$ g++ -Wall -c -fPIC -fvisibility=hidden rectangle.cpp
$ g++ -o librectangle.so --shared rectangle.o
Here again are the Rectangle::*
symbols now in the global symbol table:
$ nm -C librectangle.so | grep 'Rectangle::'
0000000000000574 t Rectangle::set_values(int, int)
000000000000055a t Rectangle::area()
They're the same as before.
And here are the Rectangle::*
symbols now in the dynamic symbol table:
$ nm -CD librectangle.so | grep 'Rectangle::'; echo Done
Done
Now there are none, thanks to -fvisibility=hidden
.
Finally, let's make just Rectangle::area
dynamically visible, keeping all
the other global symbols dynamically hidden. We need to change the source code
again:
rectangle.cpp (3)
class Rectangle {
int width, height;
public:
void set_values (int,int);
__attribute__((visibility("default"))) int area();
};
int Rectangle::area() {return width*height;}
void Rectangle::set_values (int x, int y) {
width = x;
height = y;
}
Then recompile and relink:
$ g++ -Wall -c -fPIC -fvisibility=hidden rectangle.cpp
$ g++ -o librectangle.so --shared rectangle.o
The global symbol table still shows:
$ nm -C librectangle.so | grep 'Rectangle::'
00000000000005a4 t Rectangle::set_values(int, int)
000000000000058a T Rectangle::area()
And the dynamic symbol table only shows:
$ nm -CD librectangle.so | grep 'Rectangle::'
000000000000058a T Rectangle::area()
Rectangle::area
is now the only symbol that the shared library exposes for
dynamic linkage.
And before you go...
One thing more about:
Is it possible to make area() public and set_values(int,int) local as shown in the first link without altering the code?
Making a symbol hidden for dynamic linkage doesn't make it local. Dynamic visibility (default|internal|hidden|protected) is an attribute of global symbols only. For linkage purposes, local symbols don't exist. The only ways to make a symbol local that would otherwise be global are:-
Then the symbol does not appear in the global, or dynamic, symbol tables.