I have recently ran into an error when compiling my program with the boost serialization library.
I have read across many forums that I need to link the boost serialization library (-lboost_serialization). Which, I did.
However, there is one error that I am getting on the code:
/usr/local/boost_1_64_0/boost/serialization/throw_exception.hpp:36: undefined reference to `boost::archive::archive_exception::archive_exception(boost::archive::archive_exception const&)'
So I thought, what if I have to also include the exception library?
So I added this into the libraries for my compiler settings:
-lboost_exception
However, now it is saying that it is unable to find the boost_exception library. Which is interesting because I am able to see it in the file system!
I am wondering if I am doing the right thing or am I forgetting to add something to my compiler settings? Any help will be much appreciated!
Edit:
Here is the code:
// MS compatible compilers support #pragma once
#if defined(_MSC_VER)
# pragma once
#endif
// boost/throw_exception.hpp
//
// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#ifndef BOOST_NO_EXCEPTIONS
#include <exception>
#endif
namespace boost {
namespace serialization {
#ifdef BOOST_NO_EXCEPTIONS
inline void throw_exception(std::exception const & e) {
::boost::throw_exception(e);
}
#else
template<class E> inline void throw_exception(E const & e){
throw e;// Error occurs here
}
#endif
} // namespace serialization
} // namespace boost
Here is a code sample where the breakage occurs
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <vector>
#include "boost/serialization/vector.hpp"
#include <string>
#include <fstream>
int main()
{
std::ofstream ofs("/home/phillip/test.txt");
std::vector<std::string> tests;
boost::archive::text_oarchive oa(ofs);
oa << tests;
}
I've seen this happen when linking to the boost library when compiling with a different compiler/version/flags.
E.g. many Boost Serialization answer programs wouldn't link when compiling with Clang on Coliru whereas they'd run fine when compiling with Gcc
Related
I am a beginner to cuda, c++ and I am trying to move openssl sha1 cpu code to cuda c,but I ran into a weired problem.
here is the minimum code that can reproduce the problem.
There are three files in this vs2015 cuda9.0 project. They are main.cpp ,sha1.cu and sha1.h
//main.cpp
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include "openssl\sha.h"
int main()
{
SHA_CTX ctx;
SHA1_Init(&ctx);
return 0;
}
//sha1.h
#ifndef SHA1_H
#define SHA1_H
#include <stdint.h>
#include <cuda_runtime.h>
namespace cudatest {
#ifdef __cplusplus
extern "C" {
#endif
typedef struct
{
uint32_t state[5];
uint32_t count[2];
unsigned char buffer[64];
} SHA1_CTX;
#define SHA_CTX SHA1_CTX
#define SHA_DIGEST_LENGTH 20
__device__ void SHA1_Init(SHA1_CTX * context);
#ifdef __cplusplus
}
#endif
}
#endif /* SHA1_H */
//sha1.cu
#include <cuda_runtime.h>
#include "sha1.h"
namespace cudatest {
__device__ void SHA1_Init(SHA1_CTX * context)
{
}
}
The main.cpp uses C/C++ compiler and sha1.cu uses CUDA C/C++
And I add openssl headers into the AdditionalIncludeDirectories,set directory which contains ssleay32.lib and libeay32.lib to library path,set AdditionalDependencies with ssleay32.lib, libeay32.lib .
Then the project built with no error and no warning. But when I run it
or debug it,I found the function SHA1_Init runs into device code and
the program crashed immediately.
why the compiler linked function SHA1_Init with the cuda device
SHA1_Init implement which has a namespace cudatest wrapped instead
of a ssleay32.lib, libeay32.lib CPU implement?
OK,I found the problem.I shouldn't use extern "C" in a c++ namespace.It make the function visiable to the global namespace. if you define another c SHA1_Init function in a .cpp file ,the linker will complain.But if another SHA1_Init is in a openssl lib,the vs C/C++ linker warnned nothing but linked to the cuda implement.
When compiling my .cpp file with Rcpp in R, this error message comes :
undefined reference to `boost::system::generic_category()'
But when I remove the // [[Rcpp::plugins(cpp11)]] line, there isn't any error anymore. Why?
Here is my minimal reproducible example.
// include Rcpp, it takes care of most other headers you need
#include <Rcpp.h>
#include <boost/array.hpp>
// include Boost's odeint
#include <boost/numeric/odeint.hpp>
#include <boost/numeric/odeint/integrate/integrate_adaptive.hpp>
#include <boost/filesystem/fstream.hpp>
#include <functional>
// tell R you need Boost
// [[Rcpp::depends(BH)]]
// [[Rcpp::plugins(cpp11)]]
using namespace Rcpp;
using namespace std;
using namespace boost::numeric::odeint;
typedef boost::array< double ,130 > state_type;
// [[Rcpp::export]]
void my_fun22(Rcpp::NumericVector &x, const double t,const Rcpp::NumericVector theta){
Function f("mod_cpp");
x=f(_["t"]=t,_["x"]=x,_["p1"]=theta);
}
Yet another elementary issue: Boost System (generally) requires linking which is a whole different ball game than just pointing to Boost headers via the BH package. And the very standard error message undefined reference comes from the linker / failed attempts to locate a symbol.
We discuss the use of linking to Boost libraries in some posts on the Rcpp Gallery, but the short of it is that there is no portable way to provide linking to Boost libraries across the OSs used by R.
Below is a minimal example to use the great Boost.Serialization library.
To compile the library I need to link with the boost_serialization precompiled library.
$ c++ -std=c++11 example.cpp -o example.x -lboost_serialization
^^^^^^^^^^^^^^^^^^^^^
The library is heavily templated an although complicated internally the actual code (function body) is quite simple. There are only a few references that need the linking, namely:
boost::archive::text_oarchive_impl<boost::archive::text_oarchive>::text_oarchive_impl(std::ostream&, unsigned int)
boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::text_iarchive_impl(std::istream&, unsigned int)
boost::archive::text_iarchive_impl<boost::archive::text_oarchive>::~text_oarchive_impl()
boost::archive::text_iarchive_impl<boost::archive::text_iarchive>::~text_iarchive_impl()
...
boost::archive::archive_exception::~archive_exception()'
Is there a chance that the library can be used without linking as a header-only library?
For example some undocumented trick or hack?
That would make it more simple to use in some supercomputer clusters and environments where it is not that simply to compile Boost.
#include<sstream>
#include<numeric>
#include<boost/archive/text_oarchive.hpp> // needs linking
#include<boost/archive/text_iarchive.hpp>
#include<boost/serialization/vector.hpp>
int main(){
std::vector<double> v(10); std::iota(v.begin(), v.end(), 0);
std::stringstream ss;
{
boost::archive::text_oarchive toa(ss);
toa << v;
}
std::vector<double> v2;
boost::archive::text_iarchive tia(ss);
tia >> v2;
assert(v == v2);
}
EDIT: I would be very cool if the library gave the option to be header only, like Boost.Asio does (https://stackoverflow.com/a/40729439/225186.)
EDIT2: The author and maintainer of Boost.Serialization rejected the idea of making it header only. https://github.com/boostorg/serialization/issues/71
I ended up including the cpp sources from a certain version of Boost Serialization.
I chose the cpp files by trial and error.
https://gitlab.com/correaa/boost-mpi3/-/tree/master/include/mpi3/serialization_hack
Basically, I include these cpp files from the same place I would include the Serialization hpp files.
#include <boost/archive/detail/common_iarchive.hpp>
#include <boost/archive/detail/common_oarchive.hpp>
#include <boost/archive/archive_exception.hpp>
#include <boost/archive/basic_streambuf_locale_saver.hpp>
#include <boost/archive/detail/auto_link_archive.hpp>
//#include <boost/archive/detail/abi_prefix.hpp> // must be the last header
#include <boost/serialization/array.hpp>
#include <boost/serialization/is_bitwise_serializable.hpp>
#include <boost/serialization/item_version_type.hpp>
#include <boost/serialization/string.hpp>
#include <boost/mpl/placeholders.hpp>
#include <any>
#include <optional>
// use this to avoid need for linking -lserialization
#ifdef _MAKE_BOOST_SERIALIZATION_HEADER_ONLY
//#include <boost/archive/detail/decl.hpp>
#if BOOST_VERSION > 106000 && BOOST_VERSION < 106600
#include "../mpi3/serialization_hack/singleton.cpp"
#endif
#if BOOST_VERSION < 105900
#define BOOST_ARCHIVE_DECL
#define BOOST_SERIALIZATION_DECL
#endif
// NOLINTBEGIN(hicpp-use-auto,modernize-use-auto) external code
#include "../mpi3/serialization_hack/archive_exception.cpp" // NOLINT(bugprone-suspicious-include) hack
#include "../mpi3/serialization_hack/basic_archive.cpp" // NOLINT(bugprone-suspicious-include) hack
#include "../mpi3/serialization_hack/basic_iarchive.cpp" // NOLINT(bugprone-suspicious-include) hack
#include "../mpi3/serialization_hack/basic_iserializer.cpp" // NOLINT(bugprone-suspicious-include) hack
#include "../mpi3/serialization_hack/basic_oarchive.cpp" // NOLINT(bugprone-suspicious-include) hack
#include "../mpi3/serialization_hack/basic_oserializer.cpp" // NOLINT(bugprone-suspicious-include) hack
#include "../mpi3/serialization_hack/extended_type_info.cpp" // NOLINT(bugprone-suspicious-include) hack
#include "../mpi3/serialization_hack/extended_type_info_typeid.cpp" // NOLINT(bugprone-suspicious-include) hack
// NOLINTEND(hicpp-use-auto,modernize-use-auto)
A problem with this approach is that I had to modify the sources to accommodate different versions of Boost.Serialization and also had to do some modification to appease compiler warnings and static analyzers.
I'm making scientific calculator in command line in c++ for my usage and also for practice. I have a problem with compiling it using cmake with mingw on windows. These are my source files:
main.ccp
#include <iostream>
#include <string>
#include "ExpressionCalculations/ExpressionParser.h"
int main()
{
std::string humanReadableExpression;
std::cout<<"Enter expression\n";
std::getline(std::cin, humanReadableExpression);
std::cout<<humanReadableExpression;
ExpressionCalculations::ExpressionParser parser;
auto&& expression = parser.GenerateRpnExpression(humanReadableExpression);
return 0;
}
ExpressionParser.h
#pragma once
#include <memory>
#include <stack>
#include <string>
#include <unordered_map>
namespace ExpressionCalculations
{
class ExpressionParser
{
public:
std::unique_ptr<std::string> GenerateRpnExpression(std::string &humanReadableExpression);
private:
// other code
};
}
ExpressionParser.cpp
#include <memory>
#include <stack>
#include <string>
#include <unordered_map>
#include <iostream>
#include "ExpressionParser.h"
namespace ExpressionCalculations
{
std::unique_ptr<std::string> ExpressionParser::GenerateRpnExpression(
std::string& humanReadableExpression)
{
std::unique_ptr<std::string> rpnExpression;
*rpnExpression="3456";
return rpnExpression;
}
These are cmake files
main CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
project (ScientificCalculator_exe)
add_subdirectory(ExpressionCalculations)
add_executable(ScientificCalculator main.cpp)
target_link_libraries(ScientificCalculator ExpressionCalculations)
module CMakeList.txt
set(calculators ExpressionParser.h ExpressionParser.cpp)
add_library(ExpressionCalculations ${calculators})
When I run it , I can see Enter expression and pass input. Then I get Segmentation fault. However when I remove declaration of ExpressionParser and auto&& expression the string is shown, a string can be inputted and shown in the command. I checked configuration question multiple directories under cmake, https://cmake.org/cmake-tutorial/ and https://www.codeproject.com/Articles/1181455/A-CMake-tutorial-for-Visual-Cplusplus-developers but it seems that I correctly made cmake files. I have no idea why it doesn't work. I use the latest mingw64 on windows with default make compilation parameters.
From the cppreference page on unique_ptr:
The class satisfies the requirements of MoveConstructible and MoveAssignable, but not the requirements of either CopyConstructible or CopyAssignable.
In your ExpressionParser::GenerateRpnExpression function you are attempting to copy the unique_ptr out of the function when you should be moving it. Try return std::move(rpnExpression)
After debugging program compiled with just g++ I found the problem. It was misunderstanding of unique_ptr' default constructor behaviour. I thought it would initialize std::string but after reading doc and checking it it does not initialize object and generates nullptr. Then I looked into Scott Myers's Modern Effective C++ how to initialize the unique_ptr. Instead of std::unique_ptr<std::string> rpnExpression; I used auto rpnExpression = std::make_unique<std::string>();. It works like charm. I checked compiling through cmake and there were not any problems.
I am trying to implement a test project using the Point Cloud Library and OpenCV with multiple files. When I try to compile, I get the "already defined error" message. Probably I'm doing something stupid that cannot realize for some reason - I tried out a couple of solutions found here, none of them seemed to be help in my case.
What I have:
A libs.h file, where I load the lib files (in Project properties, I only set up the .lib paths and load the libs "by hand", like the headers):
#pragma once
#ifndef PCLTEST_LIBS
#define PCLTEST_LIBS
#ifdef _DEBUG
#pragma comment(lib, "pcl_apps-gd.lib")
#pragma comment(lib, "pcl_common-gd.lib")
// a bunch of other debug libs
#else
// the release libs
#endif
#endif
A main file from which I basically deleted everything at this point to debug:
// load the libs
#ifndef PCLTEST_LIBS
#include "libs.h"
#endif
// pcltest includes
// if only this first one is #included, everything is OK
#include "opencvOperations.h"
// #including this one causes the error
#include "files.h"
// these ones are not working also
//#include "cloudOperations.h"
//#include "visualize.h"
// c++ headers
#include <stdio.h>
#include <string>
//#include <sstream>
//#include <iostream>
void writeInfo()
{
// some std::cout calls
}
int main( int argc, char* argv[] )
{
writeInfo();
// this function is in opencvOperations.h and works OK
pcltest::openLena();
}
Then I get several error messages in my main.obj that some (PCL related) symbols are already defined in files.obj. I use PCL related calls both in opencvOperations and files, the first one is OK, the second one does not work.
Edit:
To add more detail, my files.h header:
#pragma once
#ifndef PCLTEST_FILES
#define PCLTEST_FILES
// pcl headers
#ifndef PCL_COMMON_H_
#include <pcl/common/common_headers.h>
#endif
#ifndef PCL_IO_FILE_IO_H_
#include <pcl/io/file_io.h>
#endif
#ifndef PCL_IO_PCD_IO_H_
#include <pcl/io/pcd_io.h>
#endif
#ifndef PCL_IO_PLY_IO_H_
#include <pcl/io/ply_io.h>
#endif
// boost headers
#ifndef BOOST_FILESYSTEM_OPERATIONSX_HPP
#include <boost/filesystem/operations.hpp>
#endif
#endif
namespace pcltest
{
// function to open PCL or binary PLY files
pcl::PointCloud<pcl::PointXYZ>::Ptr openCloud(std::string filename);
// function to save the point cloud to PCD format
void saveCloud();
}
Before splitting the code into separate files, everything worked well (with the same project settings).
Edit2:
I located the source of the problem,
#include <pcl/io/ply_io.h>
causes this. For now, I got rid of everything related to PLY and everything works fine. I'll look at it later, this might be a PCL library specific issue. Still strange to me why this call causes linker error in an other file, where I don't even use PLY related functions/variables.
I had the same problem as you had. I had a surface.h and surface.cpp file, and I found out that I had to include the ply_io.h file from surface.cpp rather than surface.h and now it compiles fine. I hope that helps or makes sense! haha
If a constant is being instantiated in an include one can also use selectany, per http://msdn.microsoft.com/en-us/library/5tkz6s71%28v=vs.80%29.aspx -- in my case:
const int CSdata[] = {1, 2, 3, 4};
when included in more than one source part produces LNK2005 at link time, avoided via:
const __declspec(selectany) int CSdata[] = {1, 2, 3, 4};
Non-portable, yeah ...