Linking in C++

J

jacob navia

Suppose I have some class "derived" that inherits from "mainClass".

If I call just one method from "derived", do my executable include:

(1) Only that method from derived since I do not instantiate any
mainClass objects

(2) All methods of the derived class + constructor/destructor of mainClass

(3) All methods of both classes and all methods of (possible) superclasses.

Thanks

jacob
 
V

Victor Bazarov

Suppose I have some class "derived" that inherits from "mainClass".

If I call just one method from "derived", do my executable include:

(1) Only that method from derived since I do not instantiate any
mainClass objects

(2) All methods of the derived class + constructor/destructor of mainClass

(3) All methods of both classes and all methods of (possible) superclasses.

This is not governed by the language standard. There are linkers that
will remove unused functions from the object modules (so you're going to
end up with "1"). Other linkers will leave in the entire object module
(so you're getting "2" or "3" depending on how your code is organised).

V
 
A

Alain Ketterlin

jacob navia said:
Suppose I have some class "derived" that inherits from "mainClass".

If I call just one method from "derived", do my executable include:

(1) Only that method from derived since I do not instantiate any
mainClass objects

The called method will be included (unless it has been inlined by the
compiler).
(2) All methods of the derived class + constructor/destructor of mainClass

Other methods are not needed, but ctor and dtor of both "derived" and
"mainClass" are actually used (instantiating "derived" indirectly
instantiates "mainClass").
(3) All methods of both classes and all methods of (possible) superclasses.

This may happen as well...

Actually your problem has nothing to do with c++, but everything to do
with both the compiler and the linker. What will end up in the
executable depends on the amount of inlining performed by the compiler
and the smartness of the linker (i.e., its ability to notice that some
routines are unused).

-- Alain.
 
J

jacob navia

Le 25/04/11 19:16, Victor Bazarov a écrit :
This is not governed by the language standard. There are linkers that
will remove unused functions from the object modules (so you're going to
end up with "1"). Other linkers will leave in the entire object module
(so you're getting "2" or "3" depending on how your code is organised).

Thanks for your answer Victor.
 
J

jacob navia

Le 25/04/11 19:56, Alain Ketterlin a écrit :
The called method will be included (unless it has been inlined by the
compiler).


Other methods are not needed, but ctor and dtor of both "derived" and
"mainClass" are actually used (instantiating "derived" indirectly
instantiates "mainClass").


This may happen as well...

Actually your problem has nothing to do with c++, but everything to do
with both the compiler and the linker. What will end up in the
executable depends on the amount of inlining performed by the compiler
and the smartness of the linker (i.e., its ability to notice that some
routines are unused).


Thanks for your answer Alain.
 
J

James Kanze

On 4/25/2011 1:00 PM, jacob navia wrote:
This is not governed by the language standard.

It is at least partially, since you don't have to provide
implementations for functions that are not "used". (The
original question didn't provide enough information for us to
state whether some other functions were "used" or not. In
general, a virtual function is "used" as soon as there is an
instance of the class, regardless of whether the function is
ever actually called.)
There are linkers that will remove unused functions from the
object modules (so you're going to end up with "1"). Other
linkers will leave in the entire object module (so you're
getting "2" or "3" depending on how your code is organised).

The granularity of most linkers is the object file. In general,
if you are writing a library, you put each non-virtual function
in a separate object file, and only those which are actually
called are included. (But this is, of course, a quality of
implementation issue for the library provider.)
 
E

Ebenezer

The granularity of most linkers is the object file.  In general,
if you are writing a library, you put each non-virtual function
in a separate object file, and only those which are actually
called are included.  (But this is, of course, a quality of
implementation issue for the library provider.)

This seems like a "premature optimization." I haven't come
across this much, but recall your mentioning it previously.


Brian Wood
Ebenezer Enterprises
http://webEbenezer.net
 
J

jacob navia

Le 27/04/11 21:01, Pete Becker a écrit :
Not in a general-purpose library. If you get it wrong your customers
complain about code bloat. As an extreme example, linking the entire C
standard library into every application would not be a good thing.

For some people all optimizations are "premature" and they deliver
bloated, unoptimized programs. Code bloat slows down programs because
it forces more main memory reads, and makes code cacheing less
efficient. It is a very important optimization.
 
B

Bo Persson

Ebenezer said:
This seems like a "premature optimization." I haven't come
across this much, but recall your mentioning it previously.

Some compilers will do it for you, and put each function in its own
section. Perhaps that's why not everyone have noticed any "bloat".


Bo Persson
 
E

Ebenezer

Some compilers will do it for you, and put each function in its own
section. Perhaps that's why not everyone have noticed any "bloat".


What compilers do this?
What I take away is to put a limit on the size of files.
I think this is a reminder of the benefits of moderation.
 
E

Ebenezer

Le 27/04/11 21:01, Pete Becker a crit :











For some people all optimizations are "premature" and they deliver
bloated, unoptimized programs. Code bloat slows down programs because
it forces more main memory reads, and makes code cacheing less
efficient. It is a very important optimization.


I think this library -- http://quicklz.com -- is a
quality library, but there's no breaking things up
like that. I can't think of a library that splits
things up into such small chunks.
 
D

Drew Lawson

I think this library -- http://quicklz.com -- is a
quality library, but there's no breaking things up
like that. I can't think of a library that splits
things up into such small chunks.

Taking a quick look at libc on my FreeBSD system, I see that it is
split into 849 files. I find this pretty common for general use
libraries.
Less general libraries -- database APIs, toolsets, etc. -- probably
don't take that effort as often.
 
G

gwowen

Taking a quick look at libc on my FreeBSD system, I see that it is
split into 849 files.  I find this pretty common for general use
libraries.
Less general libraries -- database APIs, toolsets, etc. -- probably
don't take that effort as often.

running

nm /usr/lib/libc.a | grep -F ".o:" | wc -l

on this Ubuntu Linux box suggests 1479 distinct ibject files in the
static library

nm /usr/lib/libc.a 2> /dev/null | grep " T " | wc -l

suggests 2377 defined global symbols, or about 1.5 exported symbols
per object file.
 
R

red floyd

running

nm /usr/lib/libc.a | grep -F ".o:" | wc -l

on this Ubuntu Linux box suggests 1479 distinct ibject files in the
static library

nm /usr/lib/libc.a 2> /dev/null | grep  " T " | wc -l

suggests 2377 defined global symbols, or about 1.5 exported symbols
per object file.

An easier way to do it:

On RHEL 5,

ar tv /usr/lib/libc.a | wc

shows 1391 object files
 
E

Ebenezer

running

nm /usr/lib/libc.a | grep -F ".o:" | wc -l

on this Ubuntu Linux box suggests 1479 distinct ibject files in the
static library

nm /usr/lib/libc.a 2> /dev/null | grep  " T " | wc -l

suggests 2377 defined global symbols, or about 1.5 exported symbols
per object file.

Thanks for the commands. What about the little " t "'s in nm output?

I checked my library like you did with libc and got a ratio of 4.
 
E

Ebenezer

What compilers do this?

I'd like to give a shout out to the vendors that have done
things right in this regard. Who are the good guys in this
story?

I've made some changes to my work related to this.
Previously I had this "middle" file:

local_messages
(cmw_request)

(bool)
(bool, flex_string<char>) @out
(flex_string<char>) @in
}

----------------------------------------------------

A line like (cmw_request) caused both a Send and
Receive function to be created. And the class
that was created, local_messages, was shared by
two executables. Now I've changed the middle file
so two separate classes are created:

local_messages
(cmw_request) @in

(bool) @out
(bool, flex_string<char>) @out
}

local_messages_d
(cmw_request) @out

(bool) @in
(flex_string<char>) @in
}

-------------------------------------------------

Using this approach has reduced the size of the
two executables by 300 to 400 bytes each. It also
provides a nice application of the support for
multiple classes being outlined in a middle file.


Brian Wood
 
E

Ebenezer

Ebenezer  wrote:


For instance:
gcc -ffunction-sections


I just tried that with the combined/shared class I mentioned.
Unfortunately, the sizes of the executables are not reduced
by that option. I used -ffunction-sections when building
the object files and the executables. I didn't do anything
different when building the library.
 
M

Marc

I just tried that with the combined/shared class I mentioned.
Unfortunately, the sizes of the executables are not reduced
by that option.

You may also want to look at the --gc-sections option of ld.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,002
Messages
2,570,258
Members
46,858
Latest member
FlorrieTuf

Latest Threads

Top