为什么我的简单cpp-netlib程序需要很长时间才能编译?

时间:2015-12-05 00:31:06

标签: c++ macos boost 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 with Boost Mac OSX seg fault when using HTTP Client body

我发现编译需要大约15秒钟,并且想知道我是否有办法加快这个过程?编译这段代码真的很慢吗,或者链接器花了很多时间去获取所有这些库,如果可以,我可以加快速度吗?

1 个答案:

答案 0 :(得分:3)

我似乎记得cpp-netlib使用Spirit Qi语法来进行URL解析,例如

network/uri/accessors.hpp
network/uri/uri.ipp
  

在这种情况下,减速似乎是key_value_sequence

中的accessors.hpp解析器

这些模板很重,需要花费大量时间进行编译,这取决于所使用的编译器(根据我的经验,MSVC最差)。

您可以阻止包含这些标头。至少只将它们包含在需要它的翻译单元(cpp s)中;永远不要让它陷入你的普通&#34;标头依赖项。这意味着编译器必须在每次迭代时重新编译这些东西(即使使用预编译的头文件,成本可能也很重要)。

根据您的编译器版本,这些可能有所帮助:

  • 禁用调试信息(-g0)
  • 优化尺寸(-Os)
  • 定义BOOST_SPIRIT_USE_PHOENIX_V3(默认为~1.58)
  • FUSION_MAX_VECTOR_SIZE等内容定义为较小的数字(默认值:10)

真的,如果你使用c ++ 14能力的clang,我有兴趣测试一个补丁来使用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;
}

将编译时间从〜8s减少到我系统上的~5s

  

大胖警告 X3代码未经测试(我甚至不知道是什么使用它,我只是&#34;盲目地&#34;据我所知,翻译成X3 )