Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Eradicating unneeded libraries from linker invocation

19 views
Skip to first unread message

Frederick Virchanza Gotham

unread,
Sep 30, 2022, 6:46:45 AM9/30/22
to
Let's say you have a linker invocation as follows:

g++ -o prog *.o -lmonkey -lcow -lfish -ldog

I've written a program that parses your linker command and tries it without each of the libraries. If the linking succeeds, then it tells you that the library in question isn't needed.

Sample invocation:

./linker_reducer "g++ -o prog *.o -pthread -lwx_gtk3u_xrc-3.1 -lwx_gtk3u_html-3.1 -lwx_gtk3u_qa-3.1 -lwx_gtk3u_core-3.1 -lwx_baseu_xml-3.1 -lwx_baseu_net-3.1 -lwx_baseu-3.1 -lpcap -lpthread -ldl"

Sample output:

Trying without '-lwx_gtk3u_xrc-3.1' [SUCCESS]
Trying without '-lwx_gtk3u_html-3.1' [SUCCESS]
Trying without '-lwx_gtk3u_qa-3.1' [SUCCESS]
Trying without '-lwx_gtk3u_core-3.1' [FAILURE]
Trying without '-lwx_baseu_xml-3.1' [SUCCESS]
Trying without '-lwx_baseu_net-3.1' [SUCCESS]
Trying without '-lwx_baseu-3.1' [FAILURE]
Trying without '-lpcap' [SUCCESS]
Trying without '-lpthread' [SUCCESS]
Trying without '-ldl' [SUCCESS]

Not needed:
-lwx_gtk3u_xrc-3.1
-lwx_gtk3u_html-3.1
-lwx_gtk3u_qa-3.1
-lwx_baseu_xml-3.1
-lwx_baseu_net-3.1
-lpcap
-lpthread
-ldl

Revised Linker invocation command:

g++ -o prog *.o -pthread -lwx_gtk3u_core-3.1 -lwx_baseu-3.1

Here's the source code. Tested and working on Linux. Probably works on MS-Windows.

#include <cstddef> // size_t
#include <cstdlib> // system, EXIT_FAILURE
#include <algorithm> // max
#include <tuple> // tuple, std::get<>
#include <vector> // vector
#include <string> // string
#include <string_view> // string_view
#include <regex> // regex
#include <iostream> // cout, endl

using std::size_t;
using std::string;
using std::sregex_iterator;
using std::cout;
using std::endl;

// The vector on the next line works as follows:
// { true /* is_required */, char_index_of_library_in_string, "library_string" };
std::vector< std::tuple<bool, size_t, string> > g_libs;

string Remove_Library(std::string_view const sv, size_t const index)
{
string s(sv);

std::tuple<bool, size_t, string> const &x = g_libs.at(index);

s.erase( std::get<1u>(x), std::get<2u>(x).size() );

return s;
}

int main(int const argc, char **const argv)
{
if ( argc < 2u || argc > 3u )
{
cout << "This program takes two command line arguments.\n"
"The first is the full linker invocation command, and\n"
"the second is the regex to match a library. For example:\n\n"
" " << argv[0u] << " \"g++ -o prog *.cpp -lmonkey -lcow\" -l[^\\s]+" << "\n\n";

return EXIT_FAILURE;
}

string linker_command{ argv[1u] };

std::regex const my_regex{ (3u == argc) ? argv[2u] : "-l[^\\s]+" };

size_t longest_library_name = 0u;

for ( sregex_iterator it = sregex_iterator(linker_command.begin(), linker_command.end(), my_regex);
it != sregex_iterator();
++it )
{
std::smatch const m{ *it };

//cout << m.str() << " at position " << m.position() << " with length " << m.str().size() << '\n';

g_libs.emplace_back(std::tuple<bool, size_t, string>(true, m.position(), m.str()));

longest_library_name = std::max(longest_library_name, m.str().size());
}

size_t i = -1;
for ( auto &e : g_libs )
{
++i;

string revised_linker_command( Remove_Library(linker_command,i) );

cout << "Trying without '" << std::get<2u>(e) << "' ";

for ( size_t i = 0u; i < (longest_library_name - std::get<2u>(e).size()); ++i ) cout << " ";

cout << std::flush;

#if defined(_WIN32) || defined(_WIN64)
revised_linker_command += " > NUL 2> NUL";
#else
revised_linker_command += " > /dev/null 2> /dev/null";
#endif

int status = std::system(revised_linker_command.c_str());

#if defined(_WIN32) || defined(_WIN64)
/* Do Nothing for MS-Windows */
#else
/* Linux needs a little adjusting */
if ( status < 0 ) status = -1;
else if ( WIFEXITED(status) ) status = WEXITSTATUS(status);
else status = -1;
#endif

bool successful = (0==status);

std::get<0u>(e) = !successful;

cout << " ["
<< ( successful ? "SUCCESS]\n" : "FAILURE]\n");
}

cout << "\n\nNot needed:\n";

for ( auto const &e : g_libs )
{
if ( false == std::get<0u>(e) )
{
cout << " " << std::get<2u>(e) << endl;
}
}

cout << "\n\nRevised Linker invocation command:\n\n";

size_t accumulated = 0u;

for ( auto const &e : g_libs )
{
if ( false == std::get<0u>(e) )
{
linker_command.erase(std::get<1u>(e) - accumulated, std::get<2u>(e).size());
accumulated += std::get<2u>(e).size();
}
}

cout << " " << linker_command << endl;
}
0 new messages