Размер выходного файла при модульной компиляции велик
От: lolovo  
Дата: 18.11.19 16:54
Оценка:
Всем привет!

Вопрос может показаться не актуальным, т.к. дело обстоит со старым компилятором (g++ 4.2.1), но все же интересно разобраться.

Суть вопрос в следующем. Почему если написать программу в одном файле и скомпилировать, а потом разбить ее на модули и собрать программу, скомпилировав каждый файл в отдельности, то на выходе получаются файлы разных размеров (когда одним файлом — существенно меньше, чем та же программа собранная по-модульно):

  Программа одним файлом
z.cpp
#include <string>
#include <map>
#include <stdio.h>
#include <stdlib.h>

class A;
class B;
class C;

class C{
public:
std::string _C;
std::map<int,int> __C;
C(){};
~C(){};
void r(){
        printf("r\n");
}
;
};


class A{
public:
std::string _A;
std::map<A*,B*> __A;
A(){};
~A(){};
void r(){
        C c;
        c.r();
}
;
};

class B{
public:
std::string _B;
std::map<A*,B*> __B;
B(){};
~B(){};
void r(){
        C c;
        c.r();
}
;
};


int main()
{
        A a;
        B b;
        a.r();
        b.r();

        return 0;
}


Компиляция:
g++ -lstdc++ -DBIG_JOINS=1 -fPIC -lthr -g -lmd -o z z.cpp

Размер выходного файла z = 90550 байт



  Программа одним файлом
a.h
#ifndef _A_
#define _A_

#include <string>
#include <map>

class B;
class A;
class A{
public:
std::string _A;
std::map<A*,B*> __A;
A();
~A();
void r();
};

#endif


a.cpp
#include "c.h"
#include "a.h"

A::A(){};
A::~A(){};
void A::r()
{
        C c;
        c.r();
}


b.h
#ifndef _B_
#define _B_

#include <string>
#include <map>

class A;
class B{
public:
std::string _B;
std::map<A*,B*> __B;
B();
~B();
void r();
};

#endif


b.cpp
#include "c.h"
#include "b.h"

B::B(){};
B::~B(){};
void B::r()
{
        C c;
        c.r();
}


c.h
#ifndef _C_
#define _C_

#include <string>
#include <map>

class C{
public:
std::string _C;
std::map<int,int> __C;
C();
~C();
void r();
};

#endif


c.cpp
#include "c.h"
#include <stdio.h>
#include <stdlib.h>

C::C(){};
C::~C(){};
void C::r()
{
        printf("r\n");
}


s.cpp
#include "a.h"
#include "b.h"
#include <stdio.h>
#include <stdlib.h>

int main()
{
        A a;
        B b;
        a.r();
        b.r();

        return 0;
}


Компиляция:
g++ -lstdc++ -DBIG_JOINS=1 -fPIC -lthr -g -lmd -o s a.cpp b.cpp c.cpp s.cpp

Размер выходного файла s = 231472 байт


К сожалению компилятор не поддерживает опцию -flto, чтобы проверить скажется ли это на размере. Но неужели компилятор/линковщик дублирует библиотеки модулей, а не выкидывает их? Или в чем может быть причина?
Re: Размер выходного файла при модульной компиляции велик
От: Шахтер Интернет  
Дата: 18.11.19 17:12
Оценка:
Здравствуйте, lolovo, Вы писали:

L>Всем привет!


L>Вопрос может показаться не актуальным, т.к. дело обстоит со старым компилятором (g++ 4.2.1), но все же интересно разобраться.


Разбираться надо ручками, посмотрев .o файлы и секции, сгенерированные компилятором.
В данном случае, однако, возможно, хорошо сработал оптимизатор при компиляции одного файла, выкинув всё, кроме printf().
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re: Размер выходного файла при модульной компиляции велик
От: watchmaker  
Дата: 18.11.19 17:17
Оценка: 1 (1) +1
Здравствуйте, lolovo, Вы писали:


L>К сожалению компилятор не поддерживает опцию -flto, чтобы проверить скажется ли это на размере.

Верно, что объединение файлов в один, развязывает руки оптимизатору, что может влиять на размер, например если у компилятора получится сделать удачный constant propagation и удалить после этого неактивные ветки.
Но тут скорее всего дело в другом.

L> Или в чем может быть причина?

В отладочной информации.
Для каждого файла компилятор записал блок, нужный для отладки — во втором случае у тебя не только больше файлов, но и суммарно больше текста (из-за раскрытия include).
Удали из сгенерированных файлов отладочную информацию (strip -g) и сравни их размеры. Либо просто посмотри на размеры соответствующих секций (objdump -h).
Re: Размер выходного файла при модульной компиляции велик
От: B0FEE664  
Дата: 18.11.19 17:35
Оценка: +1
Здравствуйте, lolovo, Вы писали:

L> Или в чем может быть причина?


Например в том, что код разный. В первом случае все методы A,B и C неявно объявлены как inline, а во втором — как нормальные функции с внешним связыванием.
И каждый день — без права на ошибку...
Re[2]: Размер выходного файла при модульной компиляции велик
От: lolovo  
Дата: 18.11.19 17:39
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>В отладочной информации.

W>Для каждого файла компилятор записал блок, нужный для отладки — во втором случае у тебя не только больше файлов, но и суммарно больше текста (из-за раскрытия include).
W>Удали из сгенерированных файлов отладочную информацию (strip -g) и сравни их размеры. Либо просто посмотри на размеры соответствующих секций (objdump -h).


Удалил отладочную информацию (strip -g s и strip -g z) и теперь выходные файлы приблизились друг к другу по размерам:

Размер s = 19230 байт
Размер z = 16770 байт

Спасибо за инфо
Re[3]: Размер выходного файла при модульной компиляции велик
От: Mr.Delphist  
Дата: 21.11.19 09:03
Оценка:
Здравствуйте, lolovo, Вы писали:

L>Удалил отладочную информацию (strip -g s и strip -g z) и теперь выходные файлы приблизились друг к другу по размерам:


L>Размер s = 19230 байт

L>Размер z = 16770 байт

L>Спасибо за инфо


Кстати, сборка Release или Debug?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.