Почему моя простая программа cpp-netlib так долго компилируется?
Я недавно начал изучать cpp-netlib и тестирую одну из примеров программ netlibs.
#include <boost/network/protocol/http/client.hpp>
#include <iostream>
int main()
{
using namespace boost::network;
http::client client;
http::client::request request("http://www.boost.org");
request << header("Connection", "close");
http::client::response response = client.get(request);
std::cout << body(response) << std::endl;
return 0;
}
После многих часов исследований я обнаружил, что правильная команда, которую мне нужно использовать для компиляции моей программы,
clang++ -std=c++11 -I /usr/local/Cellar/openssl/1.0.2e/include test.cpp -L /usr/local/Cellar/openssl/1.0.2e/lib -lboost_system-mt -lboost_thread-mt -lcppnetlib-client-connections -lcppnetlib-uri -lcppnetlib-server-parsers -lssl -lcrypto
Вот ссылка на старый вопрос, который я опубликовал, подробно рассказывающий, как я нашел все, что нужно этой программе для компиляции ошибки cpp-Netlib с Boost Mac OSX при использовании тела клиента HTTP
Я считаю, что для компиляции требуется около 15 секунд, и мне было интересно, есть ли способ ускорить этот процесс? Это действительно так медленно, чтобы скомпилировать этот код, или компоновщик занимает достаточно много времени, чтобы пойти и получить все эти библиотеки, и если да, могу ли я ускорить это?
1 ответ
Кажется, я помню, что cpp-netlib использует грамматику Spirit Qi для разбора URL, например
network/uri/accessors.hpp
network/uri/uri.ipp
В этом случае замедление кажется
key_value_sequence
парсер вaccessors.hpp
Они очень трудоемки и требуют значительного времени для компиляции, в зависимости лишь от используемого компилятора (на мой взгляд, MSVC был худшим).
Вы можете предотвратить включение этих заголовков. По крайней мере, включить их только в единицы перевода (cpp
у) которые этого требуют; никогда не заставляйте его попадать в ваши "общие" зависимости заголовка. Это означало бы, что компилятор должен перекомпилировать эти вещи на каждой итерации (даже с использованием предварительно скомпилированных заголовков стоимость, вероятно, будет значительной).
В зависимости от версии вашего компилятора они могут помочь:
- отключить отладочную информацию (-g0)
- оптимизировать по размеру (-Os)
- определить BOOST_SPIRIT_USE_PHOENIX_V3 (по умолчанию с ~1.58)
- определить такие вещи, как
FUSION_MAX_VECTOR_SIZE
на меньшие номера (по умолчанию: 10)
На самом деле, если вы используете C++14-совместимый кланг, мне было бы интересно протестировать патч для использования Spirit X3 вместо Qi.
По крайней мере, заменив этот парсер Qi:
#include <boost/spirit/include/qi.hpp>
// ...
namespace details {
template <typename Map>
struct key_value_sequence : spirit::qi::grammar<uri::const_iterator, Map()> {
typedef typename Map::key_type key_type;
typedef typename Map::mapped_type mapped_type;
typedef std::pair<key_type, mapped_type> pair_type;
key_value_sequence() : key_value_sequence::base_type(query) {
query = pair >> *((spirit::qi::lit(';') | '&') >> pair);
pair = key >> -('=' >> value);
key =
spirit::qi::char_("a-zA-Z_") >> *spirit::qi::char_("-+.~a-zA-Z_0-9/%");
value = +spirit::qi::char_("-+.~a-zA-Z_0-9/%");
}
spirit::qi::rule<uri::const_iterator, Map()> query;
spirit::qi::rule<uri::const_iterator, pair_type()> pair;
spirit::qi::rule<uri::const_iterator, key_type()> key;
spirit::qi::rule<uri::const_iterator, mapped_type()> value;
};
} // namespace details
template <class Map>
inline Map &query_map(const uri &uri_, Map &map) {
const uri::string_type range = uri_.query();
details::key_value_sequence<Map> parser;
spirit::qi::parse(boost::begin(range), boost::end(range), parser, map);
return map;
}
С этим вариантом X3:
#include <boost/spirit/home/x3.hpp>
// ...
namespace details {
namespace kvs_parser {
namespace x3 = boost::spirit::x3;
static auto const key = x3::char_("a-zA-Z_") >> *x3::char_("-+.~a-zA-Z_0-9/%");
static auto const value = +x3::char_("-+.~a-zA-Z_0-9/%");
template <typename Map, typename K = typename Map::key_type, typename V = typename Map::mapped_type, typename Pair = std::pair<K, V> >
static auto const pair = x3::rule<struct kvs_pair, Pair> {}
= key >> -('=' >> value);
template <typename Map>
static auto const query = pair<Map> >> *((x3::lit(';') | '&') >> pair<Map>);
}
} // namespace details
template <class Map>
inline Map &query_map(const uri &uri_, Map &map) {
const uri::string_type range = uri_.query();
spirit::x3::parse(boost::begin(range), boost::end(range), details::kvs_parser::query<Map>, map);
return map;
}
Сокращает время компиляции с ~8 с до ~5 с в моей системе
БОЛЬШОЕ ЖИРНОЕ ПРЕДУПРЕЖДЕНИЕ Код X3 не проверен (я даже не знаю, что его использует, я просто "вслепую" перевел на X3, насколько мне известно)