LNK2019 when including asio headers, solution generated with cmake - c++

I am trying to port a big project from gcc (Linux) to msvc (windows), using cmake and boost libraries.
The project compile and runs fine for gcc but on msvc it returns the following error:
Dyna.obj : error LNK2019: unresolved external symbol "void __cdecl boost::throw_exception(class std::exception const &)" (?throw_exception#boost##YAXABVexception#std###Z) referenced in function "void __cdecl boost::asio::detail::do_throw_error(class boost::system::error_code const &,char const *)" (?do_throw_error#detail#asio#boost##YAXABVerror_code#system#3#PBD#Z)
I tried running a simple project using boost asio and it worked, which teorethically excludes boost build problems.
The CMakeLists.txt is as follows: (separated the parts of interest)
.
.
.
IF(WIN32)
# Flags para garantir a compilação em windows
SET(CMAKE_CXX_COMPILER icpl)
SET(TPN_WIN32 "/D WIN32")
SET(TPN_WIN32_LIB ws2_32.lib odbc32.lib odbccp32.lib)
SET(CMAKE_EXE_LINKER_FLAGS /NODEFAULTLIB:LIBC;LIBCMT)
ENDIF(WIN32)
# Comando para se livrar de warning sobre o caminho da library pthread
IF(COMMAND cmake_policy)
cmake_policy(SET CMP0003 NEW)
ENDIF(COMMAND cmake_policy)
# Configuracao do TPN REALTIME
# === inicio ===
IF (REALTIME_YES)
MESSAGE ("[TPN] REALTIME ENABLED")
set(Boost_ADDITIONAL_VERSIONS "1.45.0")
set(Boost_USE_MULTITHREAD ON)
set(Boost_USE_STATIC_LIBS ON)
FIND_PACKAGE( Boost "1.45.0" COMPONENTS system filesystem serialization program_options regex thread date_time REQUIRED)
FIND_PACKAGE( Threads REQUIRED )
set(HYDRO_CXX_FLAGS "-DREALTIME -DJOYSTICK")
set(HYDRO_CXX_LFLAGS ${Boost_LIBRARIES})
INCLUDE_DIRECTORIES(hydro)
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIR})
ENDIF (REALTIME_YES)
# === final ===
.
.
.
TARGET_LINK_LIBRARIES(Dyna
tpn
preadyn
${WHERE_PREA3D}
${WHERE_WAMIT_IO}
${WHERE_WAMIT_CONVERTER}
${WHERE_TECLINE}
${HYDRO_CXX_LFLAGS}
${TPN_WIN32_LIB}
)
Thanks in advance

Try to add the flag "/EHsc" into your TPN_WIN32 variable in cmake.
It seems that MSVC is not throwing exceptions and you need to enable it in your vcproj.

In my case, the /EHsc flag did not work. Turned out that BOOST_NO_EXCEPTIONS was defined so the compiler was searching for the "user defined" (as in boost/throw_exception.hpp) function.
Therefore, a quick fix is to write your favorite boost::throw_exception() function:
namespace boost
{
#ifdef BOOST_NO_EXCEPTIONS
void throw_exception( std::exception const & e ){
throw 11; // or whatever
};
#endif
}// namespace boost

Looks like, to be linking compatible, binary must have same structure exception handling enablement option. MSVC standard library implementation use structured exception handling option on. Looks like this is why boost::system also uses this on. You might see corresponding warnings telling you to add structure exception handling.
IF(MSVC)
ADD_DEFINITIONS("/EHsc")
ENDIF(MSVC)

When running on windows you need (by default) to link to boost.system and boost.regex
As it says here:
Note With MSVC or Borland C++ you may want to add
-DBOOST_DATE_TIME_NO_LIB and -DBOOST_REGEX_NO_LIB to your project
settings to disable autolinking of the Boost.Date_Time and Boost.Regex
libraries respectively. Alternatively, you may choose to build these
libraries and link to them.
If you don't want to link to other boost libraries then you can use the identical (non-boost) asio library from here.
In terms of your CMakeLists.txt file, you want a line such as
target_link_libraries (your_application ${Boost_LIBRARIES})
to actually link the library.
EDIT: also, have a look at How to link against boost.system with cmake, it could be that you have to specify the individual boost libraries specifically rather than ${Boost_LIBRARIES}

Related

CMake with MSVC and spdlog warnings

I'm using CMake to build a project that includes the spdlog library. At present, I'm doing so with Visual Studio, but I'm more used to Linux/GCC for what it's worth. Anyway, I'm having a heck of a time getting MSVC to treat spdlog as the external dependency that it is. Here's what I've got:
CMakeLists.txt from the root:
cmake_minimum_required(VERSION 3.16)
project(spdlogtest)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
find_package(spdlog REQUIRED)
add_executable(
spdlogtest
main.cpp
)
target_include_directories(
spdlogtest SYSTEM PUBLIC
${spdlog_SOURCE_DIR}/include/
)
target_compile_options(
spdlogtest PUBLIC
/Od /EHsc /nologo /MP /sdl /Wall
/external:W0
)
target_compile_definitions(
spdlogtest PUBLIC
DEBUG
)
set_target_properties(
spdlogtest PROPERTIES
CXX_STANDARD 20
CXX_STANDARD_REQUIRED ON
BINARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/debug/bin
BINARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/release/bin
)
Findspdlog.cmake:
message(STATUS "Pulling in external spdlog")
include(FetchContent)
FetchContent_Declare(
spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG eb3220622e73a4889eee355ffa37972b3cac3df5 # v1.9.2
)
FetchContent_MakeAvailable(spdlog)
And finally main.cpp is just the quickstart example from the GitHub page.
#include "spdlog/spdlog.h"
int main()
{
spdlog::info("Welcome to spdlog!");
spdlog::error("Some error message with arg: {}", 1);
spdlog::warn("Easy padding in numbers like {:08d}", 12);
spdlog::critical("Support for int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
spdlog::info("Support for floats {:03.2f}", 1.23456);
spdlog::info("Positional args are {1} {0}..", "too", "supported");
spdlog::info("{:<30}", "left aligned");
spdlog::set_level(spdlog::level::debug); // Set global log level to debug
spdlog::debug("This message should be displayed..");
// change log pattern
spdlog::set_pattern("[%H:%M:%S %z] [%n] [%^---%L---%$] [thread %t] %v");
// Compile time log levels
// define SPDLOG_ACTIVE_LEVEL to desired level
SPDLOG_TRACE("Some trace message with param {}", 42);
SPDLOG_DEBUG("Some debug message");
}
Basically, if I've got the compiler set to /W4, everything compiles without a hitch. If I set it to /Wall though, I get 100+ warnings that mostly seem to come from the libfmt included in spdlog. I've tried using an external libfmt, but achieve much the same result.
I prefer /Wall (and -pedantic) while I'm writing my own code. Holding other people to that standard is ridiculous though, so mark the fetched project as a system include and you're good, right? I certainly thought so.
The CMakeLists.txt from the root produces the massive warnings, as do the variations I've attempted. On the plus side, I think I'm better at CMake than I was when I started.
This suggestion worked for me some time in the past, but doesn't seem to affect behavior here. Adding the flag /external:I${spdlog_SOURCE_DIR}/include directly to target_compile_options() also doesn't affect anything. I also tried brute forcing it and using GLOB_RECURSE to mark all of the files in ${spdlog_SOURCE_DIR} as explicitly /W0 after fetching them, but no luck there either.
If anyone can point me in the right direction and explain why what I'm trying to do is failing, I'd be very grateful.

Problem adding std::filesystem to CMake Project

I am new to CMake projects and I want to use the file system library in my project. I am running Ubuntu 18.04 with GCC 8.2 and CMake 3.13. In order to achieve this I tried two options:
Option 1
cmake_minimum_required(VERSION 3.13)
project(TheFsProject)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "-std=c++17 -lstdc++fs")
This does not help as the compiler still cannot find the file system
library during compile time.
Option 2 (copied from:
https://www.scivision.co/cmake-cpp-17-filesystem/)
make_minimum_required(VERSION 3.13)
project(TheFsProject)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_REQUIRED_FLAGS -std=c++17)
include(CheckCXXSymbolExists)
CHECK_CXX_SYMBOL_EXISTS(std::filesystem::path::preferred_separator cxx17fs)
if(cxx17fs)
add_executable(TheFsProject main.cpp)
set_property(TARGET TheFsProject PROPERTY CXX_STANDARD 17)
endif()
This does not help either as I get a CMake error which I don't
understand.
(CHECK_CXX_SYMBOL_EXISTS):
CHECK_CXX_SYMBOL_EXISTS Macro invoked with incorrect arguments for macro named: CHECK_CXX_SYMBOL_EXISTS
I feel out of my depth on this topic which is why I came here. I don't mind putting extra work into finding out more but I don't know anymore where to look. Any help would be appreciated!
EDIT 1
Thanks for the replies so far! I made Option 3 based on your feedback:
cmake_minimum_required(VERSION 3.13)
project(TheFsProject)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(TheFsProject main.cpp)
target_link_libraries(TheFsProject stdc++fs)
Sadly it doesn't fix my problem. It still issues an error during compilation that it can't find the compilation header.
EDIT 2
Thanks for all the replies so far. All of these help. I tried Ashkan his answer last (because it seemed intimidating). This one returns
Compiler is missing file system capabilities.
so I'm guessing something is wrong on that end. This is useful in the sense that I now know it's probably not due to my CMake file. I now have to find out why the compiler does support the file system header though...
EDIT 3
Strictly speaking this question is answered because my question is about the CMake file. I am going to mark Ashkan his answer as the solution simply because it produced the next step in my troubleshooting search. If I could I would also mark lubgr his answer because I think that's a really good answer as well. Thanks everyone!
Gcc 8.2. comes with <filesystem>, so there is no need to investigate with regard to the availability. Next, option 1 is sufficient, but needs a fix:
set(CMAKE_CXX_STANDARD 17) # no need to manually adjust the CXXFLAGS
add_executable(yourExecutable yourSourceFile.cpp)
target_link_libraries(yourExecutable stdc++fs)
This should result in compiling the sources with -std=c++17 or -std=gnu++17 and adding -lstdc++fs when linking.
Edit: Note that as #Ashkan has pointed out in the comments, setting CMAKE_CXX_STANDARD_REQUIRED to true results in an immediate error at configure time if C++17 isn't supported by the compiler, instead of a compilation error (due to the missing <filesystem> header) or at link time (due to the missing shared library). This might be desirable.
Besides from #lubgr's answer. I think a more complete way is to also do try_compile to see that you can actually use the filesystem header. This in my opinion is better because some compilers are not supporting std::filesystem yet. Also in gcc 7.x you have the filesystem under experimental namespace. This way you can have a separate try_compile in the else clause and detect that.
Here is the related cmake for it
# set everything up for c++ 17 features
set(CMAKE_CXX_STANDARD 17)
# Don't add this line if you will try_compile with boost.
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# test that filesystem header actually is there and works
try_compile(HAS_FS "${CMAKE_BINARY_DIR}/temp"
"${CMAKE_SOURCE_DIR}/tests/has_filesystem.cc"
CMAKE_FLAGS -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD_REQUIRED=ON
LINK_LIBRARIES stdc++fs)
if(HAS_FS)
message(STATUS "Compiler has filesystem support")
else()
# .... You could also try searching for boost::filesystem here.
message(FATAL_ERROR "Compiler is missing filesystem capabilities")
endif(HAS_FS)
The file tests/has_filesystem.cc is very simple
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
fs::path aPath {"../"};
return 0;
}
You could in your else clause try_compile for boost::filesystem and pass a directive that can be used in your source file where you decide if you want to use c++17 filesystem or boost.
CHECK_CXX_SYMBOL_EXISTS takes three arguments, not two:
include(CheckCXXSymbolExists)
check_cxx_symbol_exists(std::filesystem::path::preferred_separator filesystem cxx17fs)
You forgot to tell CMake where to look for the symbols (the header that declares them).
I have found a case when try_compile was not enough: when using the Intel C++ compiler (icpc (ICC) 19.1.1.216 20200306) in C++17 mode running on MacOS "Mojave" 10.14.6. The test program recommended by #Ashkan compiled without errors, and it even ran. However, my code uses fs::path::filename() at one point and that resulted in a runtime linker error (dyld: lazy symbol binding failed: Symbol not found:). In other words: the header is there, the implementation apparently isn't (?). I didn't investigate this any further.
The solution is to use try_run instead of try_compile and (in my case) fall back to boost::filesystem if std::filesystem is not yet supported.
Here is the relevant CMake code section:
try_run(RUNS_WITH_STDFS COMPILES_WITH_STDFS
"${CMAKE_BINARY_DIR}/try"
"${CMAKE_SOURCE_DIR}/cmake/has_stdfs.cc"
CMAKE_FLAGS CMAKE_CXX_STANDARD=17 CMAKE_CXX_STANDARD_REQUIRED=ON
)
if (RUNS_WITH_STDFS STREQUAL "FAILED_TO_RUN")
message(STATUS "Using boost::filesystem instead of std::filesystem")
set(_boost_components ${_boost_components} filesystem system)
add_definitions(-DUSE_BOOST_FILESYSTEM)
else()
message(STATUS "std::filesystem supported")
endif()
Note that the variable RUNS_WITH_STDFS is not set to NO in case of failure but to "FAILED_TO_RUN" which is not interpreted as a FALSE Boolean (see CMake if() docs:
if() True if the constant is 1, ON, YES, TRUE, Y, or a
non-zero number. False if the constant is 0, OFF, NO, FALSE, N,
IGNORE, NOTFOUND, the empty string, or ends in the suffix -NOTFOUND.
so I had to string-compare its value.
The little test program also changed a bit compared to #Ashkan's solution:
// == PROGRAM has_stdfs.cc ==
// Check if std::filesystem is available
// Source: https://stackoverflow.com/a/54290906
// with modifications
#include <filesystem>
namespace fs = std::filesystem;
int main(int argc, char* argv[]) {
fs::path somepath{ "dir1/dir2/filename.txt" };
auto fname = somepath.filename();
return 0;
}

cmake managed/c++ error LNK2020: unresolved token

I am new to managed c++, cmake and need some help to get this going.
I am developing two managed/c++ libraries; A, and B, and want the second library
to use the first.
Whatever I try I get:
MyClassB.cpp.obj : error LNK2020: unresolved token (06000001) MyClassA::.ctor
Example managed code:
public ref class MyClassA
{
public:
MyClassA();
~MyClassA();
};
Example cmake file, library A
string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /clr /EHa /MDd /GS")
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /clr /EHa /MD /GS")
add_library(MyClassA MODULE MyClassA.cpp)
Example cmake file, library B
Similar to the one for library A, with this addition:
add_library(MyClassA MODULE IMPORTED)
If I uncomment the next line:
#target_link_libraries(MyClassB MyClassA)
I get this error:
Target "KM.Library.Types.Managedd" of type MODULE_LIBRARY may not be linked
into another target. One may link only to STATIC or SHARED libraries, ...
The code above is not the real code, I could not find a way to attach files :-(
Anyway, the task is simple enough I have two managed/c++ libraries and
want to link one to the other. The link step fails.
One other thing if I try dumpbin on library A, the EXPORTS/SYMBOLS section
is empty, is this correct ?
Regards,
Even
It seems using the /FU flag to the compiler solved the problem

Cmake test : was a library compiled/linked against libc++ or libstd++?

I am using cmake to manage my project that uses a third party library.
This library could have been compiled/linked against libc++ or libstd++ (Depending on the version).
I know how to tell cmake to compile/link my project against libc++ or libstdc++, but I don't know how to check if the library I am using was compiled/linked against libc++ or libstd++. Is there any cmake command to check that?
For shared libraries you can use the GetPrerequisites standard module to test if the library depends on libstc++ or libc++.
For example, the following code test if boost's program_options library has been compiled against libstc++ or libc++:
set (_library "/usr/local/lib/libboost_program_options.dylib")
set (_prequesites "")
set (_exclude_system FALSE)
set (_recurse FALSE)
set (_exePath "")
set (_searchDirs "")
get_prerequisites(${_library} _prequesites ${_exclude_system} ${_recurse} "${_exePath}" "${_searchDirs}")
if (_prequesites MATCHES "/libstdc\\+\\+")
message("using libstc++")
elseif (_prequesites MATCHES "/libc\\+\\+")
message("using libc++")
else()
message("using neither libstc++ nor libc++")
endif()
For static libraries you probably have to resort to running nm on the library file to determine external symbols and then search for characteristic strings like __gnu_ in the output.
Do you have an error if you link to the wrong version ? If it's the case, you can use try_compile from CMake. Example of use :
try_compile(
TRY_COMPILE_SUCCESS
${CMAKE_BINARY_DIR}/tmpTryDir
${CMAKE_MODULES_DIR}/SourceFile.cpp
CMAKE_FLAGS
"-DINCLUDE_DIRECTORIES=${TRY_INCLUDE_DIRS}"
"-DLINK_DIRECTORIES=${TRY_LIBRARY_DIRS}"
"-DLINK_LIBRARIES=${TRY_LIBRARIES}"
COMPILE_DEFINITIONS
"-DCOMPILER_OPTION"
)
And then, the CMake variable TRY_COMPILE_SUCCESS contains TRUE or FALSE depending of the compilation success.

Error while building custom Qt 4.8.3 library with CMake 2.8.11 on Windows

I am trying to migrate my Qt project from QMake to CMake but I am getting some errors when trying to build my library on Windows 7 with MSVC10. My CMakeLists.txt files is as follows:
cmake_minimum_required( VERSION 2.8.11 )
project( MyLibrary )
find_package(Qt4 REQUIRED)
set( CMAKE_AUTOMOC ON )
set( QT_USE_QTSCRIPT TRUE )
include( ${QT_USE_FILE} )
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/include ${QT_INCLUDES} )
set( MyLibrary_SOURCES
src/connection.cpp
src/mylibrary.cpp
src/node.cpp
src/socket.cpp
include/connection.h
include/mylibrary.h
include/node.h
include/socket.h
include/MyLibrary_global.h
)
add_library(MyLibrary SHARED ${MyLibrary_SOURCES})
target_link_libraries(MyLibrary ${QT_LIBRARIES} )
When I run I try to build with the generated nmake Makefile I get the following errors:
C2491:'Connection::staticMetaObjectExtraData' : definition of dllimport static data member not allowed
C2491: 'Connection::staticMetaObject' : definition of dllimport static data member not allowed
I'm new to CMake so I'm not sure if I'm missing something in the CMakeLists.txt file or if there are more tricks to using it with Qt. I should mention that the files that are getting the errors are the MOC generated ones.
Edit:
So the output of
message(${QT_INCLUDES})
is as follows (formatting is for readability):
C:/Qt/4.8.3/include/QtDesigner
C:/Qt/4.8.3/include/QtDeclarative
C:/Qt/4.8.3/include/QtScriptTools
C:/Qt/4.8.3/include/QtDBus
C:/Qt/4.8.3/include/QtDesigner
C:/Qt/4.8.3/include/QtXml
C:/Qt/4.8.3/include/QtSql
C:/Qt/4.8.3/include/QtOpenGL
C:/Qt/4.8.3/include/QtMultimedia
C:/Qt/4.8.3/include/QtNetwork
C:/Qt/4.8.3/include/phonon
C:/Qt/4.8.3/include/QtXmlPatterns
C:/Qt/4.8.3/include/QtWebKit
C:/Qt/4.8.3/include/QtHelp
C:/Qt/4.8.3/include/QtUiTools
C:/Qt/4.8.3/include/QtTest
C:/Qt/4.8.3/include/QtScript
C:/Qt/4.8.3/include/QtSvg
C:/Qt/4.8.3/include/Qt3Support
C:/Qt/4.8.3/include/QtGui
C:/Qt/4.8.3/include/QtCore
C:/Qt/4.8.3/mkspecs/default
C:/Qt/4.8.3/include
C:/Qt/4.8.3/include/QtCore
I made tried not using auto-moc but I still get the same result and errors.
Reading this: Export QObject-based class to DLL I found what's wrong:
In .pro file I had the following:
DEFINES +=APPLETTUTORIAL1_LIBRARY
Then in applet-tutorial1_global.h I have:
#if defined(APPLETTUTORIAL1_LIBRARY)
# define APPLETTUTORIAL1SHARED_EXPORT Q_DECL_EXPORT
#else
# define APPLETTUTORIAL1SHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // APPLETTUTORIAL1_GLOBAL_H
Since I didn't have the equivalent in CMakeLists.txt the compiler goes to the
# define APPLETTUTORIAL1SHARED_EXPORT Q_DECL_IMPORT
line rather than the expected one:
# define APPLETTUTORIAL1SHARED_EXPORT Q_DECL_EXPORT
So my solution was to leave only this line and my shared library built well!
# define APPLETTUTORIAL1SHARED_EXPORT Q_DECL_EXPORT
I tried the folllowing in CMakeLists.txt after reading this:http://www.cmake.org/Wiki/CMake:ConvertFromQmake but I did it wrong I think, thus the solution above.
SET(DEFINES "APPLETTUTORIAL1_LIBRARY")
Most of
http://www.cmake.org/cmake/help/v3.0/manual/cmake-qt.7.html
applies to CMake 2.8.11 too. Use imported targets, not the Use file.
Ok, I have 3 Ideas, not sure if they lead to a solution, but it could work.
First of all, what is in ${QT_INCLUDES}? Add some message(${QT_INCLUDES}) please and share the output.
The second Idea would be to mock manually, as the error orrurs in the mock. For this try to remove the set( CMAKE_AUTOMOC ON ) and add:
set(QT_USE_QTUITOOLS true)
QT4_WRAP_UI(UI UiFiles.ui)
QT4_WRAP_CPP(MOC3 QObjectFiles.h)
add_library(..........
${UI}
${MOC3})
My third idea is to remove the SHARED, maybe this causes the error, but I am not sure on that one.
Please share what you get and I'll try to help :)
I don't have enough reputation to add a comment so I have to write an answer...
Same problem but Qt4.8.5 here.
Keep using CMAKE_AUTOMOC because QT4_WRAP_CPP is the old way of doing... I found this : http://plagatux.es/2012/12/qt-automoc-with-cmake/
When I used old way, I got the same linkage error you had. With AUTOMOC I get other linkage /compilation errors but think I can go further:
applettutorial1.cpp.obj : error LNK2019: unresolved external symbol "__declspec(dllimport) const tutorial1::AppletTutorial1::`vftable'{for `XAppletPlugin'}" (__imp_??_7AppletTutorial1#tutorial1##6BXAppletPlugin###) referenced in function "public: __cdecl tutorial1::AppletTutorial1::AppletTutorial1(void)" (??0AppletTutorial1#tutorial1##QEAA#XZ)
You might add this to your includes:
${QT_QTCORE_INCLUDE_DIR}
${QT_INCLUDE_DIR}
Hoping you solved and could give us feedback so this helps other people.
EDIT : in my case I solved the following errors to get a successful build:
correctly check CMAKE_BUILD_TYPE against "Debug" string, not "DEBUG" as I read here and there. RTFM.
build my lib as STATIC, not SHARED.