c++ - visual - gcc: tira las funciones no utilizadas
visual studio code c++ (1)
Intente -Wl,--strip-all
información de depuración y de símbolos de estática libstdc ++ a través de -Wl,--strip-all
. Esto redujo mi ejecutable de 9M a 670K en Cygwin (13x) y de 6M a 80K en Ubuntu (80x).
Noté que a veces, incluso si no uso iostream
y las bibliotecas de E / S relacionadas, mis archivos binarios producidos por Mingw todavía eran demasiado grandes.
Por ejemplo, escribí un código para usar vector
y cstdio
solo y lo -O2 -flto
con -O2 -flto
, ¡mi programa puede tener un tamaño de hasta 2 MB! nm main.exe > e.txt
y me sorprendió ver todas las funciones relacionadas con iostream
en él.
Después de -ffunction-sections -Wl,-gc-sections
Google, aprendí a usar -ffunction-sections -Wl,-gc-sections
, que reduce el tamaño del programa de 2MB a ~ 300KB (si tiene -s
, 100 + KB). ¡Excelente!
Para probar aún más el efecto de -ffunction-sections -Wl,-gc-sections
, aquí hay otro código:
#include <cstdio>
#include <vector>
#include <tuple>
#include <algorithm>
#include <chrono>
#include <windows.h>
#undef min
struct Point {
int x, y;
};
constexpr int length = 5;
constexpr int half_length() {
return length & 1 ? length : length - 1;
}
template<class F>
int func_template(F&& f) {
#ifdef _MSC_VER
puts(__FUNCSIG__);
#else
puts(__PRETTY_FUNCTION__);
#endif
printf("/n");
return f();
}
struct fake_func {
int operator()() const { return 59; };
};
template<class F, class... Args>
int pass_args(F&& f, Args&&... args) {
#ifdef _MSC_VER
puts(__FUNCSIG__);
#else
puts(__PRETTY_FUNCTION__);
#endif
printf("/n");
return f(std::forward<Args>(args)...);
}
template<class T>
T min(T x) {
return x;
}
template<class T, class... Args>
T min(T x, Args... args) {
T y = min(args...);
return x < y ? x : y;
}
void type_verifier(int x) {
printf("%dd ", x);
}
void type_verifier(char x) {
printf("''%c'' ", x);
}
void type_verifier(double x) {
printf("%lff ", x);
}
template<class T>
void type_verifier(T x) {
printf("unknown ");
}
template<class T, class... Args>
void type_verifier(T x, Args... args) {
type_verifier(x);
type_verifier(args...);
}
int bufLen;
char buf[100];
template<class... Args>
inline int send(Args... args) {
bufLen = sprintf(buf, std::forward<Args>(args)...);
return bufLen;
}
namespace std {
inline namespace v1 {
void func() {
printf("I am v1/n");
}
}
namespace v2 {
void func() {
printf("I am v2/n");
}
}
}
int main() {
std::vector<int> v {1, 2, 3, 4, 5};
for (auto &i : v) printf("%d ", i);
printf("/n");
Point p {1, 2};
printf("%d %d/n", p.x, p.y);
auto t = std::make_tuple("Hello World", 12);
printf("%s %d/n", std::get<0>(t), std::get<1>(t));
int a, b;
auto f = []() { return std::make_tuple(1, 2); };
std::tie(a, b) = f();
printf("%d %d/n", a, b);
//int test_constexpr[half_length() + 4];
int ft = func_template([]{ return 42; });
printf("func_template: %d/n", ft);
ft = func_template(fake_func {});
printf("func_template: %d/n", ft);
ft = pass_args([](int x, int y) { return x + y; }, 152, 58);
printf("pass_args: %d/n", ft);
ft = pass_args([](int n, const char *m) {
for (int i = 0; i < n; i++) printf("%c ", m[i]);
printf("/n");
return 0;
}, 5, "Hello");
printf("min: %d/n", min(3, 4, 2, 1, 5));
type_verifier(12, ''A'', 0.5, "Hello");
printf("/n");
/* send("Hello World");
send("%d", 1);
send("%d", "1234");
sprintf(buf, "%d", "123");*/
std::func();
std::v1::func();
std::v2::func();
std::rotate(v.begin(), v.begin() + 2, v.end());
for (auto &i : v) printf("%d ", i);
printf("/n");
auto start = std::chrono::steady_clock::now();
std::vector<int> x {2, 4, 2, 0, 5, 10, 7, 3, 7, 1};
printf("insertion sort: ");
for (auto &i: x) printf("%d ", i);
printf("/n");
// insertion sort
for (auto i = x.begin(); i != x.end(); ++i) {
std::rotate(std::upper_bound(x.begin(), i, *i), i, i+1);
for (auto &j: x) printf("%d ", j);
printf("/n");
}
std::vector<int> heap {7, 5, 3, 4, 2};
std::make_heap(heap.begin(), heap.end());
std::pop_heap(heap.begin(), heap.end());
printf("Pop heap (%d)/n", heap.back());
heap.pop_back();
heap.push_back(1);
std::push_heap(heap.begin(), heap.end());
std::sort_heap(heap.begin(), heap.end());
for (auto &i: heap) printf("%d ", i);
printf("/n");
auto end = std::chrono::steady_clock::now();
auto diff = end - start;
printf("time: %I64d ms/n",
std::chrono::duration_cast<std::chrono::milliseconds>(diff).count());
{
auto u = v;
std::move_backward(u.begin(), u.begin() + u.size() - 1, u.begin() + u.size());
for (auto &i : u) printf("%d ", i);
printf("/n");
}
{
auto u = v;
std::move(u.begin() + 1, u.begin() + u.size(), u.begin());
for (auto &i : u) printf("%d ", i);
printf("/n");
}
start = std::chrono::steady_clock::now();
Sleep(2000);
end = std::chrono::steady_clock::now();
diff = end - start;
printf("time: %I64d ms/n",
std::chrono::duration_cast<std::chrono::milliseconds>(diff).count());
std::chrono::steady_clock::time_point before;
before = std::chrono::steady_clock::now();
Sleep(2000);
auto after = std::chrono::steady_clock::now();
printf("%f seconds/n", std::chrono::duration<double>(after - before).count());
return 0;
}
Para mi decepción, el programa final es una vez más> 2MB.
Curiosamente, cl.exe
elimina cuidadosamente todas las funciones relacionadas con iostream
manera consistente, incluso si no cl.exe main.cpp
/O2
o cualquier otra marca, solo cl.exe main.cpp
. (Para el código anterior, cl.exe
produce un binario de 100 + KB).
¿Me perdí alguna otra bandera gcc útil para esto?
Especificación:
- Mingw-w64 gcc 6.1.0
- Mingw-w64 gcc 6.2.0
- Visual Studio 2017 RC
- Todos los binarios están enlazados estáticamente
Comparar con Linux
Comparé los binarios producidos por gcc 4.9.2 (Linux) y gcc 4.9.3 (mingw-w64) para el código anterior (excepto windows.h
Sleep
se eliminaron).
Compilar bandera
g++ -o c++11 c++11.cpp -std=c++11 -static-libgcc -static-libstdc++ -ffunction-sections -Wl,-gc-sections -O2
Linux gcc -flto
éxito iostream
y las funciones sin la necesidad de -flto
mientras que Mingw-w64 gcc simplemente no puede hacerlo correctamente.
Windows solo admite el formato PE, mientras que Linux admite el formato ELF, lo que permite que Linux use el enlazador Gold. Tal vez esta es la explicación?
Actualizar
Finalmente, presenté un error en https://sourceforge.net/p/mingw-w64/bugs/578/ . ¡Esperemos que reciba alguna atención!