diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2016-07-25 08:56:48 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2016-07-25 08:56:48 +0200 |
commit | 098559ca3552ebd8f80a6d28254f4fa58913b751 (patch) | |
tree | 1eb6f65b492d3217a380a909f6810a5f3e00cc37 | |
parent | 6c8e3f09c185d7fa4664ccd9e5c4f623a17b84cc (diff) |
Add DLL export/import support
-rw-r--r-- | butl/base64 | 14 | ||||
-rw-r--r-- | butl/buildfile | 8 | ||||
-rw-r--r-- | butl/char-scanner | 4 | ||||
-rw-r--r-- | butl/export | 37 | ||||
-rw-r--r-- | butl/fdstream | 46 | ||||
-rw-r--r-- | butl/filesystem | 50 | ||||
-rw-r--r-- | butl/optional | 2 | ||||
-rw-r--r-- | butl/pager | 4 | ||||
-rw-r--r-- | butl/path | 4 | ||||
-rw-r--r-- | butl/path.cxx | 26 | ||||
-rw-r--r-- | butl/process | 6 | ||||
-rw-r--r-- | butl/sha256 | 8 | ||||
-rw-r--r-- | butl/string-table | 4 | ||||
-rw-r--r-- | butl/timestamp | 8 | ||||
-rw-r--r-- | butl/triplet | 4 | ||||
-rw-r--r-- | butl/utility | 6 | ||||
-rw-r--r-- | butl/win32-utility | 6 |
17 files changed, 155 insertions, 82 deletions
diff --git a/butl/base64 b/butl/base64 index 7a0e999..8e4f622 100644 --- a/butl/base64 +++ b/butl/base64 @@ -9,6 +9,8 @@ #include <string> #include <vector> +#include <butl/export> + namespace butl { // Base64-encode a stream or a buffer. Split the output into 76 char-long @@ -18,13 +20,13 @@ namespace butl // if it has badbit, failbit, or eofbit set and throw invalid_argument if // that's the case. Otherwise set badbit if the write operation fails. // - void + LIBBUTL_EXPORT void base64_encode (std::ostream&, std::istream&); - std::string + LIBBUTL_EXPORT std::string base64_encode (std::istream&); - std::string + LIBBUTL_EXPORT std::string base64_encode (const std::vector<char>&); // Base64-decode a stream or a string. Throw invalid_argument if the input @@ -35,13 +37,13 @@ namespace butl // invalid_argument if that's the case. Otherwise set badbit if the write // operation fails. // - void + LIBBUTL_EXPORT void base64_decode (std::ostream&, std::istream&); - void + LIBBUTL_EXPORT void base64_decode (std::ostream&, const std::string&); - std::vector<char> + LIBBUTL_EXPORT std::vector<char> base64_decode (const std::string&); }; diff --git a/butl/buildfile b/butl/buildfile index 5c939af..7a3c442 100644 --- a/butl/buildfile +++ b/butl/buildfile @@ -5,6 +5,7 @@ lib{butl}: \ {hxx cxx}{ base64 } \ {hxx cxx}{ char-scanner } \ +{hxx }{ export } \ {hxx cxx}{ fdstream } \ {hxx ixx cxx}{ filesystem } \ {hxx }{ multi-index } \ @@ -30,8 +31,15 @@ lib{butl}: \ lib{butl}: file{sha256c.c} cxx.poptions =+ -I$src_root + lib{butl}: cxx.export.poptions = -I$src_root +liba{hello}: cxx.export.poptions += -DLIBBUTL_STATIC +libs{hello}: cxx.export.poptions += -DLIBBUTL_SHARED + +obja{*}: cxx.poptions += -DLIBBUTL_STATIC_BUILD +objs{*}: cxx.poptions += -DLIBBUTL_SHARED_BUILD + # Install into the butl/ subdirectory of, say, /usr/include/. # install.include = $install.include/butl diff --git a/butl/char-scanner b/butl/char-scanner index d50745e..a3b1ad7 100644 --- a/butl/char-scanner +++ b/butl/char-scanner @@ -9,12 +9,14 @@ #include <iosfwd> #include <cstdint> // uint64_t +#include <butl/export> + namespace butl { // Low-level character stream scanner. Normally used as a base for // higher-level lexers. // - class char_scanner + class LIBBUTL_EXPORT char_scanner { public: char_scanner (std::istream& is): is_ (is) {} diff --git a/butl/export b/butl/export new file mode 100644 index 0000000..2b5a5ac --- /dev/null +++ b/butl/export @@ -0,0 +1,37 @@ +// file : butl/export -*- C++ -*- +// copyright : Copyright (c) 2014-2016 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#ifndef BUTL_EXPORT +#define BUTL_EXPORT + +// Normally we don't export class templates (but do complete specializations), +// inline functions, and classes without any member functions. But in the end +// it's all trial and error to figure out what VC needs exported. + +#if defined(LIBBUTL_STATIC) // Using static. +# define LIBBUTL_EXPORT +#elif defined(LIBBUTL_STATIC_BUILD) // Building static. +# define LIBBUTL_EXPORT +#elif defined(LIBBUTL_SHARED) // Using shared. +# ifdef _WIN32 +# define LIBBUTL_EXPORT __declspec(dllimport) +# else +# define LIBBUTL_EXPORT +# endif +#elif defined(LIBBUTL_SHARED_BUILD) // Building shared. +# ifdef _WIN32 +# define LIBBUTL_EXPORT __declspec(dllexport) +# else +# define LIBBUTL_EXPORT +# endif +#else +// If none of the above macros are defined, then we assume we are being using +// by some third-party build system that cannot/doesn't signal the library +// type. Note that this fallback works for both static and shared but in case +// of shared will be sub-optimal compared to having dllimport. +// +# define LIBBUTL_EXPORT // Using static or shared. +#endif + +#endif // BUTL_EXPORT diff --git a/butl/fdstream b/butl/fdstream index bb14f25..0caac5c 100644 --- a/butl/fdstream +++ b/butl/fdstream @@ -10,6 +10,8 @@ #include <ostream> #include <cstdint> // uint16_t +#include <butl/export> + #include <butl/path> #include <butl/filesystem> // permissions @@ -38,7 +40,7 @@ namespace butl // used // - not movable, though can be easily supported // - class fdbuf: public std::basic_streambuf<char> + class LIBBUTL_EXPORT fdbuf: public std::basic_streambuf<char> { public: virtual @@ -111,10 +113,10 @@ namespace butl skip = 0x04 }; - fdstream_mode operator& (fdstream_mode, fdstream_mode); - fdstream_mode operator| (fdstream_mode, fdstream_mode); - fdstream_mode operator&= (fdstream_mode&, fdstream_mode); - fdstream_mode operator|= (fdstream_mode&, fdstream_mode); + inline fdstream_mode operator& (fdstream_mode, fdstream_mode); + inline fdstream_mode operator| (fdstream_mode, fdstream_mode); + inline fdstream_mode operator&= (fdstream_mode&, fdstream_mode); + inline fdstream_mode operator|= (fdstream_mode&, fdstream_mode); // Extended (compared to ios::openmode) file open flags. // @@ -132,12 +134,12 @@ namespace butl none = 0 // Usefull when build the mode incrementally. }; - fdopen_mode operator& (fdopen_mode, fdopen_mode); - fdopen_mode operator| (fdopen_mode, fdopen_mode); - fdopen_mode operator&= (fdopen_mode&, fdopen_mode); - fdopen_mode operator|= (fdopen_mode&, fdopen_mode); + inline fdopen_mode operator& (fdopen_mode, fdopen_mode); + inline fdopen_mode operator| (fdopen_mode, fdopen_mode); + inline fdopen_mode operator&= (fdopen_mode&, fdopen_mode); + inline fdopen_mode operator|= (fdopen_mode&, fdopen_mode); - class fdstream_base + class LIBBUTL_EXPORT fdstream_base { protected: fdstream_base () = default; @@ -180,7 +182,7 @@ namespace butl // Note that ifdstream destructor will close an open file descriptor but // will ignore any errors. To detect such errors, call close() explicitly. // - class ifdstream: fdstream_base, public std::istream + class LIBBUTL_EXPORT ifdstream: fdstream_base, public std::istream { public: // Create an unopened object with iostate = badbit | failbit (we cannot @@ -260,7 +262,7 @@ namespace butl // (std::uncaught_exception() == true). This is enforced with assert() in // the ofdstream destructor. // - class ofdstream: fdstream_base, public std::ostream + class LIBBUTL_EXPORT ofdstream: fdstream_base, public std::ostream { public: // Create an unopened object with iostate = badbit | failbit (we cannot @@ -344,7 +346,7 @@ namespace butl // - The fail and eof bits may be left cleared in the stream exception mask // when the function throws because of badbit. // - ifdstream& + LIBBUTL_EXPORT ifdstream& getline (ifdstream&, std::string&, char delim = '\n'); // Open a file returning the file descriptor on success and throwing @@ -363,21 +365,21 @@ namespace butl // process' umask, so effective permissions are permissions & ~umask. On // Windows permissions other than ru and wu are unlikelly to have effect. // - int + LIBBUTL_EXPORT int fdopen (const char*, fdopen_mode, permissions = permissions::ru | permissions::wu | permissions::rg | permissions::wg | permissions::ro | permissions::wo); - int + LIBBUTL_EXPORT int fdopen (const std::string&, fdopen_mode, permissions = permissions::ru | permissions::wu | permissions::rg | permissions::wg | permissions::ro | permissions::wo); - int + LIBBUTL_EXPORT int fdopen (const path&, fdopen_mode, permissions = permissions::ru | permissions::wu | @@ -387,15 +389,15 @@ namespace butl // Set the translation mode for the file descriptor. Return the previous // mode on success, throw ios::failure otherwise. // - fdstream_mode + LIBBUTL_EXPORT fdstream_mode fdmode (int, fdstream_mode); // Convenience functions for setting the translation mode for standard // streams. // - fdstream_mode stdin_fdmode (fdstream_mode); - fdstream_mode stdout_fdmode (fdstream_mode); - fdstream_mode stderr_fdmode (fdstream_mode); + LIBBUTL_EXPORT fdstream_mode stdin_fdmode (fdstream_mode); + LIBBUTL_EXPORT fdstream_mode stdout_fdmode (fdstream_mode); + LIBBUTL_EXPORT fdstream_mode stderr_fdmode (fdstream_mode); // Low-level, nothrow file descriptor API. // @@ -403,7 +405,7 @@ namespace butl // Close the file descriptor. Return true on success, set errno and return // false otherwise. // - bool + LIBBUTL_EXPORT bool fdclose (int) noexcept; // Open the null device (e.g., /dev/null) that discards all data written to @@ -412,7 +414,7 @@ namespace butl // Note that it's the caller's responsibility to close the returned file // descriptor. // - int + LIBBUTL_EXPORT int fdnull () noexcept; } diff --git a/butl/filesystem b/butl/filesystem index 7b23fc5..2c4f3a4 100644 --- a/butl/filesystem +++ b/butl/filesystem @@ -25,6 +25,8 @@ #include <utility> // move() #include <iterator> +#include <butl/export> + #include <butl/path> #include <butl/timestamp> @@ -33,13 +35,13 @@ namespace butl // Return true if the path is to an existing directory. Note that // this function resolves symlinks. // - bool + LIBBUTL_EXPORT bool dir_exists (const path&); // Return true if the path is to an existing regular file. Note that // this function resolves symlinks. // - bool + LIBBUTL_EXPORT bool file_exists (const path&); // Try to create a directory unless it already exists. If you expect @@ -55,13 +57,13 @@ namespace butl // enum class mkdir_status {success, already_exists}; - mkdir_status + LIBBUTL_EXPORT mkdir_status try_mkdir (const dir_path&, mode_t = 0777); // The '-p' version of the above (i.e., it creates the parent // directories if necessary). // - mkdir_status + LIBBUTL_EXPORT mkdir_status try_mkdir_p (const dir_path&, mode_t = 0777); // Try to remove the directory returning not_exist if it does not exist @@ -70,20 +72,20 @@ namespace butl // enum class rmdir_status {success, not_exist, not_empty}; - rmdir_status + LIBBUTL_EXPORT rmdir_status try_rmdir (const dir_path&, bool ignore_error = false); // The '-r' (recursive) version of the above. Note that it will // never return not_empty. // - rmdir_status + LIBBUTL_EXPORT rmdir_status try_rmdir_r (const dir_path&, bool ignore_error = false); // As above but throws rather than returns not_exist if the directory // does not exist (unless ignore_error is true), so check before calling. // If the second argument is false, then the directory itself is not removed. // - void + LIBBUTL_EXPORT void rmdir_r (const dir_path&, bool dir = true, bool ignore_error = false); // Try to remove the file (or symlinks) returning not_exist if @@ -92,7 +94,7 @@ namespace butl // enum class rmfile_status {success, not_exist}; - rmfile_status + LIBBUTL_EXPORT rmfile_status try_rmfile (const path&, bool ignore_error = false); // Automatically try to remove the path on destruction unless cancelled. @@ -132,7 +134,7 @@ namespace butl // // Note that Windows symlinks are currently not supported. // - void + LIBBUTL_EXPORT void mksymlink (const path& target, const path& link, bool dir = false); // Create a symbolic link to a directory. Throw std::system_error on @@ -151,7 +153,7 @@ namespace butl // be a directory. While Windows support directories (via junktions), this // is currently not implemented. // - void + LIBBUTL_EXPORT void mkhardlink (const path& target, const path& link, bool dir = false); // Create a hard link to a directory. Throw std::system_error on failures. @@ -172,10 +174,10 @@ namespace butl none = 0 }; - cpflags operator& (cpflags, cpflags); - cpflags operator| (cpflags, cpflags); - cpflags operator&= (cpflags&, cpflags); - cpflags operator|= (cpflags&, cpflags); + inline cpflags operator& (cpflags, cpflags); + inline cpflags operator| (cpflags, cpflags); + inline cpflags operator&= (cpflags&, cpflags); + inline cpflags operator|= (cpflags&, cpflags); // Copy a regular file, including its permissions. Throw std::system_error // on failure. Fail if the destination file exists and the overwrite_content @@ -192,7 +194,7 @@ namespace butl // destination is a dangling symbolic link, then this function will still // fail. // - void + LIBBUTL_EXPORT void cpfile (const path& from, const path& to, cpflags = cpflags::none); // Copy a regular file to an existing directory. @@ -208,7 +210,7 @@ namespace butl // by throwing std::system_error. Note that this function resolves // symlinks. // - timestamp + LIBBUTL_EXPORT timestamp file_mtime (const path&); // Path permissions. @@ -232,21 +234,21 @@ namespace butl none = 0 }; - permissions operator& (permissions, permissions); - permissions operator| (permissions, permissions); - permissions operator&= (permissions&, permissions); - permissions operator|= (permissions&, permissions); + inline permissions operator& (permissions, permissions); + inline permissions operator| (permissions, permissions); + inline permissions operator&= (permissions&, permissions); + inline permissions operator|= (permissions&, permissions); // Get path permissions. Throw std::system_error on failure. Note that this // function resolves symlinks. // - permissions + LIBBUTL_EXPORT permissions path_permissions (const path&); // Set path permissions. Throw std::system_error on failure. Note that this // function resolves symlinks. // - void + LIBBUTL_EXPORT void path_permissions (const path&, permissions); // Directory entry iteration. @@ -260,7 +262,7 @@ namespace butl other }; - class dir_entry + class LIBBUTL_EXPORT dir_entry { public: typedef butl::path path_type; @@ -299,7 +301,7 @@ namespace butl dir_path b_; }; - class dir_iterator + class LIBBUTL_EXPORT dir_iterator { public: typedef dir_entry value_type; diff --git a/butl/optional b/butl/optional index 86bbe59..0ae7e7b 100644 --- a/butl/optional +++ b/butl/optional @@ -12,7 +12,7 @@ namespace butl // Simple optional class template while waiting for std::optional. // struct nullopt_t {constexpr nullopt_t (int) {}}; - constexpr nullopt_t nullopt = 1; + constexpr const nullopt_t nullopt = 1; template <typename T> class optional @@ -9,6 +9,8 @@ #include <vector> #include <iostream> +#include <butl/export> + #include <butl/process> #include <butl/fdstream> @@ -42,7 +44,7 @@ namespace butl // cerr << "pager error: " << e.what () << endl; // } // - class pager: protected std::streambuf + class LIBBUTL_EXPORT pager: protected std::streambuf { public: ~pager () {wait (true);} @@ -12,6 +12,8 @@ #include <exception> #include <functional> // hash +#include <butl/export> + namespace butl { @@ -25,7 +27,7 @@ namespace butl // p -= ".*"; // base // - class invalid_path_base: std::exception + class LIBBUTL_EXPORT invalid_path_base: std::exception { public: virtual char const* diff --git a/butl/path.cxx b/butl/path.cxx index 1693c86..46e36fd 100644 --- a/butl/path.cxx +++ b/butl/path.cxx @@ -28,6 +28,8 @@ #include <cassert> #include <system_error> +#include <butl/export> + #include <butl/process> #ifndef _WIN32 @@ -55,7 +57,7 @@ namespace butl // template <> - path_traits<char>::string_type path_traits<char>:: + LIBBUTL_EXPORT path_traits<char>::string_type path_traits<char>:: current () { // @@ throw system_error (and in the other current() versions). @@ -74,7 +76,7 @@ namespace butl } template <> - void path_traits<char>:: + LIBBUTL_EXPORT void path_traits<char>:: current (string_type const& s) { #ifdef _WIN32 @@ -140,7 +142,7 @@ namespace butl #endif template <> - path_traits<char>::string_type path_traits<char>:: + LIBBUTL_EXPORT path_traits<char>::string_type path_traits<char>:: temp_directory () { #ifdef _WIN32 @@ -162,7 +164,7 @@ namespace butl static atomic<size_t> temp_name_count; template <> - path_traits<char>::string_type path_traits<char>:: + LIBBUTL_EXPORT path_traits<char>::string_type path_traits<char>:: temp_name (string_type const& prefix) { return prefix @@ -171,7 +173,7 @@ namespace butl } template <> - path_traits<char>::string_type path_traits<char>:: + LIBBUTL_EXPORT path_traits<char>::string_type path_traits<char>:: home () { #ifndef _WIN32 @@ -197,7 +199,7 @@ namespace butl #ifndef _WIN32 template <> - void path_traits<char>:: + LIBBUTL_EXPORT void path_traits<char>:: realize (string_type& s) { char r[PATH_MAX]; @@ -221,7 +223,7 @@ namespace butl // template <> - path_traits<wchar_t>::string_type path_traits<wchar_t>:: + LIBBUTL_EXPORT path_traits<wchar_t>::string_type path_traits<wchar_t>:: current () { #ifdef _WIN32 @@ -242,7 +244,7 @@ namespace butl } template <> - void path_traits<wchar_t>:: + LIBBUTL_EXPORT void path_traits<wchar_t>:: current (string_type const& s) { #ifdef _WIN32 @@ -262,7 +264,7 @@ namespace butl } template <> - path_traits<wchar_t>::string_type path_traits<wchar_t>:: + LIBBUTL_EXPORT path_traits<wchar_t>::string_type path_traits<wchar_t>:: temp_directory () { #ifdef _WIN32 @@ -295,7 +297,7 @@ namespace butl } template <> - path_traits<wchar_t>::string_type path_traits<wchar_t>:: + LIBBUTL_EXPORT path_traits<wchar_t>::string_type path_traits<wchar_t>:: temp_name (string_type const& prefix) { return prefix + @@ -304,7 +306,7 @@ namespace butl } template <> - path_traits<wchar_t>::string_type path_traits<wchar_t>:: + LIBBUTL_EXPORT path_traits<wchar_t>::string_type path_traits<wchar_t>:: home () { #ifndef _WIN32 @@ -339,7 +341,7 @@ namespace butl #ifndef _WIN32 template <> - void path_traits<wchar_t>:: + LIBBUTL_EXPORT void path_traits<wchar_t>:: realize (string_type&) { assert (false); // Implement if/when needed. diff --git a/butl/process b/butl/process index e864b53..fc8c1e8 100644 --- a/butl/process +++ b/butl/process @@ -13,9 +13,11 @@ #include <cstdint> // uint32_t #include <system_error> +#include <butl/export> + namespace butl { - struct process_error: std::system_error + struct LIBBUTL_EXPORT process_error: std::system_error { bool child () const {return child_;} @@ -34,7 +36,7 @@ namespace butl bool child_; }; - class process + class LIBBUTL_EXPORT process { public: // Start another process using the specified command line. The default diff --git a/butl/sha256 b/butl/sha256 index a1d0c38..77fa6bd 100644 --- a/butl/sha256 +++ b/butl/sha256 @@ -10,6 +10,8 @@ #include <cstdint> #include <cstddef> // size_t +#include <butl/export> + namespace butl { // SHA256 checksum calculator. @@ -19,7 +21,7 @@ namespace butl // // cerr << sha256 ("123").string () << endl; // - class sha256 + class LIBBUTL_EXPORT sha256 { public: sha256 (); @@ -85,14 +87,14 @@ namespace butl // like 01:AB:CD:...). Throw invalid_argument if the argument is not a valid // SHA256 string. // - std::string + LIBBUTL_EXPORT std::string sha256_to_fingerprint (const std::string&); // Convert a fingerprint (32 colon-separated hex digit pairs) to the SHA256 // string representation (64 lower case hex digits). Throw invalid_argument // if the argument is not a valid fingerprint. // - std::string + LIBBUTL_EXPORT std::string fingerprint_to_sha256 (const std::string&); }; diff --git a/butl/string-table b/butl/string-table index d07c75a..cf2a20b 100644 --- a/butl/string-table +++ b/butl/string-table @@ -9,6 +9,8 @@ #include <string> #include <unordered_map> +#include <butl/export> + #include <butl/multi-index> namespace butl @@ -36,7 +38,7 @@ namespace butl struct string_table_traits; template <> - struct string_table_traits<std::string> + struct LIBBUTL_EXPORT string_table_traits<std::string> { static const std::string& key (const std::string& d) {return d;} diff --git a/butl/timestamp b/butl/timestamp index 02f8a92..04a65b7 100644 --- a/butl/timestamp +++ b/butl/timestamp @@ -8,6 +8,8 @@ #include <chrono> #include <iosfwd> +#include <butl/export> + #include <butl/path> namespace butl @@ -75,7 +77,7 @@ namespace butl // - support %(N) version for non-optional printing // - support for suffix %[<d>N<s>], for example %[N nsec] // - std::ostream& + LIBBUTL_EXPORT std::ostream& to_stream (std::ostream&, const timestamp&, const char* format, @@ -88,7 +90,7 @@ namespace butl return to_stream (os, ts, "%Y-%m-%d %H:%M:%S%[.N]", true, true); } - std::ostream& + LIBBUTL_EXPORT std::ostream& operator<< (std::ostream&, const duration&); // Parse human-readable representation of the timestamp. @@ -130,7 +132,7 @@ namespace butl // - ability to parse local, return UTC and vice-versa // - handle timezone parsing // - timestamp + LIBBUTL_EXPORT timestamp from_string (const char* input, const char* format, bool local, diff --git a/butl/triplet b/butl/triplet index 44b5195..013818e 100644 --- a/butl/triplet +++ b/butl/triplet @@ -7,6 +7,8 @@ #include <string> +#include <butl/export> + namespace butl { // This is the ubiquitous 'target triplet' that loosely has the CPU-VENDOR-OS @@ -93,7 +95,7 @@ namespace butl // // 2. LLVM has the Triple class with similar goals. // - struct triplet + struct LIBBUTL_EXPORT triplet { std::string cpu; std::string vendor; diff --git a/butl/utility b/butl/utility index efbb13b..2436616 100644 --- a/butl/utility +++ b/butl/utility @@ -9,11 +9,13 @@ #include <utility> // forward() #include <cstring> // strcmp +#include <butl/export> + namespace butl { // Key comparators (i.e., to be used in sets, maps, etc). // - struct compare_c_string + struct LIBBUTL_EXPORT compare_c_string { bool operator() (const char* x, const char* y) const { @@ -21,7 +23,7 @@ namespace butl } }; - struct compare_pointer_target + struct LIBBUTL_EXPORT compare_pointer_target { template <typename P> bool operator() (const P& x, const P& y) const {return *x < *y;} diff --git a/butl/win32-utility b/butl/win32-utility index c74eb66..c446485 100644 --- a/butl/win32-utility +++ b/butl/win32-utility @@ -35,14 +35,16 @@ #include <string> +#include <butl/export> + namespace butl { namespace win32 { - std::string + LIBBUTL_EXPORT std::string error_msg (DWORD code); - std::string + LIBBUTL_EXPORT std::string last_error_msg (); } }; |