ページ 11

boost::iostreamsのエラーについて

Posted: 2011年8月08日(月) 22:15
by chibago
皆様、お世話になっております。
現在、pipeで取得したデータをiostream経由で処理
(読み取りサイズなど指定などの利便性を考え)
しようと奮闘しております。boost::iostreamsが便利
であるため、こちらを利用しています。
ネット上にもそこそこ情報があり、色々と試しているのですが、
どうしてもうまくいきません。エラーを見ていると何か共通の
原因があるような気がしますが、もしかしたら、環境依存
(ディストリビューションの不備)の原因があるのではないか
とおもい、ご協力いただきたいと考えおります。

とりあえず、ネット上で紹介されているサンプルに関して、
動作させたいと思います。
http://ameblo.jp/topazbc/theme2-10007112994.html
を例と致します。(ただし、main文に関しては、私の方で
追加しています。)

コード:

#include <cstdio>
#include <string>
#include <sstream>
#include <ostream>
#include <stdexcept>
#include <iostream>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>

int execcmd(const char* cmd, std::string& output)
{
    // 子プロセスを起動
    FILE* fp = popen(cmd, "r");
    if (fp == 0) {
        throw std::runtime_error(
            std::string("popen(\"")
            + cmd + "\",\"r\")"
        );
    }

    // 子プロセスの標準出力を取得
    namespace io = boost::iostreams;
   io::stream_buffer<io::file_descriptor_source>
       sb(fileno(fp));

   std::ostringstream oss;
   oss << &sb;
   oss.str().swap(output);

   // 子プロセスの終了ステータスを取得
   return pclose(fp);
}

int main(){
  std::string command = "ls -la";
  std::string output;
  execcmd(command.c_str(), output);
  std::cout<<"output :"<<output<<std::endl;

}

こちらのコンパイル結果(fedora15,gcc-4.6.0,boost-1.46)は以下のとおりです。
In file included from stream.cpp:8:0:
/usr/include/boost/iostreams/device/file_descriptor.hpp: コンストラクタ ‘boost::iostreams::file_descriptor_source::file_descriptor_source(const Path&, std::ios_base::openmode) [with Path = int, std::ios_base::openmode = std::_Ios_Openmode]’ 内:
/usr/include/boost/iostreams/stream_buffer.hpp:96:1: instantiated from ‘boost::iostreams::stream_buffer<T, Tr, Alloc, Mode>::stream_buffer(const U0&, typename boost::disable_if<boost::is_same<U0, T> >::type*) [with U0 = int, T = boost::iostreams::file_descriptor_source, Tr = std::char_traits<char>, Alloc = std::allocator<char>, Mode = boost::iostreams::input_seekable, typename boost::disable_if<boost::is_same<U0, T> >::type = void]’
stream.cpp:24:21: instantiated from here
/usr/include/boost/iostreams/device/file_descriptor.hpp:194:7: エラー: ‘int’ から ‘const char*’ への無効な変換です [-fpermissive]
/usr/include/boost/iostreams/detail/path.hpp:47:5: エラー: initializing argument 1 of ‘boost::iostreams::detail::path::path(const char*)’ [-fpermissive]

ネット上のサンプルをいろいろ試してみましたが、
file_descriptor絡みでエラーが発生するケースが多い様です。

凡ミスでしたら申し訳ありませんが、原因がお分かりになる方
がいらっしゃりましたら、ご協力いただければ幸いです。

Re: boost::iostreamsのエラーについて

Posted: 2011年8月09日(火) 02:03
by めるぽん
stream_buffer のコンストラクタを見てみると、

コード:

    stream_buffer( const T& t,
                   std::streamsize buffer_size = default_value, 
                   std::streamsize pback_size = default_value );
となっていて、T の実際の型である file_descriptor_source について見てみると、

コード:

    template<typename Path>
    file_descriptor_source( const Path& pathname, 
                            std::ios_base::open_mode mode = 
                                std::ios_base::in );
    file_descriptor_source( int fd, file_descriptor_flags );
    // Deprecated
    file_descriptor_source( int fd, bool close_on_exit = false );
というのがあったりします。
で、コンパイルエラーになるのは、この中の const Path& を受け取るコンストラクタが選択されているからですね。
(// Deprecated と書かれているコンストラクタが選択されて欲しいのでしょうけど、これは今となっては BOOST_IOSTREAMS_USE_DEPRECATED を定義しないと動かないようですし、コードが修正できる状況ならこれを定義するのはあまり良くないです)
今回だと fd と file_descriptor_flags を指定するコンストラクタを呼び出すのが正しいようなので、

コード:

   io::stream_buffer<io::file_descriptor_source>
       sb(io::file_descriptor_source(fileno(fp), io::never_close_handle));
とすれば動くと思います。

コード部分だけ読めば何となく分かると思うので、ドキュメント( http://www.boost.org/libs/iostreams/doc/index.html )を眺めてみることをオススメします。

Re: boost::iostreamsのエラーについて

Posted: 2011年8月09日(火) 12:00
by chibago
ぬるぽんさん、
ありがとうございました。

ドキュメントを読んで本格的に勉強してみようと思います。

ただ、ご提示いただいた修正を試してみましたが
コンストラクタに関してはクリアできたようですが、
他の問題が発生しているようです。
(こちらは、環境依存のもののような気がします)

エラーは以下のようなものです。

/tmp/ccwpAPxJ.o: In function `execcmd(char const*, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)':
test.cpp:(.text+0x109): undefined reference to `boost::iostreams::file_descriptor_source::file_descriptor_source(int, boost::iostreams::file_descriptor_flags)'
/tmp/ccwpAPxJ.o: In function `boost::iostreams::file_descriptor_source boost::iostreams::detail::wrap<boost::iostreams::file_descriptor_source>(boost::iostreams::file_descriptor_source const&, boost::disable_if<boost::iostreams::is_std_io<boost::iostreams::file_descriptor_source>, void>::type*)':
test.cpp:(.text._ZN5boost9iostreams6detail4wrapINS0_22file_descriptor_sourceEEET_RKS4_PNS_10disable_ifINS0_9is_std_ioIS4_EEvE4typeE[boost::iostreams::file_descriptor_source boost::iostreams::detail::wrap<boost::iostreams::file_descriptor_source>(boost::iostreams::file_descriptor_source const&, boost::disable_if<boost::iostreams::is_std_io<boost::iostreams::file_descriptor_source>, void>::type*)]+0x14): undefined reference to `boost::iostreams::file_descriptor_source::file_descriptor_source(boost::iostreams::file_descriptor_source const&)'
/tmp/ccwpAPxJ.o: In function `boost::iostreams::detail::concept_adapter<boost::iostreams::file_descriptor_source>::concept_adapter(boost::iostreams::file_descriptor_source const&)':
test.cpp:(.text._ZN5boost9iostreams6detail15concept_adapterINS0_22file_descriptor_sourceEEC2ERKS3_[_ZN5boost9iostreams6detail15concept_adapterINS0_22file_descriptor_sourceEEC5ERKS3_]+0x14): undefined reference to `boost::iostreams::file_descriptor_source::file_descriptor_source(boost::iostreams::file_descriptor_source const&)'
/tmp/ccwpAPxJ.o: In function `boost::iostreams::detail::concept_adapter<boost::iostreams::file_descriptor_source>::concept_adapter(boost::iostreams::detail::concept_adapter<boost::iostreams::file_descriptor_source> const&)':
test.cpp:(.text._ZN5boost9iostreams6detail15concept_adapterINS0_22file_descriptor_sourceEEC2ERKS4_[_ZN5boost9iostreams6detail15concept_adapterINS0_22file_descriptor_sourceEEC5ERKS4_]+0x14): undefined reference to `boost::iostreams::file_descriptor_source::file_descriptor_source(boost::iostreams::file_descriptor_source const&)'
/tmp/ccwpAPxJ.o: In function `int boost::iostreams::detail::read_device_impl<boost::iostreams::input>::read<boost::iostreams::file_descriptor_source>(boost::iostreams::file_descriptor_source&, boost::iostreams::char_type_of<boost::iostreams::file_descriptor_source>::type*, int)':
test.cpp:(.text._ZN5boost9iostreams6detail16read_device_implINS0_5inputEE4readINS0_22file_descriptor_sourceEEEiRT_PNS0_12char_type_ofIS7_E4typeEi[int boost::iostreams::detail::read_device_impl<boost::iostreams::input>::read<boost::iostreams::file_descriptor_source>(boost::iostreams::file_descriptor_source&, boost::iostreams::char_type_of<boost::iostreams::file_descriptor_source>::type*, int)]+0x1b): undefined reference to `boost::iostreams::file_descriptor::read(char*, int)'
/tmp/ccwpAPxJ.o: In function `void boost::iostreams::detail::close_impl<boost::iostreams::closable_tag>::close<boost::iostreams::file_descriptor_source>(boost::iostreams::file_descriptor_source&, std::_Ios_Openmode)':
test.cpp:(.text._ZN5boost9iostreams6detail10close_implINS0_12closable_tagEE5closeINS0_22file_descriptor_sourceEEEvRT_St13_Ios_Openmode[void boost::iostreams::detail::close_impl<boost::iostreams::closable_tag>::close<boost::iostreams::file_descriptor_source>(boost::iostreams::file_descriptor_source&, std::_Ios_Openmode)]+0x27): undefined reference to `boost::iostreams::file_descriptor::close()'
/tmp/ccwpAPxJ.o: In function `std::fpos<__mbstate_t> boost::iostreams::detail::seek_device_impl<boost::iostreams::any_tag>::seek<boost::iostreams::file_descriptor_source>(boost::iostreams::file_descriptor_source&, long long, std::_Ios_Seekdir, std::_Ios_Openmode)':
test.cpp:(.text._ZN5boost9iostreams6detail16seek_device_implINS0_7any_tagEE4seekINS0_22file_descriptor_sourceEEESt4fposI11__mbstate_tERT_xSt12_Ios_SeekdirSt13_Ios_Openmode[std::fpos<__mbstate_t> boost::iostreams::detail::seek_device_impl<boost::iostreams::any_tag>::seek<boost::iostreams::file_descriptor_source>(boost::iostreams::file_descriptor_source&, long long, std::_Ios_Seekdir, std::_Ios_Openmode)]+0x36): undefined reference to `boost::iostreams::file_descriptor::seek(long long, std::_Ios_Seekdir)'
collect2: ld returned 1 exit status

Re: boost::iostreamsのエラーについて

Posted: 2011年8月09日(火) 14:22
by めるぽん
それは Boost.Iostreams をリンクしていないだけな気がします。
Boost ライブラリの一部はリンクを必要とするものがあって、この Boost.Iostreams もその一つです。
ということでコンパイルオプションに -lboost_iostreams を追加してリンクできるかどうか試してみてください。

Re: boost::iostreamsのエラーについて

Posted: 2011年8月09日(火) 15:06
by chibago
すみません、ご指摘の通りです。
filesystemと勘違いしてました。