0

I tried to do this: create 1 shared library on Windows (*.dll) which uses Boost::Log (I want to link the Boost::Log to this library statically since I want everything was packaged in only 1 DLL file) but not successful.

My project has 4 files as the following:

My CMakeLists.txt: ( There is another CMakeLists.txt that finds Boost library with find_package(Boost 1.54.0 REQUIRED thread log log_setup filesystem date_time system) )

cmake_minimum_required(VERSION 2.6)

add_library(mylog SHARED
  mylog.cpp
  )
target_link_libraries(mylog ${Boost_LIBRARIES})

if(UNIX)
  target_link_libraries(mylog rt)
endif(UNIX)

add_executable(testlog
  main.cpp
  )
target_link_libraries(testlog mylog)

My mylog.cpp:

#include "mylog.h"

namespace logging = boost::log;
namespace expr = boost::log::expressions;
namespace keywords = boost::log::keywords;

__declspec( dllexport ) void initLog()
{
    logging::add_file_log(
    keywords::file_name = "testlog.log",    
    keywords::format = expr::format("%1% [%2%] %3% ")
        % expr::format_date_time< boost::posix_time::ptime >("TimeStamp", "%Y-%m-%d, %H:%M:%S.%f")
        % expr::attr< logging::trivial::severity_level >("Severity")
        % expr::smessage
    );

    logging::add_common_attributes();
}

And mylog.h:

#ifndef _MYLOG_H
#define _MYLOG_H

#include <boost/log/common.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/attributes.hpp>
#include <boost/log/sinks.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/log/utility/empty_deleter.hpp>

__declspec( dllexport ) void initLog();

#endif //_MYLOG_H

My main.cpp:

#include "mylog.h"

int main(int, char*[])
{
    using namespace boost::log::trivial;
    initLog();
    BOOST_LOG_TRIVIAL(trace) << "A trace severity message";
    BOOST_LOG_TRIVIAL(debug) << "A debug severity message";
    BOOST_LOG_TRIVIAL(info) << "An informational severity message";
    BOOST_LOG_TRIVIAL(warning) << "A warning severity message";
    BOOST_LOG_TRIVIAL(error) << "An error severity message";
    BOOST_LOG_TRIVIAL(fatal) << "A fatal severity message";    
    return 0;
}

When I compiled the library mylog as a static one (without SHARED keyword) and ran program testlog, log messages were saved in the file testlog.log and no thing printed to the screen as the code said:

2013-12-20, 15:05:36.741156 [trace] A trace severity message         
2013-12-20, 15:05:36.742156 [debug] A debug severity message         
2013-12-20, 15:05:36.743156 [info] An informational severity message 
2013-12-20, 15:05:36.743156 [warning] A warning severity message     
2013-12-20, 15:05:36.743156 [error] An error severity message        
2013-12-20, 15:05:36.743156 [fatal] A fatal severity message         

But if I compile it to a DLL shared library (with SHARED keyword), the compilation was successful but the result was not as expected. No log file created and messages were displayed to the screen with different format. It looks like the function initLog was not run:

[2013-12-20 15:06:17.195469] [0x00000e6c] [trace]   A trace severity message          
[2013-12-20 15:06:17.198470] [0x00000e6c] [debug]   A debug severity message          
[2013-12-20 15:06:17.198470] [0x00000e6c] [info]    An informational severity message 
[2013-12-20 15:06:17.199470] [0x00000e6c] [warning] A warning severity message        
[2013-12-20 15:06:17.199470] [0x00000e6c] [error]   An error severity message         
[2013-12-20 15:06:17.200470] [0x00000e6c] [fatal]   A fatal severity message          

Please help me on this. Thanks.

P/S: I have also tried creating custom sinks for logging, not using Boost::Log::Trivial but the result is the same. Both Boost 1.54.0 and 1.55.0 are tested.

kevin.bui
  • 51
  • 1
  • 7

2 Answers2

1

It appears you need to configure and build boost::log appropriately to support dynamic linking. Otherwise, it assumes a static link model.

Documentation here: http://boost-log.sourceforge.net/libs/log/doc/html/log/installation/config.html

Relevant quote:

The library has a separately compiled part which should be built as described in the Getting Started guide. One thing should be noted, though. If your application consists of more than one module (e.g. an exe and one or several dll's) that use Boost.Log, the library must be built as a shared object. If you have a single executable or a single module that works with Boost.Log, you may build the library as a static library.

Joe Z
  • 17,413
  • 3
  • 28
  • 39
  • Thanks for your reply. The problem is, if I add definition -DBOOST_LOG_DYN_LINK, it will be built dynamically which means the program __testlog__ will also need __boost_log_\*.dll__ to run properly while I want to find a way to integrate Boost::Log to only 1 DLL file. – kevin.bui Dec 20 '13 at 09:25
  • @kevin.bui : I don't know the Windows dev environment very well, but it seems like, in principle, once you have your two DLLs (one with your code, and one with Boost's), you could merge them into one. **Edit**: Googling around suggests that that's a pretty tall order, apparently. – Joe Z Dec 20 '13 at 14:21
  • I googled your suggestion but it seems they just join 2 files together, but that way might generate namespace conflict. Besides, I still do not understand the way Boost react like this. Anw, thanks for your suggestion. – kevin.bui Dec 23 '13 at 02:34
0

You need a dllimport attribute on your initLog() prototype on the calling end. An idiomatic approach is to use a preprocessor define to tell mylog.h whether it is included from the DLL build, in which case it needs dllexport, or from an executable linked against the DLL, in which case it needs dllimport:

mylog.h:

#ifdef BUILD_MYLOG_DLL
#define DLLATTRIBUTE __declspec( dllexport )
#else
#define DLLATTRIBUTE __declspec( dllimport )
#endif

DLLATTRIBUTE void initLog();

CMakeLists.txt:

SET_TARGET_PROPERTIES(mylog PROPERTIES COMPILE_DEFINITIONS "BUILD_MYLOG_DLL")

Now the dllexport is only used when building the mylog library, and anything else that includes the file will get dllimport instead.

If you want to support static mode as well, add another condition around the entire BUILD_MYLOG_DLL clause which defines DLLATTRIBUTE to empty.

Peter
  • 14,559
  • 35
  • 55
  • I did try your way, but it is still not successful. When it build mylog.cpp and mylog.h, the compiler does use dllexport and when main.cpp was built, dllimport was use. But the result is still the same. Could you help me to try on your computer? Thanks. – kevin.bui Dec 23 '13 at 02:29